// ********************************************************************** // // Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. // // This copy of Ice is licensed to you under the terms described in the // ICE_LICENSE file included in this distribution. // // ********************************************************************** #ifndef ICE_UTIL_MONITOR_H #define ICE_UTIL_MONITOR_H #include #include #include namespace IceUtil { // // This monitor implements the Mesa monitor semantics. That is any // calls to notify() or notifyAll() are delayed until the monitor is // unlocked. // template class Monitor { public: typedef LockT > Lock; typedef TryLockT > TryLock; Monitor(); ~Monitor(); // // Note that lock/tryLock & unlock in general should not be used // directly. Instead use Lock & TryLock. // void lock() const; void unlock() const; bool tryLock() const; void wait() const; bool timedWait(const Time&) const; void notify(); void notifyAll(); private: // noncopyable Monitor(const Monitor&); void operator=(const Monitor&); void notifyImpl(int) const; mutable Cond _cond; T _mutex; mutable int _nnotify; }; } // End namespace IceUtil // // Since this monitor implements the Mesa monitor semantics calls to // notify() or notifyAll() are delayed until the monitor is // unlocked. This can happen either due to a call to unlock(), or a // call to wait(). The _nnotify flag keeps track of the number of // pending notification calls. -1 indicates a broadcast, a positive // number indicates calls to notify(). The _nnotify flag is reset // upon initial acquisition of the monitor lock (either through a call // to lock(), or a return from wait(). // template inline IceUtil::Monitor::Monitor() : _nnotify(0) { } template inline IceUtil::Monitor::~Monitor() { } template inline void IceUtil::Monitor::lock() const { _mutex.lock(); if(_mutex.willUnlock()) { // // On the first mutex acquisition reset the number pending // notifications. // _nnotify = 0; } } template inline void IceUtil::Monitor::unlock() const { if(_mutex.willUnlock()) { // // Perform any pending notifications. // notifyImpl(_nnotify); } _mutex.unlock(); /* int nnotify = _nnotify; if(_mutex.unlock()) { // // Perform any pending notifications. // notifyImpl(nnotify); } */ } template inline bool IceUtil::Monitor::tryLock() const { bool result = _mutex.tryLock(); if(result && _mutex.willUnlock()) { // // On the first mutex acquisition reset the number pending // notifications. // _nnotify = 0; } return result; } template inline void IceUtil::Monitor::wait() const { // // Perform any pending notifies // notifyImpl(_nnotify); // // Wait for a notification // try { _cond.waitImpl(_mutex); // // Reset the nnotify count once wait() returns. // } catch(...) { _nnotify = 0; throw; } _nnotify = 0; } template inline bool IceUtil::Monitor::timedWait(const Time& timeout) const { // // Perform any pending notifies. // notifyImpl(_nnotify); bool rc; // // Wait for a notification. // try { rc = _cond.timedWaitImpl(_mutex, timeout); // // Reset the nnotify count once wait() returns. // } catch(...) { _nnotify = 0; throw; } _nnotify = 0; return rc; } template inline void IceUtil::Monitor::notify() { // // Increment the _nnotify flag, unless a broadcast has already // been requested. // if(_nnotify != -1) { ++_nnotify; } } template inline void IceUtil::Monitor::notifyAll() { // // -1 (indicates broadcast) // _nnotify = -1; } template inline void IceUtil::Monitor::notifyImpl(int nnotify) const { // // Zero indicates no notifies. // if(nnotify != 0) { // // -1 means notifyAll. // if(nnotify == -1) { _cond.broadcast(); return; } else { // // Otherwise notify n times. // while(nnotify > 0) { _cond.signal(); --nnotify; } } } } #endif