1 karl 1.3 //%2006////////////////////////////////////////////////////////////////////////
|
2 mike 1.2 //
3 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
6 // IBM Corp.; EMC Corporation, The Open Group.
7 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
9 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
|
11 karl 1.3 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
12 // EMC Corporation; Symantec Corporation; The Open Group.
|
13 mike 1.2 //
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
15 // of this software and associated documentation files (the "Software"), to
16 // deal in the Software without restriction, including without limitation the
17 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
18 // sell copies of the Software, and to permit persons to whom the Software is
19 // furnished to do so, subject to the following conditions:
|
20 karl 1.3 //
|
21 mike 1.2 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
22 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
23 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
24 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
25 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
27 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 //==============================================================================
31 //
32 //%/////////////////////////////////////////////////////////////////////////////
33
34 #include "Mutex.h"
|
35 mike 1.4 #include "Time.h"
36 #include "PegasusAssert.h"
37 #include "Once.h"
|
38 mike 1.2
39 PEGASUS_NAMESPACE_BEGIN
40
|
41 mike 1.4 //==============================================================================
42 //
|
43 mike 1.9.16.1 // Mutex implementation with PTHREAD_MUTEX_RECURSIVE feature.
|
44 mike 1.4 //
45 //==============================================================================
46
|
47 mike 1.9.16.1 #if defined(PEGASUS_HAVE_PTHREADS) && defined(PEGASUS_HAVE_RECURSIVE_MUTEXES)
|
48 mike 1.4
49 static Once _once = PEGASUS_ONCE_INITIALIZER;
50 static pthread_mutexattr_t _attr;
51
52 static void _init_attr()
53 {
54 pthread_mutexattr_init(&_attr);
55 pthread_mutexattr_settype(&_attr, PTHREAD_MUTEX_RECURSIVE);
56 }
57
58 Mutex::Mutex()
59 {
60 once(&_once, _init_attr);
61 pthread_mutex_init(&_rep.mutex, &_attr);
62 #if defined(PEGASUS_DEBUG)
63 _rep.count = 0;
64 #endif
65 }
66
|
67 mike 1.6 Mutex::Mutex(RecursiveTag)
68 {
69 once(&_once, _init_attr);
70 pthread_mutex_init(&_rep.mutex, &_attr);
71 #if defined(PEGASUS_DEBUG)
72 _rep.count = 0;
73 #endif
74 }
75
76 Mutex::Mutex(NonRecursiveTag)
77 {
78 pthread_mutex_init(&_rep.mutex, NULL);
79 #if defined(PEGASUS_DEBUG)
80 _rep.count = 0;
81 #endif
82 }
83
|
84 mike 1.4 Mutex::~Mutex()
85 {
86 PEGASUS_DEBUG_ASSERT(_magic);
87 pthread_mutex_destroy(&_rep.mutex);
88 }
89
90 void Mutex::lock()
91 {
92 PEGASUS_DEBUG_ASSERT(_magic);
93
94 switch (pthread_mutex_lock(&_rep.mutex))
95 {
96 case 0:
97 #if defined(PEGASUS_DEBUG)
98 _rep.count++;
99 #endif
100 break;
101
102 default:
103 throw WaitFailed(Threads::self());
104 }
105 mike 1.4 }
106
107 void Mutex::try_lock()
108 {
109 PEGASUS_DEBUG_ASSERT(_magic);
110
|
111 marek 1.5 int r = pthread_mutex_trylock(&_rep.mutex);
112 if (r == -1)
113 r=errno;
114 switch (r)
|
115 mike 1.4 {
116 case 0:
117 #if defined(PEGASUS_DEBUG)
118 _rep.count++;
119 #endif
120 break;
121
122 case EBUSY:
123 throw AlreadyLocked(Threads::self());
124
125 default:
126 throw WaitFailed(Threads::self());
127 }
128 }
129
130 void Mutex::timed_lock(Uint32 milliseconds)
131 {
132 PEGASUS_DEBUG_ASSERT(_magic);
133
134 struct timeval now;
135 struct timeval finish;
136 mike 1.4 struct timeval remaining;
137 {
138 Uint32 usec;
139 gettimeofday(&finish, NULL);
140 finish.tv_sec += (milliseconds / 1000 );
141 milliseconds %= 1000;
142 usec = finish.tv_usec + ( milliseconds * 1000 );
143 finish.tv_sec += (usec / 1000000);
144 finish.tv_usec = usec % 1000000;
145 }
146
147 for (;;)
148 {
|
149 marek 1.5 int r=pthread_mutex_trylock(&_rep.mutex);
150 if (r == -1)
151 r = errno;
152 switch (r)
|
153 mike 1.4 {
154 case 0:
155 #if defined(PEGASUS_DEBUG)
156 _rep.count++;
157 #endif
158 return;
159
160 case EBUSY:
161 {
162 gettimeofday(&now, NULL);
163
164 if (Time::subtract(&remaining, &finish, &now))
165 throw TimeOut(Threads::self());
166
167 Threads::yield();
168 break;
169 }
170
171 default:
172 throw WaitFailed(Threads::self());
173 }
174 mike 1.4 }
175 }
176
177 void Mutex::unlock()
178 {
179 PEGASUS_DEBUG_ASSERT(_magic);
180 PEGASUS_DEBUG_ASSERT(_rep.count > 0);
181
182 #if defined(PEGASUS_DEBUG)
183 _rep.count--;
184 #endif
185
186 if (pthread_mutex_unlock(&_rep.mutex) != 0)
187 throw Permission(Threads::self());
188 }
189
|
190 kumpf 1.8 #if defined(PEGASUS_OS_LINUX)
191 void Mutex::reinitialize()
192 {
193 pthread_mutex_init(&_rep.mutex, &_attr);
194 #if defined(PEGASUS_DEBUG)
195 _rep.count = 0;
196 #endif
197 }
198 #endif
199
|
200 mike 1.9.16.1 #endif /* PEGASUS_HAVE_PTHREADS && PEGASUS_HAVE_RECURSIVE_MUTEXES */
201
202 //==============================================================================
203 //
204 // Mutex implementation without PTHREAD_MUTEX_RECURSIVE feature.
205 //
206 //==============================================================================
207
208 #if defined(PEGASUS_HAVE_PTHREADS) && !defined(PEGASUS_HAVE_RECURSIVE_MUTEXES)
209
210 Mutex::Mutex()
211 {
212 pthread_mutex_init(&_rep.mutex, NULL);
213 pthread_cond_init(&_rep.cond, NULL);
214 _rep.owner = 0;
215 _rep.count = 0;
216 }
217
218 Mutex::Mutex(RecursiveTag)
219 {
|
220 mike 1.9.16.2 _rep.recursive = 1;
|
221 mike 1.9.16.1 pthread_mutex_init(&_rep.mutex, NULL);
222 pthread_cond_init(&_rep.cond, NULL);
223 _rep.owner = 0;
224 _rep.count = 0;
225 }
226
227 Mutex::Mutex(NonRecursiveTag)
228 {
|
229 mike 1.9.16.2 _rep.recursive = 0;
|
230 mike 1.9.16.1 pthread_mutex_init(&_rep.mutex, NULL);
231 }
232
233 Mutex::~Mutex()
234 {
235 PEGASUS_DEBUG_ASSERT(_magic);
236 pthread_mutex_destroy(&_rep.mutex);
|
237 mike 1.9.16.2
238 if (_rep.recursive)
239 pthread_cond_destroy(&_rep.cond);
|
240 mike 1.9.16.1 }
241
242 void Mutex::lock()
243 {
244 PEGASUS_DEBUG_ASSERT(_magic);
245
|
246 mike 1.9.16.2 if (_rep.recursive)
|
247 mike 1.9.16.1 {
|
248 mike 1.9.16.2 pthread_t self = pthread_self();
249
250 pthread_mutex_lock(&_rep.mutex);
|
251 mike 1.9.16.1 {
|
252 mike 1.9.16.2 if (_rep.count == 0)
253 {
254 _rep.owner = self;
255 }
256 else if (!pthread_equal(_rep.owner, self))
257 {
258 while (_rep.count > 0)
259 pthread_cond_wait(&_rep.cond, &_rep.mutex);
260
261 _rep.owner = self;
262 }
263
264 _rep.count++;
|
265 mike 1.9.16.1 }
|
266 mike 1.9.16.2 pthread_mutex_unlock(&_rep.mutex);
267 }
268 else
269 {
270 if (pthread_mutex_lock(&_rep.mutex) != 0)
|
271 mike 1.9.16.1 {
|
272 mike 1.9.16.2 throw WaitFailed(Threads::self());
|
273 mike 1.9.16.1 }
274 }
275 }
276
277 void Mutex::try_lock()
278 {
279 PEGASUS_DEBUG_ASSERT(_magic);
280
|
281 mike 1.9.16.2 if (_rep.recursive)
|
282 mike 1.9.16.1 {
|
283 mike 1.9.16.2 pthread_t self = pthread_self();
284
285 pthread_mutex_lock(&_rep.mutex);
|
286 mike 1.9.16.1 {
|
287 mike 1.9.16.2 if (_rep.count == 0)
288 {
289 _rep.owner = self;
290 _rep.count = 1;
291 }
292 else if (pthread_equal(_rep.owner, self))
293 {
294 _rep.count++;
295 }
296 else
297 {
298 pthread_mutex_unlock(&_rep.mutex);
299 throw AlreadyLocked(Threads::self());
300 }
|
301 mike 1.9.16.1 }
|
302 mike 1.9.16.2 pthread_mutex_unlock(&_rep.mutex);
303 }
304 else
305 {
306 int r = pthread_mutex_trylock(&_rep.mutex);
307
308 if (r == -1)
309 r = errno;
310
311 switch (r)
|
312 mike 1.9.16.1 {
|
313 mike 1.9.16.2 case 0:
314 break;
315
316 case EBUSY:
317 throw AlreadyLocked(Threads::self());
318
319 default:
320 throw WaitFailed(Threads::self());
|
321 mike 1.9.16.1 }
322 }
323 }
324
325 void Mutex::timed_lock(Uint32 milliseconds)
326 {
327 PEGASUS_DEBUG_ASSERT(_magic);
328
|
329 mike 1.9.16.2 if (_rep.recursive)
330 {
331 pthread_t self = pthread_self();
332
333 pthread_mutex_lock(&_rep.mutex);
334 {
335 if (_rep.count == 0)
336 {
337 _rep.owner = self;
338 }
339 else if (!pthread_equal(_rep.owner, self))
340 {
341 timespec ts;
342 clock_gettime(CLOCK_REALTIME, &ts);
343
344 ts.tv_sec += milliseconds / 1000;
345 ts.tv_nsec += (milliseconds % 1000) * 1000000;
346
347 while (_rep.count > 0)
348 {
349 if (pthread_cond_timedwait(
350 mike 1.9.16.2 &_rep.cond, &_rep.mutex, &ts) != 0)
351 {
352 pthread_mutex_unlock(&_rep.mutex);
353 throw TimeOut(Threads::self());
354 }
355 }
356
357 _rep.owner = self;
358 }
359
360 _rep.count++;
361 }
362 pthread_mutex_unlock(&_rep.mutex);
363 }
364 else
|
365 mike 1.9.16.1 {
|
366 mike 1.9.16.2 struct timeval now;
367 struct timeval finish;
368 struct timeval remaining;
|
369 mike 1.9.16.1 {
|
370 mike 1.9.16.2 Uint32 usec;
371 gettimeofday(&finish, NULL);
372 finish.tv_sec += (milliseconds / 1000 );
373 milliseconds %= 1000;
374 usec = finish.tv_usec + ( milliseconds * 1000 );
375 finish.tv_sec += (usec / 1000000);
376 finish.tv_usec = usec % 1000000;
|
377 mike 1.9.16.1 }
|
378 mike 1.9.16.2
379 for (;;)
|
380 mike 1.9.16.1 {
|
381 mike 1.9.16.2 int r = pthread_mutex_trylock(&_rep.mutex);
|
382 mike 1.9.16.1
|
383 mike 1.9.16.2 if (r == -1)
384 r = errno;
|
385 mike 1.9.16.1
|
386 mike 1.9.16.2 switch (r)
|
387 mike 1.9.16.1 {
|
388 mike 1.9.16.2 case 0:
389 return;
390
391 case EBUSY:
|
392 mike 1.9.16.1 {
|
393 mike 1.9.16.2 gettimeofday(&now, NULL);
394
395 if (Time::subtract(&remaining, &finish, &now))
396 throw TimeOut(Threads::self());
397
398 Threads::yield();
399 break;
|
400 mike 1.9.16.1 }
401
|
402 mike 1.9.16.2 default:
403 throw WaitFailed(Threads::self());
404 }
|
405 mike 1.9.16.1 }
406 }
407 }
408
409 void Mutex::unlock()
410 {
411 PEGASUS_DEBUG_ASSERT(_magic);
412
|
413 mike 1.9.16.2 if (_rep.recursive)
|
414 mike 1.9.16.1 {
|
415 mike 1.9.16.2 pthread_t self = pthread_self();
416
417 pthread_mutex_lock(&_rep.mutex);
418 {
419 // If not locked or if calling thread is not the locker.
|
420 mike 1.9.16.1
|
421 mike 1.9.16.2 if (_rep.count == 0 || !pthread_equal(_rep.owner, self))
422 PEGASUS_DEBUG_ASSERT(0);
|
423 mike 1.9.16.1
|
424 mike 1.9.16.2 _rep.count--;
425 _rep.owner = 0;
426 pthread_cond_signal(&_rep.cond);
427 }
428 pthread_mutex_unlock(&_rep.mutex);
429 }
430 else
431 {
432 if (pthread_mutex_unlock(&_rep.mutex) != 0)
433 throw Permission(Threads::self());
|
434 mike 1.9.16.1 }
435 }
436
437 #endif /* PEGASUS_HAVE_PTHREADS && !PEGASUS_HAVE_RECURSIVE_MUTEXES */
|
438 mike 1.4
439 //==============================================================================
440 //
441 // PEGASUS_HAVE_WINDOWS_THREADS
442 //
443 //==============================================================================
444
445 #if defined(PEGASUS_HAVE_WINDOWS_THREADS)
446
|
447 mike 1.7 static inline void _initialize(MutexRep& rep)
448 {
449 rep.handle = CreateMutex(NULL, FALSE, NULL);
450 rep.count = 0;
451 }
452
|
453 mike 1.4 Mutex::Mutex()
454 {
|
455 mike 1.7 _initialize(_rep);
456 }
457
|
458 mike 1.6 Mutex::Mutex(RecursiveTag)
459 {
|
460 mike 1.7 _initialize(_rep);
|
461 mike 1.6 }
462
463 Mutex::Mutex(NonRecursiveTag)
464 {
|
465 mike 1.7 _initialize(_rep);
|
466 mike 1.4 }
467
468 Mutex::~Mutex()
469 {
470 PEGASUS_DEBUG_ASSERT(_magic);
471
472 WaitForSingleObject(_rep.handle, INFINITE);
473 CloseHandle(_rep.handle);
474 }
475
476 void Mutex::lock()
477 {
478 PEGASUS_DEBUG_ASSERT(_magic);
479
480 DWORD rc = WaitForSingleObject(_rep.handle, INFINITE);
481
482 if (rc == WAIT_FAILED)
483 throw WaitFailed(Threads::self());
484
485 _rep.count++;
486 }
487 mike 1.4
488 void Mutex::try_lock()
489 {
490 PEGASUS_DEBUG_ASSERT(_magic);
491
492 DWORD rc = WaitForSingleObject(_rep.handle, 0);
493
494 if (rc == WAIT_TIMEOUT)
495 throw AlreadyLocked(Threads::self());
496
497 if (rc == WAIT_FAILED)
498 throw WaitFailed(Threads::self());
499
500 _rep.count++;
501 }
502
503 void Mutex::timed_lock(Uint32 milliseconds)
504 {
505 PEGASUS_DEBUG_ASSERT(_magic);
506
507 DWORD rc = WaitForSingleObject(_rep.handle, milliseconds);
508 mike 1.4
509 if (rc == WAIT_TIMEOUT)
510 throw TimeOut(Threads::self());
511
512 if (rc == WAIT_FAILED)
513 throw WaitFailed(Threads::self());
514
515 _rep.count++;
516 }
517
518 void Mutex::unlock()
519 {
520 PEGASUS_DEBUG_ASSERT(_magic);
521 PEGASUS_DEBUG_ASSERT(_rep.count > 0);
522
523 _rep.count--;
524 ReleaseMutex(_rep.handle);
525 }
526
527 #endif /* PEGASUS_HAVE_WINDOWS_THREADS */
528
|
529 mike 1.2 PEGASUS_NAMESPACE_END
|