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