| // Copyright (c) 2006- Facebook | 
 | // Distributed under the Thrift Software License | 
 | // | 
 | // See accompanying file LICENSE or visit the Thrift site at: | 
 | // http://developers.facebook.com/thrift/ | 
 |  | 
 | #include "Monitor.h" | 
 | #include "Exception.h" | 
 | #include "Util.h" | 
 |  | 
 | #include <assert.h> | 
 | #include <errno.h> | 
 |  | 
 | #include <iostream> | 
 |  | 
 | #include <pthread.h> | 
 |  | 
 | namespace facebook { namespace thrift { namespace concurrency { | 
 |  | 
 | /** | 
 |  * Monitor implementation using the POSIX pthread library | 
 |  * | 
 |  * @author marc | 
 |  * @version $Id:$ | 
 |  */ | 
 | class Monitor::Impl { | 
 |  | 
 |  public: | 
 |  | 
 |   Impl() : | 
 |     mutexInitialized_(false), | 
 |     condInitialized_(false) { | 
 |  | 
 |     if (pthread_mutex_init(&pthread_mutex_, NULL) == 0) { | 
 |       mutexInitialized_ = true; | 
 |  | 
 |       if (pthread_cond_init(&pthread_cond_, NULL) == 0) { | 
 |         condInitialized_ = true; | 
 |       } | 
 |     } | 
 |  | 
 |     if (!mutexInitialized_ || !condInitialized_) { | 
 |       cleanup(); | 
 |       throw SystemResourceException(); | 
 |     } | 
 |   } | 
 |  | 
 |   ~Impl() { cleanup(); } | 
 |  | 
 |   void lock() const { pthread_mutex_lock(&pthread_mutex_); } | 
 |  | 
 |   void unlock() const { pthread_mutex_unlock(&pthread_mutex_); } | 
 |  | 
 |   void wait(int64_t timeout) const { | 
 |  | 
 |     // XXX Need to assert that caller owns mutex | 
 |     assert(timeout >= 0LL); | 
 |     if (timeout == 0LL) { | 
 |       int iret = pthread_cond_wait(&pthread_cond_, &pthread_mutex_); | 
 |       assert(iret == 0); | 
 |     } else { | 
 |       struct timespec abstime; | 
 |       int64_t now = Util::currentTime(); | 
 |       Util::toTimespec(abstime, now + timeout); | 
 |       int result = pthread_cond_timedwait(&pthread_cond_, | 
 |                                           &pthread_mutex_, | 
 |                                           &abstime); | 
 |       if (result == ETIMEDOUT) { | 
 |         // pthread_cond_timedwait has been observed to return early on | 
 |         // various platforms, so comment out this assert. | 
 |         //assert(Util::currentTime() >= (now + timeout)); | 
 |         throw TimedOutException(); | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   void notify() { | 
 |     // XXX Need to assert that caller owns mutex | 
 |     int iret = pthread_cond_signal(&pthread_cond_); | 
 |     assert(iret == 0); | 
 |   } | 
 |  | 
 |   void notifyAll() { | 
 |     // XXX Need to assert that caller owns mutex | 
 |     int iret = pthread_cond_broadcast(&pthread_cond_); | 
 |     assert(iret == 0); | 
 |   } | 
 |  | 
 |  private: | 
 |  | 
 |   void cleanup() { | 
 |     if (mutexInitialized_) { | 
 |       mutexInitialized_ = false; | 
 |       int iret = pthread_mutex_destroy(&pthread_mutex_); | 
 |       assert(iret == 0); | 
 |     } | 
 |  | 
 |     if (condInitialized_) { | 
 |       condInitialized_ = false; | 
 |       int iret = pthread_cond_destroy(&pthread_cond_); | 
 |       assert(iret == 0); | 
 |     } | 
 |   } | 
 |  | 
 |   mutable pthread_mutex_t pthread_mutex_; | 
 |   mutable bool mutexInitialized_; | 
 |   mutable pthread_cond_t pthread_cond_; | 
 |   mutable bool condInitialized_; | 
 | }; | 
 |  | 
 | Monitor::Monitor() : impl_(new Monitor::Impl()) {} | 
 |  | 
 | Monitor::~Monitor() { delete impl_; } | 
 |  | 
 | void Monitor::lock() const { impl_->lock(); } | 
 |  | 
 | void Monitor::unlock() const { impl_->unlock(); } | 
 |  | 
 | void Monitor::wait(int64_t timeout) const { impl_->wait(timeout); } | 
 |  | 
 | void Monitor::notify() const { impl_->notify(); } | 
 |  | 
 | void Monitor::notifyAll() const { impl_->notifyAll(); } | 
 |  | 
 | }}} // facebook::thrift::concurrency |