root/trunk/dep/src/zthread/macos/Monitor.cxx

Revision 2, 6.1 kB (checked in by yumileroy, 17 years ago)

[svn] * Proper SVN structure

Original author: Neo2003
Date: 2008-10-02 16:23:55-05:00

Line 
1/*
2 * Copyright (c) 2005, Eric Crahen
3 *
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:
10 *
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
13 *
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.
20 *
21 */
22
23#include "Monitor.h"
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29using namespace ZThread;
30
31Monitor::Monitor() : _owner(0), _waiting(false), _pending(false) {
32 
33  if(MPCreateSemaphore(1, 0, &_sema) != noErr) {
34    assert(0);
35    throw Initialization_Exception();
36  }
37
38}
39 
40Monitor::~Monitor() throw() {
41
42  assert(!_waiting);
43
44  OSStatus status = MPDeleteSemaphore(_sema);
45  if(status != noErr)
46    assert(false);
47
48}
49
50Monitor::STATE Monitor::wait(unsigned long timeout) {
51
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
54
55  AbsoluteTime tTarget;
56  Duration waitDuration =
57    (timeout == 0) ? kDurationForever : (kDurationMillisecond * timeout);
58 
59  if(waitDuration != kDurationForever)
60    tTarget = AddDurationToAbsolute(waitDuration, UpTime());
61
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();
67
68  STATE state(INVALID);
69 
70  // Serialize access to the state of the Monitor
71  // and test the state to determine if a wait is needed.
72  _waitLock.acquire();
73
74  if(pending(ANYTHING)) {
75   
76    // Return without waiting when possible
77    state = next();
78
79    _waitLock.release();
80    return state;
81
82  }
83  // Unlock the external lock if a wait() is probably needed.
84  // Access to the state is still serial.
85  _lock.release();
86
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.
92
93  // Wait, ignoring signals
94  _waiting = true;
95 
96  _waitLock.release();
97
98  // Update the wait time
99  if(waitDuration != kDurationForever)
100    waitDuration = AbsoluteDeltaToDuration(tTarget, UpTime());
101
102  // Sleep until a signal arrives or a timeout occurs
103  OSStatus status = MPWaitOnSemaphore(_sema, waitDuration);
104
105  // Reacquire serialized access to the state
106  _waitLock.acquire();
107 
108  // Awaken only when the event is set or the timeout expired
109  assert(status == kMPTimeoutErr || status == noErr);
110 
111  if(status ==  kMPTimeoutErr)
112    push(TIMEDOUT);
113
114  // Get the next available STATE
115  state = next(); 
116
117  _waiting = false; 
118
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) {
122   
123    status = MPWaitOnSemaphore(_sema, kDurationForever);
124    assert(status == noErr);
125
126  }
127
128  _pending = false;
129 
130  // Acquire the internal lock & release the external lock
131  _waitLock.release();
132
133  // Reaquire the external lock, keep from deadlocking threads calling
134  // notify(), interrupt(), etc.
135  _lock.acquire();
136
137  return state;
138
139}
140
141
142bool Monitor::interrupt() {
143
144  // Serialize access to the state
145  _waitLock.acquire();
146 
147  bool wasInterruptable = !pending(INTERRUPTED);
148  bool hasWaiter = false;
149
150  // Update the state & wake the waiter if there is one
151  if(wasInterruptable) {
152
153    push(INTERRUPTED);
154   
155    wasInterruptable = false;
156
157    if(_waiting && !_pending) {
158
159      _pending = true;
160      hasWaiter = true;
161
162    } else
163      wasInterruptable = !(_owner == MPCurrentTaskID());
164
165  }
166
167  _waitLock.release();
168
169  if(hasWaiter && !masked(Monitor::INTERRUPTED))
170    MPSignalSemaphore(_sema);
171
172  return wasInterruptable;
173
174}
175
176bool Monitor::isInterrupted() {
177
178  // Serialize access to the state
179  _waitLock.acquire();
180
181  bool wasInterrupted = pending(INTERRUPTED);
182  clear(INTERRUPTED);
183   
184  _waitLock.release();
185
186  return wasInterrupted;
187
188}
189
190
191bool Monitor::notify() {
192
193  // Serialize access to the state
194  _waitLock.acquire();
195
196  bool wasNotifyable = !pending(INTERRUPTED);
197  bool hasWaiter = false;
198
199  // Set the flag if theres a waiter
200  if(wasNotifyable) {
201
202    push(SIGNALED);
203
204    if(_waiting && !_pending) {
205
206      _pending = true;
207      hasWaiter = true;
208
209    }
210
211  }
212
213  _waitLock.release();
214
215  if(hasWaiter)
216    MPSignalSemaphore(_sema);
217
218  return wasNotifyable;
219
220}
221
222
223bool Monitor::cancel() {
224
225  // Serialize access to the state
226  _waitLock.acquire();
227
228  bool wasInterrupted = !pending(INTERRUPTED);
229  bool hasWaiter = false;
230 
231  push(CANCELED);
232
233  // Update the state if theres a waiter
234  if(wasInterrupted) {
235       
236    push(INTERRUPTED);
237
238    if(_waiting && !_pending) {
239
240      _pending = true;
241      hasWaiter = true;
242
243    }
244
245  }
246 
247  _waitLock.release();
248 
249  if(hasWaiter && !masked(Monitor::INTERRUPTED))
250    MPSignalSemaphore(_sema);
251
252  return wasInterrupted;
253
254}
255
256bool Monitor::isCanceled() {
257 
258  // Serialize access to the state
259  _waitLock.acquire();
260 
261  bool wasCanceled = Status::examine(CANCELED);
262   
263  if(_owner == MPCurrentTaskID())
264    clear(INTERRUPTED);
265
266  _waitLock.release();
267
268  return wasCanceled;
269
270}
271
272
273
274
275
276
277
278
279
280
Note: See TracBrowser for help on using the browser.