blob: 3d6440c5e6faa010de3620a899cf5cd945039dad [file] [log] [blame]
David Reissea2cba82009-03-30 21:35:00 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
Mark Slee9f0c6512007-02-28 23:58:26 +000019
Marc Slemko3a3b53b2007-05-22 23:59:54 +000020#include "Monitor.h"
21#include "Exception.h"
Marc Slemko0e53ccd2006-07-17 23:51:05 +000022#include "Util.h"
Marc Slemko66949872006-07-15 01:52:39 +000023
David Reissb9db49c2010-03-09 05:19:30 +000024#include <boost/scoped_ptr.hpp>
25
Marc Slemko66949872006-07-15 01:52:39 +000026#include <assert.h>
27#include <errno.h>
Marc Slemko8a40a762006-07-19 17:46:50 +000028
29#include <iostream>
30
Marc Slemko66949872006-07-15 01:52:39 +000031#include <pthread.h>
32
T Jake Lucianib5e62212009-01-31 22:36:20 +000033namespace apache { namespace thrift { namespace concurrency {
Marc Slemko66949872006-07-15 01:52:39 +000034
David Reissb9db49c2010-03-09 05:19:30 +000035using boost::scoped_ptr;
36
Mark Sleef5f2be42006-09-05 21:05:31 +000037/**
38 * Monitor implementation using the POSIX pthread library
Marc Slemko3a3b53b2007-05-22 23:59:54 +000039 *
Mark Sleef5f2be42006-09-05 21:05:31 +000040 * @version $Id:$
41 */
Marc Slemko66949872006-07-15 01:52:39 +000042class Monitor::Impl {
43
44 public:
45
David Reissb9db49c2010-03-09 05:19:30 +000046 Impl()
47 : ownedMutex_(new Mutex()),
48 mutex_(NULL),
49 condInitialized_(false) {
50 init(ownedMutex_.get());
51 }
Marc Slemko3a3b53b2007-05-22 23:59:54 +000052
David Reissb9db49c2010-03-09 05:19:30 +000053 Impl(Mutex* mutex)
54 : mutex_(NULL),
55 condInitialized_(false) {
56 init(mutex);
57 }
Marc Slemko3a3b53b2007-05-22 23:59:54 +000058
David Reissb9db49c2010-03-09 05:19:30 +000059 Impl(Monitor* monitor)
60 : mutex_(NULL),
61 condInitialized_(false) {
62 init(&(monitor->mutex()));
Marc Slemko66949872006-07-15 01:52:39 +000063 }
64
Mark Sleef5f2be42006-09-05 21:05:31 +000065 ~Impl() { cleanup(); }
Marc Slemko6f038a72006-08-03 18:58:09 +000066
David Reissb9db49c2010-03-09 05:19:30 +000067 Mutex& mutex() { return *mutex_; }
68 void lock() { mutex().lock(); }
69 void unlock() { mutex().unlock(); }
Marc Slemko66949872006-07-15 01:52:39 +000070
Bryan Duxbury3746b292011-08-24 00:35:52 +000071 /**
72 * Exception-throwing version of waitForTimeRelative(), called simply
73 * wait(int64) for historical reasons. Timeout is in milliseconds.
74 *
75 * If the condition occurs, this function returns cleanly; on timeout or
76 * error an exception is thrown.
77 */
78 void wait(int64_t timeout_ms) const {
79 int result = waitForTimeRelative(timeout_ms);
80 if (result == ETIMEDOUT) {
81 // pthread_cond_timedwait has been observed to return early on
82 // various platforms, so comment out this assert.
83 //assert(Util::currentTime() >= (now + timeout));
84 throw TimedOutException();
85 } else if (result != 0) {
86 throw TException(
87 "pthread_cond_wait() or pthread_cond_timedwait() failed");
88 }
89 }
90
91 /**
92 * Waits until the specified timeout in milliseconds for the condition to
93 * occur, or waits forever if timeout_ms == 0.
94 *
95 * Returns 0 if condition occurs, ETIMEDOUT on timeout, or an error code.
96 */
97 int waitForTimeRelative(int64_t timeout_ms) const {
98 if (timeout_ms == 0LL) {
99 return waitForever();
100 }
101
102 struct timespec abstime;
103 Util::toTimespec(abstime, Util::currentTime() + timeout_ms);
104 return waitForTime(&abstime);
105 }
106
107 /**
108 * Waits until the absolute time specified using struct timespec.
109 * Returns 0 if condition occurs, ETIMEDOUT on timeout, or an error code.
110 */
111 int waitForTime(const timespec* abstime) const {
David Reissb9db49c2010-03-09 05:19:30 +0000112 assert(mutex_);
113 pthread_mutex_t* mutexImpl =
114 reinterpret_cast<pthread_mutex_t*>(mutex_->getUnderlyingImpl());
115 assert(mutexImpl);
Marc Slemko66949872006-07-15 01:52:39 +0000116
117 // XXX Need to assert that caller owns mutex
Bryan Duxbury3746b292011-08-24 00:35:52 +0000118 return pthread_cond_timedwait(&pthread_cond_,
119 mutexImpl,
120 abstime);
Marc Slemko66949872006-07-15 01:52:39 +0000121 }
122
Bryan Duxbury3746b292011-08-24 00:35:52 +0000123 /**
124 * Waits forever until the condition occurs.
125 * Returns 0 if condition occurs, or an error code otherwise.
126 */
127 int waitForever() const {
128 assert(mutex_);
129 pthread_mutex_t* mutexImpl =
130 reinterpret_cast<pthread_mutex_t*>(mutex_->getUnderlyingImpl());
131 assert(mutexImpl);
132 return pthread_cond_wait(&pthread_cond_, mutexImpl);
133 }
134
135
Marc Slemko66949872006-07-15 01:52:39 +0000136 void notify() {
Marc Slemko66949872006-07-15 01:52:39 +0000137 // XXX Need to assert that caller owns mutex
Aditya Agarwal9dc57402007-03-31 17:45:12 +0000138 int iret = pthread_cond_signal(&pthread_cond_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +0000139 assert(iret == 0);
Marc Slemko66949872006-07-15 01:52:39 +0000140 }
141
142 void notifyAll() {
Marc Slemko66949872006-07-15 01:52:39 +0000143 // XXX Need to assert that caller owns mutex
Aditya Agarwal9dc57402007-03-31 17:45:12 +0000144 int iret = pthread_cond_broadcast(&pthread_cond_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +0000145 assert(iret == 0);
Marc Slemko66949872006-07-15 01:52:39 +0000146 }
147
Mark Sleef5f2be42006-09-05 21:05:31 +0000148 private:
Marc Slemko66949872006-07-15 01:52:39 +0000149
David Reissb9db49c2010-03-09 05:19:30 +0000150 void init(Mutex* mutex) {
151 mutex_ = mutex;
152
153 if (pthread_cond_init(&pthread_cond_, NULL) == 0) {
154 condInitialized_ = true;
Marc Slemko6f038a72006-08-03 18:58:09 +0000155 }
156
David Reissb9db49c2010-03-09 05:19:30 +0000157 if (!condInitialized_) {
158 cleanup();
159 throw SystemResourceException();
160 }
161 }
162
163 void cleanup() {
Mark Slee2f6404d2006-10-10 01:37:40 +0000164 if (condInitialized_) {
165 condInitialized_ = false;
Aditya Agarwal9dc57402007-03-31 17:45:12 +0000166 int iret = pthread_cond_destroy(&pthread_cond_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +0000167 assert(iret == 0);
Marc Slemko6f038a72006-08-03 18:58:09 +0000168 }
169 }
170
David Reissb9db49c2010-03-09 05:19:30 +0000171 scoped_ptr<Mutex> ownedMutex_;
172 Mutex* mutex_;
173
Mark Slee2f6404d2006-10-10 01:37:40 +0000174 mutable pthread_cond_t pthread_cond_;
175 mutable bool condInitialized_;
Marc Slemko66949872006-07-15 01:52:39 +0000176};
177
Mark Slee2f6404d2006-10-10 01:37:40 +0000178Monitor::Monitor() : impl_(new Monitor::Impl()) {}
David Reissb9db49c2010-03-09 05:19:30 +0000179Monitor::Monitor(Mutex* mutex) : impl_(new Monitor::Impl(mutex)) {}
180Monitor::Monitor(Monitor* monitor) : impl_(new Monitor::Impl(monitor)) {}
Marc Slemko66949872006-07-15 01:52:39 +0000181
Mark Slee2f6404d2006-10-10 01:37:40 +0000182Monitor::~Monitor() { delete impl_; }
Marc Slemko66949872006-07-15 01:52:39 +0000183
David Reissb9db49c2010-03-09 05:19:30 +0000184Mutex& Monitor::mutex() const { return impl_->mutex(); }
185
Mark Slee2f6404d2006-10-10 01:37:40 +0000186void Monitor::lock() const { impl_->lock(); }
Marc Slemko66949872006-07-15 01:52:39 +0000187
Mark Slee2f6404d2006-10-10 01:37:40 +0000188void Monitor::unlock() const { impl_->unlock(); }
Marc Slemko66949872006-07-15 01:52:39 +0000189
Mark Slee9b82d272007-05-23 05:16:07 +0000190void Monitor::wait(int64_t timeout) const { impl_->wait(timeout); }
Marc Slemko66949872006-07-15 01:52:39 +0000191
Bryan Duxbury3746b292011-08-24 00:35:52 +0000192int Monitor::waitForTime(const timespec* abstime) const {
193 return impl_->waitForTime(abstime);
194}
195
196int Monitor::waitForTimeRelative(int64_t timeout_ms) const {
197 return impl_->waitForTimeRelative(timeout_ms);
198}
199
200int Monitor::waitForever() const {
201 return impl_->waitForever();
202}
203
Mark Slee2f6404d2006-10-10 01:37:40 +0000204void Monitor::notify() const { impl_->notify(); }
Marc Slemko66949872006-07-15 01:52:39 +0000205
Mark Slee2f6404d2006-10-10 01:37:40 +0000206void Monitor::notifyAll() const { impl_->notifyAll(); }
Marc Slemko66949872006-07-15 01:52:39 +0000207
T Jake Lucianib5e62212009-01-31 22:36:20 +0000208}}} // apache::thrift::concurrency