| // 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 "Mutex.h" | 
 |  | 
 | #include <assert.h> | 
 | #include <pthread.h> | 
 |  | 
 | using boost::shared_ptr; | 
 |  | 
 | namespace facebook { namespace thrift { namespace concurrency { | 
 |  | 
 | /** | 
 |  * Implementation of Mutex class using POSIX mutex | 
 |  * | 
 |  * @author marc | 
 |  * @version $Id:$ | 
 |  */ | 
 | class Mutex::impl { | 
 |  public: | 
 |   impl(Initializer init) : initialized_(false) { | 
 |     init(&pthread_mutex_); | 
 |     initialized_ = true; | 
 |   } | 
 |  | 
 |   ~impl() { | 
 |     if (initialized_) { | 
 |       initialized_ = false; | 
 |       int ret = pthread_mutex_destroy(&pthread_mutex_); | 
 |       assert(ret == 0); | 
 |     } | 
 |   } | 
 |  | 
 |   void lock() const { pthread_mutex_lock(&pthread_mutex_); } | 
 |  | 
 |   bool trylock() const { return (0 == pthread_mutex_trylock(&pthread_mutex_)); } | 
 |  | 
 |   void unlock() const { pthread_mutex_unlock(&pthread_mutex_); } | 
 |  | 
 |  private: | 
 |   mutable pthread_mutex_t pthread_mutex_; | 
 |   mutable bool initialized_; | 
 | }; | 
 |  | 
 | Mutex::Mutex(Initializer init) : impl_(new Mutex::impl(init)) {} | 
 |  | 
 | void Mutex::lock() const { impl_->lock(); } | 
 |  | 
 | bool Mutex::trylock() const { return impl_->trylock(); } | 
 |  | 
 | void Mutex::unlock() const { impl_->unlock(); } | 
 |  | 
 | void Mutex::DEFAULT_INITIALIZER(void* arg) { | 
 |   pthread_mutex_t* pthread_mutex = (pthread_mutex_t*)arg; | 
 |   int ret = pthread_mutex_init(pthread_mutex, NULL); | 
 |   assert(ret == 0); | 
 | } | 
 |  | 
 | static void init_with_kind(pthread_mutex_t* mutex, int kind) { | 
 |   pthread_mutexattr_t mutexattr; | 
 |   int ret = pthread_mutexattr_init(&mutexattr); | 
 |   assert(ret == 0); | 
 |  | 
 |   // Apparently, this can fail.  Should we really be aborting? | 
 |   ret = pthread_mutexattr_settype(&mutexattr, kind); | 
 |   assert(ret == 0); | 
 |  | 
 |   ret = pthread_mutex_init(mutex, &mutexattr); | 
 |   assert(ret == 0); | 
 |  | 
 |   ret = pthread_mutexattr_destroy(&mutexattr); | 
 |   assert(ret == 0); | 
 | } | 
 |  | 
 | #ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP | 
 | void Mutex::ADAPTIVE_INITIALIZER(void* arg) { | 
 |   // From mysql source: mysys/my_thr_init.c | 
 |   // Set mutex type to "fast" a.k.a "adaptive" | 
 |   // | 
 |   // In this case the thread may steal the mutex from some other thread | 
 |   // that is waiting for the same mutex. This will save us some | 
 |   // context switches but may cause a thread to 'starve forever' while | 
 |   // waiting for the mutex (not likely if the code within the mutex is | 
 |   // short). | 
 |   init_with_kind((pthread_mutex_t*)arg, PTHREAD_MUTEX_ADAPTIVE_NP); | 
 | } | 
 | #endif | 
 |  | 
 | #ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP | 
 | void Mutex::RECURSIVE_INITIALIZER(void* arg) { | 
 |   init_with_kind((pthread_mutex_t*)arg, PTHREAD_MUTEX_RECURSIVE_NP); | 
 | } | 
 | #endif | 
 |  | 
 |  | 
 | /** | 
 |  * Implementation of ReadWriteMutex class using POSIX rw lock | 
 |  * | 
 |  * @author boz | 
 |  * @version $Id:$ | 
 |  */ | 
 | class ReadWriteMutex::impl { | 
 | public: | 
 |   impl() : initialized_(false) { | 
 |     int ret = pthread_rwlock_init(&rw_lock_, NULL); | 
 |     assert(ret == 0); | 
 |     initialized_ = true; | 
 |   } | 
 |  | 
 |   ~impl() { | 
 |     if(initialized_) { | 
 |       initialized_ = false; | 
 |       int ret = pthread_rwlock_destroy(&rw_lock_); | 
 |       assert(ret == 0); | 
 |     } | 
 |   } | 
 |  | 
 |   void acquireRead() const { pthread_rwlock_rdlock(&rw_lock_); } | 
 |  | 
 |   void acquireWrite() const { pthread_rwlock_wrlock(&rw_lock_); } | 
 |  | 
 |   bool attemptRead() const { return pthread_rwlock_tryrdlock(&rw_lock_); } | 
 |  | 
 |   bool attemptWrite() const { return pthread_rwlock_trywrlock(&rw_lock_); } | 
 |  | 
 |   void release() const { pthread_rwlock_unlock(&rw_lock_); } | 
 |  | 
 | private: | 
 |   mutable pthread_rwlock_t rw_lock_; | 
 |   mutable bool initialized_; | 
 | }; | 
 |  | 
 | ReadWriteMutex::ReadWriteMutex() : impl_(new ReadWriteMutex::impl()) {} | 
 |  | 
 | void ReadWriteMutex::acquireRead() const { impl_->acquireRead(); } | 
 |  | 
 | void ReadWriteMutex::acquireWrite() const { impl_->acquireWrite(); } | 
 |  | 
 | bool ReadWriteMutex::attemptRead() const { return impl_->attemptRead(); } | 
 |  | 
 | bool ReadWriteMutex::attemptWrite() const { return impl_->attemptWrite(); } | 
 |  | 
 | void ReadWriteMutex::release() const { impl_->release(); } | 
 |  | 
 | }}} // facebook::thrift::concurrency | 
 |  |