blob: f9751d4746de70c77973b4439818e0ece38af1f2 [file] [log] [blame]
Mark Slee9f0c6512007-02-28 23:58:26 +00001// Copyright (c) 2006- Facebook
2// Distributed under the Thrift Software License
3//
4// See accompanying file LICENSE or visit the Thrift site at:
5// http://developers.facebook.com/thrift/
6
Marc Slemko3a3b53b2007-05-22 23:59:54 +00007#include "Monitor.h"
8#include "Exception.h"
Marc Slemko0e53ccd2006-07-17 23:51:05 +00009#include "Util.h"
Marc Slemko66949872006-07-15 01:52:39 +000010
11#include <assert.h>
12#include <errno.h>
Marc Slemko8a40a762006-07-19 17:46:50 +000013
14#include <iostream>
15
Marc Slemko66949872006-07-15 01:52:39 +000016#include <pthread.h>
17
T Jake Lucianib5e62212009-01-31 22:36:20 +000018namespace apache { namespace thrift { namespace concurrency {
Marc Slemko66949872006-07-15 01:52:39 +000019
Mark Sleef5f2be42006-09-05 21:05:31 +000020/**
21 * Monitor implementation using the POSIX pthread library
Marc Slemko3a3b53b2007-05-22 23:59:54 +000022 *
Mark Sleef5f2be42006-09-05 21:05:31 +000023 * @version $Id:$
24 */
Marc Slemko66949872006-07-15 01:52:39 +000025class Monitor::Impl {
26
27 public:
28
Mark Sleef5f2be42006-09-05 21:05:31 +000029 Impl() :
Mark Slee2f6404d2006-10-10 01:37:40 +000030 mutexInitialized_(false),
31 condInitialized_(false) {
Marc Slemko3a3b53b2007-05-22 23:59:54 +000032
Mark Slee2782d6d2007-05-23 04:55:30 +000033 if (pthread_mutex_init(&pthread_mutex_, NULL) == 0) {
Mark Slee2f6404d2006-10-10 01:37:40 +000034 mutexInitialized_ = true;
Marc Slemko3a3b53b2007-05-22 23:59:54 +000035
Mark Slee2782d6d2007-05-23 04:55:30 +000036 if (pthread_cond_init(&pthread_cond_, NULL) == 0) {
Marc Slemko3a3b53b2007-05-22 23:59:54 +000037 condInitialized_ = true;
38 }
39 }
40
Mark Slee2782d6d2007-05-23 04:55:30 +000041 if (!mutexInitialized_ || !condInitialized_) {
Marc Slemko6f038a72006-08-03 18:58:09 +000042 cleanup();
Marc Slemko3a3b53b2007-05-22 23:59:54 +000043 throw SystemResourceException();
Marc Slemko66949872006-07-15 01:52:39 +000044 }
45 }
46
Mark Sleef5f2be42006-09-05 21:05:31 +000047 ~Impl() { cleanup(); }
Marc Slemko6f038a72006-08-03 18:58:09 +000048
Mark Slee2f6404d2006-10-10 01:37:40 +000049 void lock() const { pthread_mutex_lock(&pthread_mutex_); }
Marc Slemko66949872006-07-15 01:52:39 +000050
Mark Slee2f6404d2006-10-10 01:37:40 +000051 void unlock() const { pthread_mutex_unlock(&pthread_mutex_); }
Marc Slemko66949872006-07-15 01:52:39 +000052
Mark Slee9b82d272007-05-23 05:16:07 +000053 void wait(int64_t timeout) const {
Marc Slemko66949872006-07-15 01:52:39 +000054
55 // XXX Need to assert that caller owns mutex
Aditya Agarwal3f234da2007-04-01 01:19:57 +000056 assert(timeout >= 0LL);
Mark Sleef5f2be42006-09-05 21:05:31 +000057 if (timeout == 0LL) {
Aditya Agarwal9dc57402007-03-31 17:45:12 +000058 int iret = pthread_cond_wait(&pthread_cond_, &pthread_mutex_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +000059 assert(iret == 0);
Marc Slemko66949872006-07-15 01:52:39 +000060 } else {
Marc Slemko66949872006-07-15 01:52:39 +000061 struct timespec abstime;
Mark Slee9b82d272007-05-23 05:16:07 +000062 int64_t now = Util::currentTime();
Marc Slemko9f27a4e2006-07-19 20:02:22 +000063 Util::toTimespec(abstime, now + timeout);
Mark Slee2f6404d2006-10-10 01:37:40 +000064 int result = pthread_cond_timedwait(&pthread_cond_,
65 &pthread_mutex_,
66 &abstime);
Mark Sleef5f2be42006-09-05 21:05:31 +000067 if (result == ETIMEDOUT) {
David Reiss428d5692008-12-02 02:22:01 +000068 // pthread_cond_timedwait has been observed to return early on
69 // various platforms, so comment out this assert.
70 //assert(Util::currentTime() >= (now + timeout));
Marc Slemko3a3b53b2007-05-22 23:59:54 +000071 throw TimedOutException();
Marc Slemko66949872006-07-15 01:52:39 +000072 }
73 }
74 }
75
76 void notify() {
Marc Slemko66949872006-07-15 01:52:39 +000077 // XXX Need to assert that caller owns mutex
Aditya Agarwal9dc57402007-03-31 17:45:12 +000078 int iret = pthread_cond_signal(&pthread_cond_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +000079 assert(iret == 0);
Marc Slemko66949872006-07-15 01:52:39 +000080 }
81
82 void notifyAll() {
Marc Slemko66949872006-07-15 01:52:39 +000083 // XXX Need to assert that caller owns mutex
Aditya Agarwal9dc57402007-03-31 17:45:12 +000084 int iret = pthread_cond_broadcast(&pthread_cond_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +000085 assert(iret == 0);
Marc Slemko66949872006-07-15 01:52:39 +000086 }
87
Mark Sleef5f2be42006-09-05 21:05:31 +000088 private:
Marc Slemko66949872006-07-15 01:52:39 +000089
Marc Slemko6f038a72006-08-03 18:58:09 +000090 void cleanup() {
Mark Slee2f6404d2006-10-10 01:37:40 +000091 if (mutexInitialized_) {
92 mutexInitialized_ = false;
Aditya Agarwal9dc57402007-03-31 17:45:12 +000093 int iret = pthread_mutex_destroy(&pthread_mutex_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +000094 assert(iret == 0);
Marc Slemko6f038a72006-08-03 18:58:09 +000095 }
96
Mark Slee2f6404d2006-10-10 01:37:40 +000097 if (condInitialized_) {
98 condInitialized_ = false;
Aditya Agarwal9dc57402007-03-31 17:45:12 +000099 int iret = pthread_cond_destroy(&pthread_cond_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +0000100 assert(iret == 0);
Marc Slemko6f038a72006-08-03 18:58:09 +0000101 }
102 }
103
Mark Slee2f6404d2006-10-10 01:37:40 +0000104 mutable pthread_mutex_t pthread_mutex_;
105 mutable bool mutexInitialized_;
106 mutable pthread_cond_t pthread_cond_;
107 mutable bool condInitialized_;
Marc Slemko66949872006-07-15 01:52:39 +0000108};
109
Mark Slee2f6404d2006-10-10 01:37:40 +0000110Monitor::Monitor() : impl_(new Monitor::Impl()) {}
Marc Slemko66949872006-07-15 01:52:39 +0000111
Mark Slee2f6404d2006-10-10 01:37:40 +0000112Monitor::~Monitor() { delete impl_; }
Marc Slemko66949872006-07-15 01:52:39 +0000113
Mark Slee2f6404d2006-10-10 01:37:40 +0000114void Monitor::lock() const { impl_->lock(); }
Marc Slemko66949872006-07-15 01:52:39 +0000115
Mark Slee2f6404d2006-10-10 01:37:40 +0000116void Monitor::unlock() const { impl_->unlock(); }
Marc Slemko66949872006-07-15 01:52:39 +0000117
Mark Slee9b82d272007-05-23 05:16:07 +0000118void Monitor::wait(int64_t timeout) const { impl_->wait(timeout); }
Marc Slemko66949872006-07-15 01:52:39 +0000119
Mark Slee2f6404d2006-10-10 01:37:40 +0000120void Monitor::notify() const { impl_->notify(); }
Marc Slemko66949872006-07-15 01:52:39 +0000121
Mark Slee2f6404d2006-10-10 01:37:40 +0000122void Monitor::notifyAll() const { impl_->notifyAll(); }
Marc Slemko66949872006-07-15 01:52:39 +0000123
T Jake Lucianib5e62212009-01-31 22:36:20 +0000124}}} // apache::thrift::concurrency