blob: 932ae686dff57b191244def629c4d0b69b7f1b35 [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
Marc Slemko3a3b53b2007-05-22 23:59:54 +000018namespace facebook { 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 * @author marc
24 * @version $Id:$
25 */
Marc Slemko66949872006-07-15 01:52:39 +000026class Monitor::Impl {
27
28 public:
29
Mark Sleef5f2be42006-09-05 21:05:31 +000030 Impl() :
Mark Slee2f6404d2006-10-10 01:37:40 +000031 mutexInitialized_(false),
32 condInitialized_(false) {
Marc Slemko3a3b53b2007-05-22 23:59:54 +000033
Mark Slee2782d6d2007-05-23 04:55:30 +000034 if (pthread_mutex_init(&pthread_mutex_, NULL) == 0) {
Mark Slee2f6404d2006-10-10 01:37:40 +000035 mutexInitialized_ = true;
Marc Slemko3a3b53b2007-05-22 23:59:54 +000036
Mark Slee2782d6d2007-05-23 04:55:30 +000037 if (pthread_cond_init(&pthread_cond_, NULL) == 0) {
Marc Slemko3a3b53b2007-05-22 23:59:54 +000038 condInitialized_ = true;
39 }
40 }
41
Mark Slee2782d6d2007-05-23 04:55:30 +000042 if (!mutexInitialized_ || !condInitialized_) {
Marc Slemko6f038a72006-08-03 18:58:09 +000043 cleanup();
Marc Slemko3a3b53b2007-05-22 23:59:54 +000044 throw SystemResourceException();
Marc Slemko66949872006-07-15 01:52:39 +000045 }
46 }
47
Mark Sleef5f2be42006-09-05 21:05:31 +000048 ~Impl() { cleanup(); }
Marc Slemko6f038a72006-08-03 18:58:09 +000049
Mark Slee2f6404d2006-10-10 01:37:40 +000050 void lock() const { pthread_mutex_lock(&pthread_mutex_); }
Marc Slemko66949872006-07-15 01:52:39 +000051
Mark Slee2f6404d2006-10-10 01:37:40 +000052 void unlock() const { pthread_mutex_unlock(&pthread_mutex_); }
Marc Slemko66949872006-07-15 01:52:39 +000053
Mark Slee9b82d272007-05-23 05:16:07 +000054 void wait(int64_t timeout) const {
Marc Slemko66949872006-07-15 01:52:39 +000055
56 // XXX Need to assert that caller owns mutex
Aditya Agarwal3f234da2007-04-01 01:19:57 +000057 assert(timeout >= 0LL);
Mark Sleef5f2be42006-09-05 21:05:31 +000058 if (timeout == 0LL) {
Aditya Agarwal9dc57402007-03-31 17:45:12 +000059 int iret = pthread_cond_wait(&pthread_cond_, &pthread_mutex_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +000060 assert(iret == 0);
Marc Slemko66949872006-07-15 01:52:39 +000061 } else {
Marc Slemko66949872006-07-15 01:52:39 +000062 struct timespec abstime;
Mark Slee9b82d272007-05-23 05:16:07 +000063 int64_t now = Util::currentTime();
Marc Slemko9f27a4e2006-07-19 20:02:22 +000064 Util::toTimespec(abstime, now + timeout);
Mark Slee2f6404d2006-10-10 01:37:40 +000065 int result = pthread_cond_timedwait(&pthread_cond_,
66 &pthread_mutex_,
67 &abstime);
Mark Sleef5f2be42006-09-05 21:05:31 +000068 if (result == ETIMEDOUT) {
David Reiss428d5692008-12-02 02:22:01 +000069 // pthread_cond_timedwait has been observed to return early on
70 // various platforms, so comment out this assert.
71 //assert(Util::currentTime() >= (now + timeout));
Marc Slemko3a3b53b2007-05-22 23:59:54 +000072 throw TimedOutException();
Marc Slemko66949872006-07-15 01:52:39 +000073 }
74 }
75 }
76
77 void notify() {
Marc Slemko66949872006-07-15 01:52:39 +000078 // XXX Need to assert that caller owns mutex
Aditya Agarwal9dc57402007-03-31 17:45:12 +000079 int iret = pthread_cond_signal(&pthread_cond_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +000080 assert(iret == 0);
Marc Slemko66949872006-07-15 01:52:39 +000081 }
82
83 void notifyAll() {
Marc Slemko66949872006-07-15 01:52:39 +000084 // XXX Need to assert that caller owns mutex
Aditya Agarwal9dc57402007-03-31 17:45:12 +000085 int iret = pthread_cond_broadcast(&pthread_cond_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +000086 assert(iret == 0);
Marc Slemko66949872006-07-15 01:52:39 +000087 }
88
Mark Sleef5f2be42006-09-05 21:05:31 +000089 private:
Marc Slemko66949872006-07-15 01:52:39 +000090
Marc Slemko6f038a72006-08-03 18:58:09 +000091 void cleanup() {
Mark Slee2f6404d2006-10-10 01:37:40 +000092 if (mutexInitialized_) {
93 mutexInitialized_ = false;
Aditya Agarwal9dc57402007-03-31 17:45:12 +000094 int iret = pthread_mutex_destroy(&pthread_mutex_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +000095 assert(iret == 0);
Marc Slemko6f038a72006-08-03 18:58:09 +000096 }
97
Mark Slee2f6404d2006-10-10 01:37:40 +000098 if (condInitialized_) {
99 condInitialized_ = false;
Aditya Agarwal9dc57402007-03-31 17:45:12 +0000100 int iret = pthread_cond_destroy(&pthread_cond_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +0000101 assert(iret == 0);
Marc Slemko6f038a72006-08-03 18:58:09 +0000102 }
103 }
104
Mark Slee2f6404d2006-10-10 01:37:40 +0000105 mutable pthread_mutex_t pthread_mutex_;
106 mutable bool mutexInitialized_;
107 mutable pthread_cond_t pthread_cond_;
108 mutable bool condInitialized_;
Marc Slemko66949872006-07-15 01:52:39 +0000109};
110
Mark Slee2f6404d2006-10-10 01:37:40 +0000111Monitor::Monitor() : impl_(new Monitor::Impl()) {}
Marc Slemko66949872006-07-15 01:52:39 +0000112
Mark Slee2f6404d2006-10-10 01:37:40 +0000113Monitor::~Monitor() { delete impl_; }
Marc Slemko66949872006-07-15 01:52:39 +0000114
Mark Slee2f6404d2006-10-10 01:37:40 +0000115void Monitor::lock() const { impl_->lock(); }
Marc Slemko66949872006-07-15 01:52:39 +0000116
Mark Slee2f6404d2006-10-10 01:37:40 +0000117void Monitor::unlock() const { impl_->unlock(); }
Marc Slemko66949872006-07-15 01:52:39 +0000118
Mark Slee9b82d272007-05-23 05:16:07 +0000119void Monitor::wait(int64_t timeout) const { impl_->wait(timeout); }
Marc Slemko66949872006-07-15 01:52:39 +0000120
Mark Slee2f6404d2006-10-10 01:37:40 +0000121void Monitor::notify() const { impl_->notify(); }
Marc Slemko66949872006-07-15 01:52:39 +0000122
Mark Slee2f6404d2006-10-10 01:37:40 +0000123void Monitor::notifyAll() const { impl_->notifyAll(); }
Marc Slemko66949872006-07-15 01:52:39 +0000124
125}}} // facebook::thrift::concurrency