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.
29 using namespace ZThread
;
31 Monitor::Monitor() : _owner(0), _waiting(false) {
33 _handle
= ::CreateEvent(0, TRUE
, FALSE
, 0);
44 ::CloseHandle(_handle
);
48 Monitor::STATE
Monitor::wait(unsigned long ms
) {
50 // Update the owner on first use. The owner will not change, each
51 // thread waits only on a single Monitor and a Monitor is never
54 _owner
= ::GetCurrentThreadId();
56 STATE state
; //(INVALID);
58 // Serialize access to the state of the Monitor
59 // and test the state to determine if a wait is needed.
62 if(pending(ANYTHING
)) {
64 // Return without waiting when possible
71 // Unlock the external lock if a wait() is probably needed.
72 // Access to the state is still serial.
75 // Wait for a transition in the state that is of interest, this
76 // allows waits to exclude certain flags (e.g. INTERRUPTED)
77 // for a single wait() w/o actually discarding those flags -
78 // they will remain set until a wait interested in those flags
80 // if(!currentState(interest)) {
82 // Wait, ignoring signals
85 // Block until the event is set.
88 // The event is manual reset so this lack of atmoicity will not
92 ::WaitForSingleObject(_handle
, ((ms
== 0) ? INFINITE
: (DWORD
)ms
));
94 // Reacquire serialized access to the state
97 // Awaken only when the event is set or the timeout expired
98 assert(dwResult
== WAIT_OBJECT_0
|| dwResult
== WAIT_TIMEOUT
);
100 if(dwResult
== WAIT_TIMEOUT
)
103 // Get the next available STATE
107 ::ResetEvent(_handle
);
109 // Acquire the internal lock & release the external lock
112 // Reaquire the external lock, keep from deadlocking threads calling
113 // notify(), interrupt(), etc.
121 bool Monitor::interrupt() {
123 // Serialize access to the state
126 bool wasInterruptable
= !pending(INTERRUPTED
);
127 bool hadWaiter
= _waiting
;
129 if(wasInterruptable
) {
131 // Update the state & wake the waiter if there is one
134 wasInterruptable
= false;
136 if(hadWaiter
&& !masked(Monitor::INTERRUPTED
)) {
138 // Blocked on a synchronization object
139 if(::SetEvent(_handle
) == FALSE
) {
144 wasInterruptable
= !(_owner
== ::GetCurrentThreadId());
150 // Only returns true when an interrupted thread is not currently blocked
151 return wasInterruptable
;
155 bool Monitor::isInterrupted() {
157 // Serialize access to the state
160 bool wasInterrupted
= pending(INTERRUPTED
);
165 return wasInterrupted
;
170 bool Monitor::notify() {
172 // Serialize access to the state
175 bool wasNotifyable
= !pending(INTERRUPTED
);
179 // Set the flag and wake the waiter if there
183 // If there is a waiter then send the signal.
185 if(::SetEvent(_handle
) == FALSE
) {
193 return wasNotifyable
;
198 bool Monitor::cancel() {
200 // Serialize access to the state
203 bool wasInterrupted
= !pending(INTERRUPTED
);
204 bool hadWaiter
= _waiting
;
210 // Update the state & wake the waiter if there is one
213 // If there is a waiter then send the signal.
214 if(hadWaiter
&& !masked(Monitor::INTERRUPTED
))
215 if(::SetEvent(_handle
) == FALSE
) {
223 return wasInterrupted
;
227 bool Monitor::isCanceled() {
229 // Serialize access to the state
232 bool wasCanceled
= examine(CANCELED
);
234 if(_owner
== ::GetCurrentThreadId())