Initial Patch of Auction House bot rev. 135
[auctionmangos.git] / dep / src / zthread / posix / Monitor.cxx
blobbb157dae0dc2ee16ad09c204a66ca393949f57fc
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"
24 #include "../Debug.h"
25 #include "../TimeStrategy.h"
27 #include <errno.h>
28 #include <assert.h>
29 #include <signal.h>
31 namespace ZThread {
33 Monitor::Monitor() : _owner(0), _waiting(false) {
35 pthread_cond_init(&_waitCond, 0);
36 pthread_mutex_init(&_waitLock, 0);
40 Monitor::~Monitor() {
42 assert(!_waiting);
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
53 // shared
54 if(_owner == 0)
55 _owner = pthread_self();
57 STATE state(INVALID);
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
67 state = next();
69 pthread_mutex_unlock(&_waitLock);
70 return state;
74 // Unlock the external lock if a wait() is probably needed.
75 // Access to the state is still serial.
76 _lock.release();
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)) {
85 // Wait, ignoring signals
86 _waiting = true;
87 int status = 0;
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
96 assert(status == 0);
98 } else {
100 // Find the target time
101 TimeStrategy t;
103 ms += t.milliseconds();
105 unsigned long s = t.seconds() + (ms / 1000);
106 ms %= 1000;
108 // Convert to a timespec
109 struct ::timespec timeout;
111 timeout.tv_sec = s;
112 timeout.tv_nsec = ms*1000000;
114 // Wait ignoring signals until the state is interesting
115 do {
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)
126 push(TIMEDOUT);
130 // Get the next available STATE
131 state = next();
132 _waiting = false;
134 pthread_mutex_unlock(&_waitLock);
136 // Reaquire the external lock, keep from deadlocking threads calling
137 // notify(), interrupt(), etc.
139 _lock.acquire();
141 return state;
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
157 push(INTERRUPTED);
159 wasInterruptable = false;
161 if(hadWaiter && !masked(Monitor::INTERRUPTED))
162 pthread_cond_signal(&_waitCond);
163 else
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);
182 clear(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()))
198 clear(INTERRUPTED);
200 pthread_mutex_unlock(&_waitLock);
202 return wasCanceled;
206 bool Monitor::cancel() {
208 // Serialize access to the state
209 pthread_mutex_lock(&_waitLock);
211 bool wasInterrupted = !pending(INTERRUPTED);
212 bool hadWaiter = _waiting;
214 push(CANCELED);
216 if(wasInterrupted) {
218 // Update the state & wake the waiter if there is one
219 push(INTERRUPTED);
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);
239 if(wasNotifyable) {
241 // Set the flag and wake the waiter if there
242 // is one
243 push(SIGNALED);
245 if(_waiting)
246 pthread_cond_signal(&_waitCond);
250 pthread_mutex_unlock(&_waitLock);
252 return wasNotifyable;
256 } // namespace ZThread