| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| |
| #include "pagespeed/kernel/thread/mock_scheduler.h" |
| |
| #include "base/logging.h" |
| #include "pagespeed/kernel/base/abstract_mutex.h" |
| #include "pagespeed/kernel/base/basictypes.h" |
| #include "pagespeed/kernel/base/mock_timer.h" |
| #include "pagespeed/kernel/thread/scheduler.h" |
| #include "pagespeed/kernel/base/thread_system.h" |
| #include "pagespeed/kernel/base/timer.h" |
| |
| namespace net_instaweb { |
| |
| MockScheduler::MockScheduler( |
| ThreadSystem* thread_system, MockTimer* timer) |
| : Scheduler(thread_system, timer), |
| timer_(timer) { |
| } |
| |
| MockScheduler::~MockScheduler() { |
| } |
| |
| void MockScheduler::AwaitWakeupUntilUs(int64 wakeup_time_us) { |
| // AwaitWakeupUntilUs is used to effectively move simulated time forward |
| // during unit tests. Various callbacks in the test infrastructure |
| // can be called as a result of Alarms firing, enabling the simulation of |
| // cache/http fetches with non-zero delay, compute-bound rewrites, or |
| // threaded rewrites. |
| // |
| // To make things simple and deterministic, we simply advance the |
| // time when the work threads quiesce. |
| if (QueuedWorkerPool::AreBusy(workers_) || running_waiting_alarms()) { |
| Scheduler::AwaitWakeupUntilUs(timer_->NowUs() + 10 * Timer::kMsUs); |
| } else { |
| // Can fire off alarms, so we have to be careful to have the lock |
| // relinquished. |
| |
| mutex()->Unlock(); |
| if (wakeup_time_us >= timer_->NowUs()) { |
| timer_->SetTimeUs(wakeup_time_us); |
| } |
| mutex()->Lock(); |
| } |
| } |
| |
| void MockScheduler::AwaitQuiescence() { |
| ScopedMutex lock(mutex()); |
| while (QueuedWorkerPool::AreBusy(workers_) || running_waiting_alarms()) { |
| Scheduler::AwaitWakeupUntilUs(timer_->NowUs() + 10 * Timer::kMsUs); |
| } |
| } |
| |
| void MockScheduler::RegisterWorker(QueuedWorkerPool::Sequence* w) { |
| ScopedMutex lock(mutex()); |
| workers_.insert(w); |
| } |
| |
| void MockScheduler::UnregisterWorker(QueuedWorkerPool::Sequence* w) { |
| ScopedMutex lock(mutex()); |
| workers_.erase(w); |
| } |
| |
| void MockScheduler::AdvanceTimeUs(int64 timeout_us) { |
| ScopedMutex lock(mutex()); |
| SetTimeUsMutexHeld(timer_->NowUs() + timeout_us); |
| } |
| |
| void MockScheduler::SetTimeUsMutexHeld(int64 time_us) { |
| // BlockingTimedWaitUs does not guarantee that it will wait all |
| // the way until a timeout occurs, so we loop. |
| while (timer_->NowUs() < time_us) { |
| BlockingTimedWaitUs(time_us - timer_->NowUs()); |
| } |
| } |
| |
| void MockScheduler::SetTimeUs(int64 time_us) { |
| CHECK_LE(timer_->NowUs(), time_us) |
| << "Time cannot go backward in the scheduler: " |
| << "delta=" << timer_->NowUs() - time_us; |
| { |
| ScopedMutex lock(mutex()); |
| SetTimeUsMutexHeld(time_us); |
| } |
| } |
| |
| } // namespace net_instaweb |