wibble 1.1
mutex.h
Go to the documentation of this file.
1#ifndef WIBBLE_SYS_MUTEX_H
2#define WIBBLE_SYS_MUTEX_H
3
4/*
5 * Encapsulated pthread mutex and condition
6 *
7 * Copyright (C) 2003--2006 Enrico Zini <enrico@debian.org>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24#include <wibble/sys/macros.h>
25#include <wibble/exception.h>
26#ifdef POSIX
27#include <pthread.h>
28#endif
29
30#ifdef _WIN32
31#include <windows.h>
32#include <queue>
33#include <time.h>
34#endif
35
36#include <errno.h>
37
38namespace wibble {
39namespace sys {
40
47class Mutex
48{
49protected:
50#ifdef POSIX
51 pthread_mutex_t mutex;
52#endif
53
54#ifdef _WIN32
55 HANDLE mutex;
56 bool singlylocking;
57#endif
58
59public:
60 Mutex(bool recursive = false)
61 {
62 int res = 0;
63#ifdef POSIX
66 if ( recursive ) {
67#if (__APPLE__ || __xlC__)
69#else
71#endif
72 } else {
73#ifndef NDEBUG
75#endif
76 }
77 res = pthread_mutex_init(&mutex, &attr);
78#endif
79
80#ifdef _WIN32
81 mutex = CreateMutex( NULL, FALSE, NULL );
82 singlylocking = false;
83
84 if (mutex == NULL)
85 res = (int)GetLastError();
86#endif
87 if (res != 0)
88 throw wibble::exception::System(res, "creating pthread mutex");
89 }
90
91 Mutex( const Mutex & )
92 {
93 int res = 0;
94#ifdef POSIX
97 res = pthread_mutex_init(&mutex, &attr);
98#endif
99
100#ifdef _WIN32
101 mutex = CreateMutex(NULL, FALSE, NULL);
102 singlylocking = false;
103
104 if(mutex == NULL)
105 res = (int)GetLastError();
106#endif
107 if (res != 0)
108 throw wibble::exception::System(res, "creating pthread mutex");
109 }
110
112 {
113 int res = 0;
114#ifdef POSIX
115 res = pthread_mutex_destroy(&mutex);
116#endif
117
118#ifdef _WIN32
119 if(!CloseHandle(mutex))
120 res = (int)GetLastError();
121#endif
122 if (res != 0)
123 throw wibble::exception::System(res, "destroying pthread mutex");
124 }
125
126 bool trylock()
127 {
128 int res = 0;
129#ifdef POSIX
130 res = pthread_mutex_trylock(&mutex);
131 if ( res == EBUSY )
132 return false;
133 if ( res == 0 )
134 return true;
135#endif
136
137#ifdef _WIN32
140 return true;
142 return false;
143 res = (int)GetLastError();
144#endif
145 throw wibble::exception::System(res, "(try)locking pthread mutex");
146 }
147
150 void lock()
151 {
152 int res = 0;
153#ifdef POSIX
154 res = pthread_mutex_lock(&mutex);
155#endif
156
157#ifdef _WIN32
158 while(singlylocking)
159 Sleep(1);
161 res = (int)GetLastError();
162#endif
163 if (res != 0)
164 throw wibble::exception::System(res, "locking pthread mutex");
165 }
166
169 void unlock()
170 {
171 int res = 0;
172#ifdef POSIX
173 res = pthread_mutex_unlock(&mutex);
174#endif
175
176#ifdef _WIN32
177 if(!ReleaseMutex(mutex))
178 res = (int)GetLastError();
179#endif
180 if (res != 0)
181 throw wibble::exception::System(res, "unlocking pthread mutex");
182 }
183
185 void reinit()
186 {
187#ifdef POSIX
188 if (int res = pthread_mutex_init(&mutex, 0))
189 throw wibble::exception::System(res, "reinitialising pthread mutex");
190#endif
191 }
192
193 friend class Condition;
194};
195
199template< typename Mutex >
201{
202private:
203 // Disallow copy
204 MutexLockT(const MutexLockT&);
205 MutexLockT& operator=(const MutexLockT&);
206
207public:
209 bool locked;
210 bool yield;
211
213 mutex.lock();
214 locked = true;
215 }
216
218 if ( locked ) {
219 mutex.unlock();
220 checkYield();
221 }
222 }
223
224 void drop() {
225 mutex.unlock();
226 locked = false;
227 checkYield();
228 }
229 void reclaim() { mutex.lock(); locked = true; }
230 void setYield( bool y ) {
231 yield = y;
232 }
233
234 void checkYield() {
235
236 if ( yield )
237#ifdef POSIX
238 sched_yield();
239#elif _WIN32
240 Sleep(0);
241#else
242 ;
243#endif
244 }
245
246 friend class Condition;
247};
248
250
251/*
252 * pthread condition wrapper.
253 *
254 * It works in association with a MutexLock.
255 *
256 * WARNING: the class allows copying and assignment; see Mutex: similar caveats
257 * apply. Do not copy or assign a Condition that may be in use.
258 */
260{
261protected:
262#ifdef POSIX
264#endif
265
266#ifdef _WIN32
267 int waiters_count_; // number of waiting threads
269 HANDLE sema_; // semaphore used to queue up threads waiting for the condition
271 // An auto-reset event used by the broadcast/signal thread to wait
272 // for all the waiting thread(s) to wake up and be released from the
273 // semaphore.
274
275 bool was_broadcast_;
276 // Keeps track of whether we were broadcasting or signaling. This
277 // allows us to optimize the code if we're just signaling.
278#endif
279
280public:
282 {
283 int res = 0;
284#ifdef POSIX
285 res = pthread_cond_init(&cond, 0);
286#endif
287
288#ifdef _WIN32
289 waiters_count_ = 0;
290 was_broadcast_ = false;
291 sema_ = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
294
295 if(sema_ == NULL || waiters_done_ == NULL)
296 res = (int)GetLastError();
297#endif
298 if (res != 0)
299 throw wibble::exception::System(res, "creating pthread condition");
300 }
301
303 {
304 int res = 0;
305#ifdef POSIX
306 res = pthread_cond_init(&cond, 0);
307#endif
308
309#ifdef _WIN32
310 waiters_count_ = 0;
311 was_broadcast_ = false;
312 sema_ = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
315
316 if(sema_ == NULL || waiters_done_ == NULL)
317 res = (int)GetLastError();
318#endif
319 if (res != 0)
320 throw wibble::exception::System(res, "creating pthread condition");
321 }
322
324 {
325 int res = 0;
326#ifdef POSIX
328#endif
329
330#ifdef _WIN32
333 res = (int)GetLastError();
334#endif
335 if (res != 0)
336 throw wibble::exception::System(res, "destroying pthread condition");
337 }
338
340 void signal()
341 {
342 int res = 0;
343#ifdef POSIX
345#endif
346
347#ifdef _WIN32
349 bool have_waiters = waiters_count_ > 0;
351
352 // if there aren't any waiters, then this is a no-op
353 if(have_waiters && !ReleaseSemaphore(sema_, 1, 0))
354 res = (int)GetLastError();
355#endif
356 if (res != 0)
357 throw wibble::exception::System(res, "signaling on a pthread condition");
358 }
359
362 {
363 int res = 0;
364#ifdef POSIX
366#endif
367
368#ifdef _WIN32
369 for(bool once = true; once; once = false)
370 {
372 bool have_waiters = false;
373
374 if(waiters_count_ > 0) {
375 was_broadcast_ = true;
376 have_waiters = true;
377 }
378
379 if(have_waiters) {
381 res = (int)GetLastError();
382 break;
383 }
386 res = (int)GetLastError();
387 break;
388 }
389 was_broadcast_ = false;
390 }
391 else
393 }
394#endif
395 if (res != 0)
396 throw wibble::exception::System(res, "broadcasting on a pthread condition");
397 }
398
404 {
405 int res = 0;
406#ifdef POSIX
407 res = pthread_cond_wait(&cond, &l.mutex.mutex);
408#endif
409
410#ifdef _WIN32
411 for(bool once = true; once; once = false)
412 {
416
417 if(SignalObjectAndWait(l.mutex.mutex, sema_, INFINITE, FALSE) != WAIT_OBJECT_0) {
418 res = (int)GetLastError();
419 break;
420 }
421
426
427 if (last_waiter) {
429 {
430 res = (int)GetLastError();
431 break;
432 }
433 }
434 else {
435 if(WaitForSingleObject (l.mutex.mutex, INFINITE) != WAIT_OBJECT_0)
436 {
437 res = (int)GetLastError();
438 break;
439 }
440 }
441 }
442#endif
443 if (res != 0)
444 throw wibble::exception::System(res, "waiting on a pthread condition");
445 }
446
447 void wait(Mutex& l)
448 {
449 int res = 0;
450#ifdef POSIX
451 res = pthread_cond_wait(&cond, &l.mutex);
452#endif
453
454#ifdef _WIN32
455 for(bool once = true; once; once = false)
456 {
457 if(WaitForSingleObject(l.mutex, 0) == WAIT_OBJECT_0) {
458 l.singlylocking = true;
459 while(ReleaseMutex(l.mutex)) ;
460 if ((res = ((int)GetLastError() != 288))) //288 -> MUTEX_NOT_OWNED
461 break;
462 }
464 res = (int)GetLastError();
465 break;
466 }
467 l.singlylocking = false;
468
472
474 res = (int)GetLastError();
475 break;
476 }
477
482
483 if(last_waiter) {
485 res = (int)GetLastError();
486 break;
487 }
488 }
489 else {
491 res = (int)GetLastError();
492 break;
493 }
494 }
495 }
496#endif
497 if (res != 0)
498 throw wibble::exception::System(res, "waiting on a pthread condition");
499 }
500
501#ifdef POSIX
512 bool wait(MutexLock& l, const struct timespec& abstime);
513#endif
514};
515
516}
517}
518
519// vim:set ts=4 sw=4:
520#endif
Base class for system exceptions.
Definition exception.h:397
Definition mutex.h:260
void broadcast()
Wake up all processes waiting on the condition.
Definition mutex.h:361
Condition(const Condition &)
Definition mutex.h:302
void wait(Mutex &l)
Definition mutex.h:447
void signal()
Wake up one process waiting on the condition.
Definition mutex.h:340
Condition()
Definition mutex.h:281
~Condition()
Definition mutex.h:323
void wait(MutexLock &l)
Wait on the condition, locking with l.
Definition mutex.h:403
Acquire a mutex lock, RAII-style.
Definition mutex.h:201
MutexLockT(Mutex &m)
Definition mutex.h:212
void reclaim()
Definition mutex.h:229
Mutex & mutex
Definition mutex.h:208
void checkYield()
Definition mutex.h:234
bool yield
Definition mutex.h:210
bool locked
Definition mutex.h:209
void setYield(bool y)
Definition mutex.h:230
~MutexLockT()
Definition mutex.h:217
void drop()
Definition mutex.h:224
pthread mutex wrapper; WARNING: the class allows copying and assignment, but this is not always safe.
Definition mutex.h:48
~Mutex()
Definition mutex.h:111
Mutex(bool recursive=false)
Definition mutex.h:60
void lock()
Lock the mutex Normally it's better to use MutexLock.
Definition mutex.h:150
bool trylock()
Definition mutex.h:126
void unlock()
Unlock the mutex Normally it's better to use MutexLock.
Definition mutex.h:169
Mutex(const Mutex &)
Definition mutex.h:91
void reinit()
Reinitialize the mutex.
Definition mutex.h:185
MutexLockT< Mutex > MutexLock
Definition mutex.h:249
Definition amorph.h:17
Definition amorph.h:30