blob: 2943ef703203e0b92290084a13122ca7c376bcc9 [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
Mark Slee9b82d272007-05-23 05:16:07 +000071 void wait(int64_t timeout) const {
David Reissb9db49c2010-03-09 05:19:30 +000072 assert(mutex_);
73 pthread_mutex_t* mutexImpl =
74 reinterpret_cast<pthread_mutex_t*>(mutex_->getUnderlyingImpl());
75 assert(mutexImpl);
Marc Slemko66949872006-07-15 01:52:39 +000076
77 // XXX Need to assert that caller owns mutex
Aditya Agarwal3f234da2007-04-01 01:19:57 +000078 assert(timeout >= 0LL);
Mark Sleef5f2be42006-09-05 21:05:31 +000079 if (timeout == 0LL) {
David Reissb9db49c2010-03-09 05:19:30 +000080 int iret = pthread_cond_wait(&pthread_cond_, mutexImpl);
Aditya Agarwal3f234da2007-04-01 01:19:57 +000081 assert(iret == 0);
Marc Slemko66949872006-07-15 01:52:39 +000082 } else {
Marc Slemko66949872006-07-15 01:52:39 +000083 struct timespec abstime;
Mark Slee9b82d272007-05-23 05:16:07 +000084 int64_t now = Util::currentTime();
Marc Slemko9f27a4e2006-07-19 20:02:22 +000085 Util::toTimespec(abstime, now + timeout);
Mark Slee2f6404d2006-10-10 01:37:40 +000086 int result = pthread_cond_timedwait(&pthread_cond_,
David Reissb9db49c2010-03-09 05:19:30 +000087 mutexImpl,
Mark Slee2f6404d2006-10-10 01:37:40 +000088 &abstime);
Mark Sleef5f2be42006-09-05 21:05:31 +000089 if (result == ETIMEDOUT) {
David Reiss428d5692008-12-02 02:22:01 +000090 // pthread_cond_timedwait has been observed to return early on
91 // various platforms, so comment out this assert.
92 //assert(Util::currentTime() >= (now + timeout));
Marc Slemko3a3b53b2007-05-22 23:59:54 +000093 throw TimedOutException();
Marc Slemko66949872006-07-15 01:52:39 +000094 }
95 }
96 }
97
98 void notify() {
Marc Slemko66949872006-07-15 01:52:39 +000099 // XXX Need to assert that caller owns mutex
Aditya Agarwal9dc57402007-03-31 17:45:12 +0000100 int iret = pthread_cond_signal(&pthread_cond_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +0000101 assert(iret == 0);
Marc Slemko66949872006-07-15 01:52:39 +0000102 }
103
104 void notifyAll() {
Marc Slemko66949872006-07-15 01:52:39 +0000105 // XXX Need to assert that caller owns mutex
Aditya Agarwal9dc57402007-03-31 17:45:12 +0000106 int iret = pthread_cond_broadcast(&pthread_cond_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +0000107 assert(iret == 0);
Marc Slemko66949872006-07-15 01:52:39 +0000108 }
109
Mark Sleef5f2be42006-09-05 21:05:31 +0000110 private:
Marc Slemko66949872006-07-15 01:52:39 +0000111
David Reissb9db49c2010-03-09 05:19:30 +0000112 void init(Mutex* mutex) {
113 mutex_ = mutex;
114
115 if (pthread_cond_init(&pthread_cond_, NULL) == 0) {
116 condInitialized_ = true;
Marc Slemko6f038a72006-08-03 18:58:09 +0000117 }
118
David Reissb9db49c2010-03-09 05:19:30 +0000119 if (!condInitialized_) {
120 cleanup();
121 throw SystemResourceException();
122 }
123 }
124
125 void cleanup() {
Mark Slee2f6404d2006-10-10 01:37:40 +0000126 if (condInitialized_) {
127 condInitialized_ = false;
Aditya Agarwal9dc57402007-03-31 17:45:12 +0000128 int iret = pthread_cond_destroy(&pthread_cond_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +0000129 assert(iret == 0);
Marc Slemko6f038a72006-08-03 18:58:09 +0000130 }
131 }
132
David Reissb9db49c2010-03-09 05:19:30 +0000133 scoped_ptr<Mutex> ownedMutex_;
134 Mutex* mutex_;
135
Mark Slee2f6404d2006-10-10 01:37:40 +0000136 mutable pthread_cond_t pthread_cond_;
137 mutable bool condInitialized_;
Marc Slemko66949872006-07-15 01:52:39 +0000138};
139
Mark Slee2f6404d2006-10-10 01:37:40 +0000140Monitor::Monitor() : impl_(new Monitor::Impl()) {}
David Reissb9db49c2010-03-09 05:19:30 +0000141Monitor::Monitor(Mutex* mutex) : impl_(new Monitor::Impl(mutex)) {}
142Monitor::Monitor(Monitor* monitor) : impl_(new Monitor::Impl(monitor)) {}
Marc Slemko66949872006-07-15 01:52:39 +0000143
Mark Slee2f6404d2006-10-10 01:37:40 +0000144Monitor::~Monitor() { delete impl_; }
Marc Slemko66949872006-07-15 01:52:39 +0000145
David Reissb9db49c2010-03-09 05:19:30 +0000146Mutex& Monitor::mutex() const { return impl_->mutex(); }
147
Mark Slee2f6404d2006-10-10 01:37:40 +0000148void Monitor::lock() const { impl_->lock(); }
Marc Slemko66949872006-07-15 01:52:39 +0000149
Mark Slee2f6404d2006-10-10 01:37:40 +0000150void Monitor::unlock() const { impl_->unlock(); }
Marc Slemko66949872006-07-15 01:52:39 +0000151
Mark Slee9b82d272007-05-23 05:16:07 +0000152void Monitor::wait(int64_t timeout) const { impl_->wait(timeout); }
Marc Slemko66949872006-07-15 01:52:39 +0000153
Mark Slee2f6404d2006-10-10 01:37:40 +0000154void Monitor::notify() const { impl_->notify(); }
Marc Slemko66949872006-07-15 01:52:39 +0000155
Mark Slee2f6404d2006-10-10 01:37:40 +0000156void Monitor::notifyAll() const { impl_->notifyAll(); }
Marc Slemko66949872006-07-15 01:52:39 +0000157
T Jake Lucianib5e62212009-01-31 22:36:20 +0000158}}} // apache::thrift::concurrency