Initial Patch of Auction House bot rev. 135
[auctionmangos.git] / dep / src / zthread / macos / Monitor.cxx
blobab7806b13df9193371f0d019689fabcebe02b5b0
1 /*
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.
23 #include "Monitor.h"
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
29 using namespace ZThread;
31 Monitor::Monitor() : _owner(0), _waiting(false), _pending(false) {
33 if(MPCreateSemaphore(1, 0, &_sema) != noErr) {
34 assert(0);
35 throw Initialization_Exception();
40 Monitor::~Monitor() throw() {
42 assert(!_waiting);
44 OSStatus status = MPDeleteSemaphore(_sema);
45 if(status != noErr)
46 assert(false);
50 Monitor::STATE Monitor::wait(unsigned long timeout) {
52 // Calcuate the time, taking into account Intertask Signaling Time
53 // http://developer.apple.com/techpubs/macosx/Carbon/oss/MultiPServices/Multiprocessing_Services/index.html?http://developer.apple.com/techpubs/macosx/Carbon/oss/MultiPServices/Multiprocessing_Services/Functions/Creating_and_ssage_Queues.html
55 AbsoluteTime tTarget;
56 Duration waitDuration =
57 (timeout == 0) ? kDurationForever : (kDurationMillisecond * timeout);
59 if(waitDuration != kDurationForever)
60 tTarget = AddDurationToAbsolute(waitDuration, UpTime());
62 // Update the owner on first use. The owner will not change, each
63 // thread waits only on a single Monitor and a Monitor is never
64 // shared
65 if(_owner == 0)
66 _owner = MPCurrentTaskID();
68 STATE state(INVALID);
70 // Serialize access to the state of the Monitor
71 // and test the state to determine if a wait is needed.
72 _waitLock.acquire();
74 if(pending(ANYTHING)) {
76 // Return without waiting when possible
77 state = next();
79 _waitLock.release();
80 return state;
83 // Unlock the external lock if a wait() is probably needed.
84 // Access to the state is still serial.
85 _lock.release();
87 // Wait for a transition in the state that is of interest, this
88 // allows waits to exclude certain flags (e.g. INTERRUPTED)
89 // for a single wait() w/o actually discarding those flags -
90 // they will remain set until a wait interested in those flags
91 // occurs.
93 // Wait, ignoring signals
94 _waiting = true;
96 _waitLock.release();
98 // Update the wait time
99 if(waitDuration != kDurationForever)
100 waitDuration = AbsoluteDeltaToDuration(tTarget, UpTime());
102 // Sleep until a signal arrives or a timeout occurs
103 OSStatus status = MPWaitOnSemaphore(_sema, waitDuration);
105 // Reacquire serialized access to the state
106 _waitLock.acquire();
108 // Awaken only when the event is set or the timeout expired
109 assert(status == kMPTimeoutErr || status == noErr);
111 if(status == kMPTimeoutErr)
112 push(TIMEDOUT);
114 // Get the next available STATE
115 state = next();
117 _waiting = false;
119 // Its possible that a timeout will wake the thread before a signal is
120 // delivered. Absorb that leftover so the next wait isn't aborted right away
121 if(status == kMPTimeoutErr && _pending) {
123 status = MPWaitOnSemaphore(_sema, kDurationForever);
124 assert(status == noErr);
128 _pending = false;
130 // Acquire the internal lock & release the external lock
131 _waitLock.release();
133 // Reaquire the external lock, keep from deadlocking threads calling
134 // notify(), interrupt(), etc.
135 _lock.acquire();
137 return state;
142 bool Monitor::interrupt() {
144 // Serialize access to the state
145 _waitLock.acquire();
147 bool wasInterruptable = !pending(INTERRUPTED);
148 bool hasWaiter = false;
150 // Update the state & wake the waiter if there is one
151 if(wasInterruptable) {
153 push(INTERRUPTED);
155 wasInterruptable = false;
157 if(_waiting && !_pending) {
159 _pending = true;
160 hasWaiter = true;
162 } else
163 wasInterruptable = !(_owner == MPCurrentTaskID());
167 _waitLock.release();
169 if(hasWaiter && !masked(Monitor::INTERRUPTED))
170 MPSignalSemaphore(_sema);
172 return wasInterruptable;
176 bool Monitor::isInterrupted() {
178 // Serialize access to the state
179 _waitLock.acquire();
181 bool wasInterrupted = pending(INTERRUPTED);
182 clear(INTERRUPTED);
184 _waitLock.release();
186 return wasInterrupted;
191 bool Monitor::notify() {
193 // Serialize access to the state
194 _waitLock.acquire();
196 bool wasNotifyable = !pending(INTERRUPTED);
197 bool hasWaiter = false;
199 // Set the flag if theres a waiter
200 if(wasNotifyable) {
202 push(SIGNALED);
204 if(_waiting && !_pending) {
206 _pending = true;
207 hasWaiter = true;
213 _waitLock.release();
215 if(hasWaiter)
216 MPSignalSemaphore(_sema);
218 return wasNotifyable;
223 bool Monitor::cancel() {
225 // Serialize access to the state
226 _waitLock.acquire();
228 bool wasInterrupted = !pending(INTERRUPTED);
229 bool hasWaiter = false;
231 push(CANCELED);
233 // Update the state if theres a waiter
234 if(wasInterrupted) {
236 push(INTERRUPTED);
238 if(_waiting && !_pending) {
240 _pending = true;
241 hasWaiter = true;
247 _waitLock.release();
249 if(hasWaiter && !masked(Monitor::INTERRUPTED))
250 MPSignalSemaphore(_sema);
252 return wasInterrupted;
256 bool Monitor::isCanceled() {
258 // Serialize access to the state
259 _waitLock.acquire();
261 bool wasCanceled = Status::examine(CANCELED);
263 if(_owner == MPCurrentTaskID())
264 clear(INTERRUPTED);
266 _waitLock.release();
268 return wasCanceled;