| /* |
| * Copyright 2015 Google Inc. |
| * |
| * Licensed 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. |
| */ |
| |
| // Author: jmarantz@google.com (Joshua Marantz) |
| |
| #ifndef PAGESPEED_KERNEL_BASE_NAMED_LOCK_TESTER_H_ |
| #define PAGESPEED_KERNEL_BASE_NAMED_LOCK_TESTER_H_ |
| |
| #include "base/logging.h" |
| #include "pagespeed/kernel/base/abstract_mutex.h" |
| #include "pagespeed/kernel/base/basictypes.h" |
| #include "pagespeed/kernel/base/function.h" |
| #include "pagespeed/kernel/base/named_lock_manager.h" |
| #include "pagespeed/kernel/base/scoped_ptr.h" |
| #include "pagespeed/kernel/base/thread_system.h" |
| |
| namespace net_instaweb { |
| |
| // The NamedLock class does not have any blocking operations in it, as |
| // they don't fit well with PageSpeed's asynchronous archicture and with |
| // plans to make an asynchronous lock manager. However, in the context |
| // of unit tests, it is convenient to assume a blocking or schedule-based |
| // lock manager, and check that the call completes. |
| class NamedLockTester { |
| public: |
| explicit NamedLockTester(ThreadSystem* thread_system) |
| : acquired_(false), |
| failed_(false), |
| mutex_(thread_system->NewMutex()) { |
| } |
| |
| bool TryLock(NamedLock* lock) { |
| Clear(); |
| lock->LockTimedWait(0, MakeFunction( |
| this, |
| &NamedLockTester::LockAcquired, |
| &NamedLockTester::LockFailed)); |
| Quiesce(); |
| CHECK(WasCalled()) << "LockTimedWait returned lock operation completed"; |
| return Acquired(); |
| } |
| bool LockTimedWaitStealOld(int64 wait_ms, int64 steal_ms, NamedLock* lock) { |
| Clear(); |
| lock->LockTimedWaitStealOld(wait_ms, steal_ms, MakeFunction( |
| this, |
| &NamedLockTester::LockAcquired, |
| &NamedLockTester::LockFailed)); |
| Quiesce(); |
| CHECK(WasCalled()) |
| << "LockTimedWaitStealOld returned lock operation completed"; |
| return Acquired(); |
| } |
| bool LockTimedWait(int64 wait_ms, NamedLock* lock) { |
| Clear(); |
| lock->LockTimedWait(wait_ms, MakeFunction( |
| this, |
| &NamedLockTester::LockAcquired, |
| &NamedLockTester::LockFailed)); |
| Quiesce(); |
| CHECK(WasCalled()) << "LockTimedWait returned lock operation completed"; |
| return Acquired(); |
| } |
| |
| void Quiesce() { |
| if (quiesce_.get() != NULL) { |
| quiesce_->CallRun(); |
| quiesce_->Reset(); |
| } |
| } |
| |
| // Sets a function to be called after calling an asynchronous locking |
| // method, prior to testing acuisition status. Onwership of this function |
| // transfers to this class. |
| void set_quiesce(Function* quiesce) { |
| quiesce->set_delete_after_callback(false); |
| quiesce_.reset(quiesce); |
| } |
| |
| private: |
| void Clear() { |
| ScopedMutex lock(mutex_.get()); |
| acquired_ = false; |
| failed_ = false; |
| } |
| |
| void LockAcquired() { |
| ScopedMutex lock(mutex_.get()); |
| acquired_ = true; |
| } |
| void LockFailed() { |
| ScopedMutex lock(mutex_.get()); |
| failed_ = true; |
| } |
| bool WasCalled() { |
| ScopedMutex lock(mutex_.get()); |
| return acquired_ || failed_; |
| } |
| bool Acquired() { |
| ScopedMutex lock(mutex_.get()); |
| return acquired_; |
| } |
| |
| bool acquired_; |
| bool failed_; |
| scoped_ptr<AbstractMutex> mutex_; |
| scoped_ptr<Function> quiesce_; |
| |
| DISALLOW_COPY_AND_ASSIGN(NamedLockTester); |
| }; |
| |
| } // namespace net_instaweb |
| |
| #endif // PAGESPEED_KERNEL_BASE_NAMED_LOCK_TESTER_H_ |