/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/** * Monitor provides a *non*-reentrant monitor: *not* a Java-style * monitor. If your code needs support for reentrancy, use * ReentrantMonitor instead. (Rarely should reentrancy be needed.) * * Instead of directly calling Monitor methods, it's safer and simpler * to instead use the RAII wrappers MonitorAutoLock and * MonitorAutoUnlock.
*/ class MOZ_CAPABILITY("monitor") Monitor { public: explicit Monitor(constchar* aName)
: mMutex(aName), mCondVar(mMutex, "[Monitor.mCondVar]") {}
/** * MonitorSingleWriter * * Monitor where a single writer exists, so that reads from the same thread * will not generate data races or consistency issues. * * When possible, use MonitorAutoLock/MonitorAutoUnlock to lock/unlock this * monitor within a scope, instead of calling Lock/Unlock directly. * * This requires an object implementing Mutex's SingleWriterLockOwner, so * we can do correct-thread checks.
*/
class MonitorSingleWriter : public Monitor { public: // aOwner should be the object that contains the mutex, typically. We // will use that object (which must have a lifetime the same or greater // than this object) to verify that we're running on the correct thread, // typically only in DEBUG builds explicit MonitorSingleWriter(constchar* aName, SingleWriterLockOwner* aOwner)
: Monitor(aName) #ifdef DEBUG
,
mOwner(aOwner) #endif
{
MOZ_COUNT_CTOR(MonitorSingleWriter);
MOZ_ASSERT(mOwner);
}
private: #ifdef DEBUG
SingleWriterLockOwner* mOwner MOZ_UNSAFE_REF( "This is normally the object that contains the MonitorSingleWriter, so " "we don't want to hold a reference to ourselves"); #endif
/** * Lock the monitor for the lexical scope instances of this class are * bound to (except for MonitorAutoUnlock in nested scopes). * * The monitor must be unlocked when instances of this class are * created.
*/ namespace detail { template <typename T> class MOZ_SCOPED_CAPABILITY MOZ_STACK_CLASS BaseMonitorAutoLock { public: explicit BaseMonitorAutoLock(T& aMonitor) MOZ_CAPABILITY_ACQUIRE(aMonitor)
: mMonitor(&aMonitor) {
mMonitor->Lock();
}
~BaseMonitorAutoLock() MOZ_CAPABILITY_RELEASE() { mMonitor->Unlock(); } // It's very hard to mess up MonitorAutoLock lock(mMonitor); ... lock.Wait(). // The only way you can fail to hold the lock when you call lock.Wait() is to // use MonitorAutoUnlock. For now we'll ignore that case. void Wait() {
mMonitor->AssertCurrentThreadOwns();
mMonitor->Wait();
}
CVStatus Wait(TimeDuration aDuration) {
mMonitor->AssertCurrentThreadOwns(); return mMonitor->Wait(aDuration);
}
// Assert that aLock is the monitor passed to the constructor and that the // current thread owns the monitor. In coding patterns such as: // // void LockedMethod(const BaseAutoLock<T>& aProofOfLock) // { // aProofOfLock.AssertOwns(mMonitor); // ... // } // // Without this assertion, it could be that mMonitor is not actually // locked. It's possible to have code like: // // BaseAutoLock lock(someMonitor); // ... // BaseAutoUnlock unlock(someMonitor); // ... // LockedMethod(lock); // // and in such a case, simply asserting that the monitor pointers match is not // sufficient; monitor ownership must be asserted as well. // // Note that if you are going to use the coding pattern presented above, you // should use this method in preference to using AssertCurrentThreadOwns on // the mutex you expected to be held, since this method provides stronger // guarantees. void AssertOwns(const T& aMonitor) const MOZ_ASSERT_CAPABILITY(aMonitor) {
MOZ_ASSERT(&aMonitor == mMonitor);
mMonitor->AssertCurrentThreadOwns();
}
// clang-format off // Use if we've done AssertOnWritingThread(), and then later need to take the // lock to write to a protected member. Instead of // MutexSingleWriterAutoLock lock(mutex) // use // MutexSingleWriterAutoLockOnThread(lock, mutex) // clang-format on #define MonitorSingleWriterAutoLockOnThread(lock, monitor) \
MOZ_PUSH_IGNORE_THREAD_SAFETY \
MonitorSingleWriterAutoLock lock(monitor); \
MOZ_POP_THREAD_SAFETY
/** * Unlock the monitor for the lexical scope instances of this class * are bound to (except for MonitorAutoLock in nested scopes). * * The monitor must be locked by the current thread when instances of * this class are created.
*/ namespace detail { template <typename T> class MOZ_STACK_CLASS MOZ_SCOPED_CAPABILITY BaseMonitorAutoUnlock { public: explicit BaseMonitorAutoUnlock(T& aMonitor)
MOZ_SCOPED_UNLOCK_RELEASE(aMonitor)
: mMonitor(&aMonitor) {
mMonitor->Unlock();
}
/** * Lock the monitor for the lexical scope instances of this class are * bound to (except for MonitorAutoUnlock in nested scopes). * * The monitor must be unlocked when instances of this class are * created.
*/ class MOZ_SCOPED_CAPABILITY MOZ_STACK_CLASS ReleasableMonitorAutoLock { public: explicit ReleasableMonitorAutoLock(Monitor& aMonitor)
MOZ_CAPABILITY_ACQUIRE(aMonitor)
: mMonitor(&aMonitor) {
mMonitor->Lock();
mLocked = true;
}
~ReleasableMonitorAutoLock() MOZ_CAPABILITY_RELEASE() { if (mLocked) {
mMonitor->Unlock();
}
}
// See BaseMonitorAutoLock::Wait void Wait() {
mMonitor->AssertCurrentThreadOwns(); // someone could have called Unlock()
mMonitor->Wait();
}
CVStatus Wait(TimeDuration aDuration) {
mMonitor->AssertCurrentThreadOwns(); return mMonitor->Wait(aDuration);
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.30Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.