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

Revision 2, 5.8 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#include "../Debug.h"
25#include "../TimeStrategy.h"
26
27#include <errno.h>
28#include <assert.h>
29#include <signal.h>
30
31namespace ZThread {
32
33Monitor::Monitor() : _owner(0), _waiting(false) {
34 
35  pthread_cond_init(&_waitCond, 0);
36  pthread_mutex_init(&_waitLock, 0);
37
38}
39 
40Monitor::~Monitor() {
41 
42  assert(!_waiting);
43
44  pthread_cond_destroy(&_waitCond);
45  pthread_mutex_destroy(&_waitLock);
46 
47}
48
49Monitor::STATE Monitor::wait(unsigned long ms) {
50
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
53  // shared
54  if(_owner == 0)
55    _owner = pthread_self();
56
57  STATE state(INVALID);
58 
59  // Serialize access to the state of the Monitor
60  // and test the state to determine if a wait is needed.
61 
62  pthread_mutex_lock(&_waitLock);
63 
64  if(pending(ANYTHING)) {
65   
66    // Return without waiting when possible
67    state = next();
68
69    pthread_mutex_unlock(&_waitLock);
70    return state;
71
72  }
73     
74  // Unlock the external lock if a wait() is probably needed.
75  // Access to the state is still serial.
76  _lock.release();
77 
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
82  // occurs.
83  //  if(!currentState(interest)) {
84
85  // Wait, ignoring signals
86  _waiting = true;
87  int status = 0;
88 
89  if(ms == 0) { // Wait forever
90   
91    do { // ignore signals unless the state is interesting 
92      status = pthread_cond_wait(&_waitCond, &_waitLock);
93    } while(status == EINTR && !pending(ANYTHING));
94   
95    // Akwaken only when a state is pending
96    assert(status == 0);
97   
98  } else {
99   
100    // Find the target time
101    TimeStrategy t;
102
103    ms += t.milliseconds();
104
105    unsigned long s = t.seconds() + (ms / 1000);
106    ms %= 1000;
107
108    // Convert to a timespec
109    struct ::timespec timeout;   
110   
111    timeout.tv_sec = s;
112    timeout.tv_nsec = ms*1000000;
113   
114    // Wait ignoring signals until the state is interesting   
115    do {
116     
117      // When a timeout occurs, update the state to reflect that.
118      status = pthread_cond_timedwait(&_waitCond, &_waitLock, &timeout);
119     
120    } while(status == EINTR && !pending(ANYTHING));
121 
122    // Akwaken only when a state is pending or when the timeout expired
123    assert(status == 0 || status == ETIMEDOUT);
124   
125    if(status == ETIMEDOUT)
126      push(TIMEDOUT);
127
128  }
129 
130  // Get the next available STATE
131  state = next(); 
132  _waiting = false; 
133   
134  pthread_mutex_unlock(&_waitLock);
135   
136  // Reaquire the external lock, keep from deadlocking threads calling
137  // notify(), interrupt(), etc.
138
139  _lock.acquire();
140
141  return state;
142
143}
144
145
146bool Monitor::interrupt() {
147
148  // Serialize access to the state
149  pthread_mutex_lock(&_waitLock);
150 
151  bool wasInterruptable = !pending(INTERRUPTED);
152  bool hadWaiter = _waiting;
153 
154  if(wasInterruptable) {
155 
156    // Update the state & wake the waiter if there is one
157    push(INTERRUPTED);
158
159    wasInterruptable = false;
160   
161    if(hadWaiter && !masked(Monitor::INTERRUPTED))
162      pthread_cond_signal(&_waitCond);
163    else
164      wasInterruptable = !pthread_equal(_owner, pthread_self());
165
166  }
167
168  pthread_mutex_unlock(&_waitLock);
169
170  // Only returns true when an interrupted thread is not currently blocked
171  return wasInterruptable;
172
173}
174
175bool Monitor::isInterrupted() {
176
177  // Serialize access to the state
178  pthread_mutex_lock(&_waitLock);
179
180  bool wasInterrupted = pending(INTERRUPTED);
181
182  clear(INTERRUPTED);
183   
184  pthread_mutex_unlock(&_waitLock);
185
186  return wasInterrupted;
187
188}
189
190bool Monitor::isCanceled() {
191
192  // Serialize access to the state
193  pthread_mutex_lock(&_waitLock);
194
195  bool wasCanceled = examine(CANCELED);
196   
197  if(pthread_equal(_owner, pthread_self()))
198    clear(INTERRUPTED);
199
200  pthread_mutex_unlock(&_waitLock);
201
202  return wasCanceled;
203
204}
205
206bool Monitor::cancel() {
207
208  // Serialize access to the state
209  pthread_mutex_lock(&_waitLock);
210
211  bool wasInterrupted = !pending(INTERRUPTED);
212  bool hadWaiter = _waiting;
213 
214  push(CANCELED);
215
216  if(wasInterrupted) {
217 
218    // Update the state & wake the waiter if there is one
219    push(INTERRUPTED);
220   
221    if(hadWaiter && !masked(Monitor::INTERRUPTED))
222      pthread_cond_signal(&_waitCond);
223   
224  }
225
226  pthread_mutex_unlock(&_waitLock);
227
228  return wasInterrupted;
229
230}
231
232bool Monitor::notify() {
233
234  // Serialize access to the state
235  pthread_mutex_lock(&_waitLock);
236
237  bool wasNotifyable = !pending(INTERRUPTED);
238 
239  if(wasNotifyable) {
240 
241    // Set the flag and wake the waiter if there
242    // is one
243    push(SIGNALED);
244   
245    if(_waiting)
246      pthread_cond_signal(&_waitCond);
247   
248  }
249
250  pthread_mutex_unlock(&_waitLock);
251
252  return wasNotifyable;
253
254}
255
256} // namespace ZThread
257
Note: See TracBrowser for help on using the browser.