blob: 2055caa950be9bf4dc8b3c86f756fd7a6d77235f [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
24#include <assert.h>
25#include <errno.h>
Marc Slemko8a40a762006-07-19 17:46:50 +000026
27#include <iostream>
28
Marc Slemko66949872006-07-15 01:52:39 +000029#include <pthread.h>
30
T Jake Lucianib5e62212009-01-31 22:36:20 +000031namespace apache { namespace thrift { namespace concurrency {
Marc Slemko66949872006-07-15 01:52:39 +000032
Mark Sleef5f2be42006-09-05 21:05:31 +000033/**
34 * Monitor implementation using the POSIX pthread library
Marc Slemko3a3b53b2007-05-22 23:59:54 +000035 *
Mark Sleef5f2be42006-09-05 21:05:31 +000036 * @version $Id:$
37 */
Marc Slemko66949872006-07-15 01:52:39 +000038class Monitor::Impl {
39
40 public:
41
Mark Sleef5f2be42006-09-05 21:05:31 +000042 Impl() :
Mark Slee2f6404d2006-10-10 01:37:40 +000043 mutexInitialized_(false),
44 condInitialized_(false) {
Marc Slemko3a3b53b2007-05-22 23:59:54 +000045
Mark Slee2782d6d2007-05-23 04:55:30 +000046 if (pthread_mutex_init(&pthread_mutex_, NULL) == 0) {
Mark Slee2f6404d2006-10-10 01:37:40 +000047 mutexInitialized_ = true;
Marc Slemko3a3b53b2007-05-22 23:59:54 +000048
Mark Slee2782d6d2007-05-23 04:55:30 +000049 if (pthread_cond_init(&pthread_cond_, NULL) == 0) {
Marc Slemko3a3b53b2007-05-22 23:59:54 +000050 condInitialized_ = true;
51 }
52 }
53
Mark Slee2782d6d2007-05-23 04:55:30 +000054 if (!mutexInitialized_ || !condInitialized_) {
Marc Slemko6f038a72006-08-03 18:58:09 +000055 cleanup();
Marc Slemko3a3b53b2007-05-22 23:59:54 +000056 throw SystemResourceException();
Marc Slemko66949872006-07-15 01:52:39 +000057 }
58 }
59
Mark Sleef5f2be42006-09-05 21:05:31 +000060 ~Impl() { cleanup(); }
Marc Slemko6f038a72006-08-03 18:58:09 +000061
Mark Slee2f6404d2006-10-10 01:37:40 +000062 void lock() const { pthread_mutex_lock(&pthread_mutex_); }
Marc Slemko66949872006-07-15 01:52:39 +000063
Mark Slee2f6404d2006-10-10 01:37:40 +000064 void unlock() const { pthread_mutex_unlock(&pthread_mutex_); }
Marc Slemko66949872006-07-15 01:52:39 +000065
Mark Slee9b82d272007-05-23 05:16:07 +000066 void wait(int64_t timeout) const {
Marc Slemko66949872006-07-15 01:52:39 +000067
68 // XXX Need to assert that caller owns mutex
Aditya Agarwal3f234da2007-04-01 01:19:57 +000069 assert(timeout >= 0LL);
Mark Sleef5f2be42006-09-05 21:05:31 +000070 if (timeout == 0LL) {
Aditya Agarwal9dc57402007-03-31 17:45:12 +000071 int iret = pthread_cond_wait(&pthread_cond_, &pthread_mutex_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +000072 assert(iret == 0);
Marc Slemko66949872006-07-15 01:52:39 +000073 } else {
Marc Slemko66949872006-07-15 01:52:39 +000074 struct timespec abstime;
Mark Slee9b82d272007-05-23 05:16:07 +000075 int64_t now = Util::currentTime();
Marc Slemko9f27a4e2006-07-19 20:02:22 +000076 Util::toTimespec(abstime, now + timeout);
Mark Slee2f6404d2006-10-10 01:37:40 +000077 int result = pthread_cond_timedwait(&pthread_cond_,
78 &pthread_mutex_,
79 &abstime);
Mark Sleef5f2be42006-09-05 21:05:31 +000080 if (result == ETIMEDOUT) {
David Reiss428d5692008-12-02 02:22:01 +000081 // pthread_cond_timedwait has been observed to return early on
82 // various platforms, so comment out this assert.
83 //assert(Util::currentTime() >= (now + timeout));
Marc Slemko3a3b53b2007-05-22 23:59:54 +000084 throw TimedOutException();
Marc Slemko66949872006-07-15 01:52:39 +000085 }
86 }
87 }
88
89 void notify() {
Marc Slemko66949872006-07-15 01:52:39 +000090 // XXX Need to assert that caller owns mutex
Aditya Agarwal9dc57402007-03-31 17:45:12 +000091 int iret = pthread_cond_signal(&pthread_cond_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +000092 assert(iret == 0);
Marc Slemko66949872006-07-15 01:52:39 +000093 }
94
95 void notifyAll() {
Marc Slemko66949872006-07-15 01:52:39 +000096 // XXX Need to assert that caller owns mutex
Aditya Agarwal9dc57402007-03-31 17:45:12 +000097 int iret = pthread_cond_broadcast(&pthread_cond_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +000098 assert(iret == 0);
Marc Slemko66949872006-07-15 01:52:39 +000099 }
100
Mark Sleef5f2be42006-09-05 21:05:31 +0000101 private:
Marc Slemko66949872006-07-15 01:52:39 +0000102
Marc Slemko6f038a72006-08-03 18:58:09 +0000103 void cleanup() {
Mark Slee2f6404d2006-10-10 01:37:40 +0000104 if (mutexInitialized_) {
105 mutexInitialized_ = false;
Aditya Agarwal9dc57402007-03-31 17:45:12 +0000106 int iret = pthread_mutex_destroy(&pthread_mutex_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +0000107 assert(iret == 0);
Marc Slemko6f038a72006-08-03 18:58:09 +0000108 }
109
Mark Slee2f6404d2006-10-10 01:37:40 +0000110 if (condInitialized_) {
111 condInitialized_ = false;
Aditya Agarwal9dc57402007-03-31 17:45:12 +0000112 int iret = pthread_cond_destroy(&pthread_cond_);
Aditya Agarwal3f234da2007-04-01 01:19:57 +0000113 assert(iret == 0);
Marc Slemko6f038a72006-08-03 18:58:09 +0000114 }
115 }
116
Mark Slee2f6404d2006-10-10 01:37:40 +0000117 mutable pthread_mutex_t pthread_mutex_;
118 mutable bool mutexInitialized_;
119 mutable pthread_cond_t pthread_cond_;
120 mutable bool condInitialized_;
Marc Slemko66949872006-07-15 01:52:39 +0000121};
122
Mark Slee2f6404d2006-10-10 01:37:40 +0000123Monitor::Monitor() : impl_(new Monitor::Impl()) {}
Marc Slemko66949872006-07-15 01:52:39 +0000124
Mark Slee2f6404d2006-10-10 01:37:40 +0000125Monitor::~Monitor() { delete impl_; }
Marc Slemko66949872006-07-15 01:52:39 +0000126
Mark Slee2f6404d2006-10-10 01:37:40 +0000127void Monitor::lock() const { impl_->lock(); }
Marc Slemko66949872006-07-15 01:52:39 +0000128
Mark Slee2f6404d2006-10-10 01:37:40 +0000129void Monitor::unlock() const { impl_->unlock(); }
Marc Slemko66949872006-07-15 01:52:39 +0000130
Mark Slee9b82d272007-05-23 05:16:07 +0000131void Monitor::wait(int64_t timeout) const { impl_->wait(timeout); }
Marc Slemko66949872006-07-15 01:52:39 +0000132
Mark Slee2f6404d2006-10-10 01:37:40 +0000133void Monitor::notify() const { impl_->notify(); }
Marc Slemko66949872006-07-15 01:52:39 +0000134
Mark Slee2f6404d2006-10-10 01:37:40 +0000135void Monitor::notifyAll() const { impl_->notifyAll(); }
Marc Slemko66949872006-07-15 01:52:39 +0000136
T Jake Lucianib5e62212009-01-31 22:36:20 +0000137}}} // apache::thrift::concurrency