2
* Copyright (c) 2005, Eric Crahen
4
* Permission is hereby granted, free of charge, to any person obtaining a copy
5
* of this software and associated documentation files (the "Software"), to deal
6
* in the Software without restriction, including without limitation the rights
7
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
* copies of the Software, and to permit persons to whom the Software is furnished
9
* to do so, subject to the following conditions:
11
* The above copyright notice and this permission notice shall be included in all
12
* copies or substantial portions of the Software.
14
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
#include "../TimeStrategy.h"
33
Monitor::Monitor() : _owner(0), _waiting(false) {
35
pthread_cond_init(&_waitCond, 0);
36
pthread_mutex_init(&_waitLock, 0);
44
pthread_cond_destroy(&_waitCond);
45
pthread_mutex_destroy(&_waitLock);
49
Monitor::STATE Monitor::wait(unsigned long ms) {
51
// Update the owner on first use. The owner will not change, each
52
// thread waits only on a single Monitor and a Monitor is never
55
_owner = pthread_self();
59
// Serialize access to the state of the Monitor
60
// and test the state to determine if a wait is needed.
62
pthread_mutex_lock(&_waitLock);
64
if(pending(ANYTHING)) {
66
// Return without waiting when possible
69
pthread_mutex_unlock(&_waitLock);
74
// Unlock the external lock if a wait() is probably needed.
75
// Access to the state is still serial.
78
// Wait for a transition in the state that is of interest, this
79
// allows waits to exclude certain flags (e.g. INTERRUPTED)
80
// for a single wait() w/o actually discarding those flags -
81
// they will remain set until a wait interested in those flags
83
// if(!currentState(interest)) {
85
// Wait, ignoring signals
89
if(ms == 0) { // Wait forever
91
do { // ignore signals unless the state is interesting
92
status = pthread_cond_wait(&_waitCond, &_waitLock);
93
} while(status == EINTR && !pending(ANYTHING));
95
// Akwaken only when a state is pending
100
// Find the target time
103
ms += t.milliseconds();
105
unsigned long s = t.seconds() + (ms / 1000);
108
// Convert to a timespec
109
struct ::timespec timeout;
112
timeout.tv_nsec = ms*1000000;
114
// Wait ignoring signals until the state is interesting
117
// When a timeout occurs, update the state to reflect that.
118
status = pthread_cond_timedwait(&_waitCond, &_waitLock, &timeout);
120
} while(status == EINTR && !pending(ANYTHING));
122
// Akwaken only when a state is pending or when the timeout expired
123
assert(status == 0 || status == ETIMEDOUT);
125
if(status == ETIMEDOUT)
130
// Get the next available STATE
134
pthread_mutex_unlock(&_waitLock);
136
// Reaquire the external lock, keep from deadlocking threads calling
137
// notify(), interrupt(), etc.
146
bool Monitor::interrupt() {
148
// Serialize access to the state
149
pthread_mutex_lock(&_waitLock);
151
bool wasInterruptable = !pending(INTERRUPTED);
152
bool hadWaiter = _waiting;
154
if(wasInterruptable) {
156
// Update the state & wake the waiter if there is one
159
wasInterruptable = false;
161
if(hadWaiter && !masked(Monitor::INTERRUPTED))
162
pthread_cond_signal(&_waitCond);
164
wasInterruptable = !pthread_equal(_owner, pthread_self());
168
pthread_mutex_unlock(&_waitLock);
170
// Only returns true when an interrupted thread is not currently blocked
171
return wasInterruptable;
175
bool Monitor::isInterrupted() {
177
// Serialize access to the state
178
pthread_mutex_lock(&_waitLock);
180
bool wasInterrupted = pending(INTERRUPTED);
184
pthread_mutex_unlock(&_waitLock);
186
return wasInterrupted;
190
bool Monitor::isCanceled() {
192
// Serialize access to the state
193
pthread_mutex_lock(&_waitLock);
195
bool wasCanceled = examine(CANCELED);
197
if(pthread_equal(_owner, pthread_self()))
200
pthread_mutex_unlock(&_waitLock);
206
bool Monitor::cancel() {
208
// Serialize access to the state
209
pthread_mutex_lock(&_waitLock);
211
bool wasInterrupted = !pending(INTERRUPTED);
212
bool hadWaiter = _waiting;
218
// Update the state & wake the waiter if there is one
221
if(hadWaiter && !masked(Monitor::INTERRUPTED))
222
pthread_cond_signal(&_waitCond);
226
pthread_mutex_unlock(&_waitLock);
228
return wasInterrupted;
232
bool Monitor::notify() {
234
// Serialize access to the state
235
pthread_mutex_lock(&_waitLock);
237
bool wasNotifyable = !pending(INTERRUPTED);
241
// Set the flag and wake the waiter if there
246
pthread_cond_signal(&_waitCond);
250
pthread_mutex_unlock(&_waitLock);
252
return wasNotifyable;
256
} // namespace ZThread