Mercurial > trustbridge > nss-cmake-static
comparison nspr/pr/src/pthreads/ptsynch.c @ 0:1e5118fa0cb1
This is NSS with a Cmake Buildsyste
To compile a static NSS library for Windows we've used the
Chromium-NSS fork and added a Cmake buildsystem to compile
it statically for Windows. See README.chromium for chromium
changes and README.trustbridge for our modifications.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 28 Jul 2014 10:47:06 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1e5118fa0cb1 |
---|---|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | |
2 /* This Source Code Form is subject to the terms of the Mozilla Public | |
3 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
5 | |
6 /* | |
7 ** File: ptsynch.c | |
8 ** Descritpion: Implemenation for thread synchronization using pthreads | |
9 ** Exports: prlock.h, prcvar.h, prmon.h, prcmon.h | |
10 */ | |
11 | |
12 #if defined(_PR_PTHREADS) | |
13 | |
14 #include "primpl.h" | |
15 #include "obsolete/prsem.h" | |
16 | |
17 #include <string.h> | |
18 #include <pthread.h> | |
19 #include <sys/time.h> | |
20 | |
21 static pthread_mutexattr_t _pt_mattr; | |
22 static pthread_condattr_t _pt_cvar_attr; | |
23 | |
24 #if defined(DEBUG) | |
25 extern PTDebug pt_debug; /* this is shared between several modules */ | |
26 | |
27 #if defined(_PR_DCETHREADS) | |
28 static pthread_t pt_zero_tid; /* a null pthread_t (pthread_t is a struct | |
29 * in DCE threads) to compare with */ | |
30 #endif /* defined(_PR_DCETHREADS) */ | |
31 #endif /* defined(DEBUG) */ | |
32 | |
33 #if defined(FREEBSD) | |
34 /* | |
35 * On older versions of FreeBSD, pthread_mutex_trylock returns EDEADLK. | |
36 * Newer versions return EBUSY. We still need to support both. | |
37 */ | |
38 static int | |
39 pt_pthread_mutex_is_locked(pthread_mutex_t *m) | |
40 { | |
41 int rv = pthread_mutex_trylock(m); | |
42 return (EBUSY == rv || EDEADLK == rv); | |
43 } | |
44 #endif | |
45 | |
46 /**************************************************************/ | |
47 /**************************************************************/ | |
48 /*****************************LOCKS****************************/ | |
49 /**************************************************************/ | |
50 /**************************************************************/ | |
51 | |
52 void _PR_InitLocks(void) | |
53 { | |
54 int rv; | |
55 rv = _PT_PTHREAD_MUTEXATTR_INIT(&_pt_mattr); | |
56 PR_ASSERT(0 == rv); | |
57 | |
58 #ifdef LINUX | |
59 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) | |
60 rv = pthread_mutexattr_settype(&_pt_mattr, PTHREAD_MUTEX_ADAPTIVE_NP); | |
61 PR_ASSERT(0 == rv); | |
62 #endif | |
63 #endif | |
64 | |
65 rv = _PT_PTHREAD_CONDATTR_INIT(&_pt_cvar_attr); | |
66 PR_ASSERT(0 == rv); | |
67 } | |
68 | |
69 static void pt_PostNotifies(PRLock *lock, PRBool unlock) | |
70 { | |
71 PRIntn index, rv; | |
72 _PT_Notified post; | |
73 _PT_Notified *notified, *prev = NULL; | |
74 /* | |
75 * Time to actually notify any conditions that were affected | |
76 * while the lock was held. Get a copy of the list that's in | |
77 * the lock structure and then zero the original. If it's | |
78 * linked to other such structures, we own that storage. | |
79 */ | |
80 post = lock->notified; /* a safe copy; we own the lock */ | |
81 | |
82 #if defined(DEBUG) | |
83 memset(&lock->notified, 0, sizeof(_PT_Notified)); /* reset */ | |
84 #else | |
85 lock->notified.length = 0; /* these are really sufficient */ | |
86 lock->notified.link = NULL; | |
87 #endif | |
88 | |
89 /* should (may) we release lock before notifying? */ | |
90 if (unlock) | |
91 { | |
92 rv = pthread_mutex_unlock(&lock->mutex); | |
93 PR_ASSERT(0 == rv); | |
94 } | |
95 | |
96 notified = &post; /* this is where we start */ | |
97 do | |
98 { | |
99 for (index = 0; index < notified->length; ++index) | |
100 { | |
101 PRCondVar *cv = notified->cv[index].cv; | |
102 PR_ASSERT(NULL != cv); | |
103 PR_ASSERT(0 != notified->cv[index].times); | |
104 if (-1 == notified->cv[index].times) | |
105 { | |
106 rv = pthread_cond_broadcast(&cv->cv); | |
107 PR_ASSERT(0 == rv); | |
108 } | |
109 else | |
110 { | |
111 while (notified->cv[index].times-- > 0) | |
112 { | |
113 rv = pthread_cond_signal(&cv->cv); | |
114 PR_ASSERT(0 == rv); | |
115 } | |
116 } | |
117 #if defined(DEBUG) | |
118 pt_debug.cvars_notified += 1; | |
119 if (0 > PR_ATOMIC_DECREMENT(&cv->notify_pending)) | |
120 { | |
121 pt_debug.delayed_cv_deletes += 1; | |
122 PR_DestroyCondVar(cv); | |
123 } | |
124 #else /* defined(DEBUG) */ | |
125 if (0 > PR_ATOMIC_DECREMENT(&cv->notify_pending)) | |
126 PR_DestroyCondVar(cv); | |
127 #endif /* defined(DEBUG) */ | |
128 } | |
129 prev = notified; | |
130 notified = notified->link; | |
131 if (&post != prev) PR_DELETE(prev); | |
132 } while (NULL != notified); | |
133 } /* pt_PostNotifies */ | |
134 | |
135 PR_IMPLEMENT(PRLock*) PR_NewLock(void) | |
136 { | |
137 PRIntn rv; | |
138 PRLock *lock; | |
139 | |
140 if (!_pr_initialized) _PR_ImplicitInitialization(); | |
141 | |
142 lock = PR_NEWZAP(PRLock); | |
143 if (lock != NULL) | |
144 { | |
145 rv = _PT_PTHREAD_MUTEX_INIT(lock->mutex, _pt_mattr); | |
146 PR_ASSERT(0 == rv); | |
147 } | |
148 #if defined(DEBUG) | |
149 pt_debug.locks_created += 1; | |
150 #endif | |
151 return lock; | |
152 } /* PR_NewLock */ | |
153 | |
154 PR_IMPLEMENT(void) PR_DestroyLock(PRLock *lock) | |
155 { | |
156 PRIntn rv; | |
157 PR_ASSERT(NULL != lock); | |
158 PR_ASSERT(PR_FALSE == lock->locked); | |
159 PR_ASSERT(0 == lock->notified.length); | |
160 PR_ASSERT(NULL == lock->notified.link); | |
161 rv = pthread_mutex_destroy(&lock->mutex); | |
162 PR_ASSERT(0 == rv); | |
163 #if defined(DEBUG) | |
164 memset(lock, 0xaf, sizeof(PRLock)); | |
165 pt_debug.locks_destroyed += 1; | |
166 #endif | |
167 PR_Free(lock); | |
168 } /* PR_DestroyLock */ | |
169 | |
170 PR_IMPLEMENT(void) PR_Lock(PRLock *lock) | |
171 { | |
172 /* Nb: PR_Lock must not call PR_GetCurrentThread to access the |id| or | |
173 * |tid| field of the current thread's PRThread structure because | |
174 * _pt_root calls PR_Lock before setting thred->id and thred->tid. */ | |
175 PRIntn rv; | |
176 PR_ASSERT(lock != NULL); | |
177 rv = pthread_mutex_lock(&lock->mutex); | |
178 PR_ASSERT(0 == rv); | |
179 PR_ASSERT(0 == lock->notified.length); | |
180 PR_ASSERT(NULL == lock->notified.link); | |
181 PR_ASSERT(PR_FALSE == lock->locked); | |
182 /* Nb: the order of the next two statements is not critical to | |
183 * the correctness of PR_AssertCurrentThreadOwnsLock(), but | |
184 * this particular order makes the assertion more likely to | |
185 * catch errors. */ | |
186 lock->owner = pthread_self(); | |
187 lock->locked = PR_TRUE; | |
188 #if defined(DEBUG) | |
189 pt_debug.locks_acquired += 1; | |
190 #endif | |
191 } /* PR_Lock */ | |
192 | |
193 PR_IMPLEMENT(PRStatus) PR_Unlock(PRLock *lock) | |
194 { | |
195 pthread_t self = pthread_self(); | |
196 PRIntn rv; | |
197 | |
198 PR_ASSERT(lock != NULL); | |
199 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(lock->mutex)); | |
200 PR_ASSERT(PR_TRUE == lock->locked); | |
201 PR_ASSERT(pthread_equal(lock->owner, self)); | |
202 | |
203 if (!lock->locked || !pthread_equal(lock->owner, self)) | |
204 return PR_FAILURE; | |
205 | |
206 lock->locked = PR_FALSE; | |
207 if (0 == lock->notified.length) /* shortcut */ | |
208 { | |
209 rv = pthread_mutex_unlock(&lock->mutex); | |
210 PR_ASSERT(0 == rv); | |
211 } | |
212 else pt_PostNotifies(lock, PR_TRUE); | |
213 | |
214 #if defined(DEBUG) | |
215 pt_debug.locks_released += 1; | |
216 #endif | |
217 return PR_SUCCESS; | |
218 } /* PR_Unlock */ | |
219 | |
220 PR_IMPLEMENT(void) PR_AssertCurrentThreadOwnsLock(PRLock *lock) | |
221 { | |
222 /* Nb: the order of the |locked| and |owner==me| checks is not critical | |
223 * to the correctness of PR_AssertCurrentThreadOwnsLock(), but | |
224 * this particular order makes the assertion more likely to | |
225 * catch errors. */ | |
226 PR_ASSERT(lock->locked && pthread_equal(lock->owner, pthread_self())); | |
227 } | |
228 | |
229 /**************************************************************/ | |
230 /**************************************************************/ | |
231 /***************************CONDITIONS*************************/ | |
232 /**************************************************************/ | |
233 /**************************************************************/ | |
234 | |
235 | |
236 /* | |
237 * This code is used to compute the absolute time for the wakeup. | |
238 * It's moderately ugly, so it's defined here and called in a | |
239 * couple of places. | |
240 */ | |
241 #define PT_NANOPERMICRO 1000UL | |
242 #define PT_BILLION 1000000000UL | |
243 | |
244 static PRIntn pt_TimedWait( | |
245 pthread_cond_t *cv, pthread_mutex_t *ml, PRIntervalTime timeout) | |
246 { | |
247 int rv; | |
248 struct timeval now; | |
249 struct timespec tmo; | |
250 PRUint32 ticks = PR_TicksPerSecond(); | |
251 | |
252 tmo.tv_sec = (PRInt32)(timeout / ticks); | |
253 tmo.tv_nsec = (PRInt32)(timeout - (tmo.tv_sec * ticks)); | |
254 tmo.tv_nsec = (PRInt32)PR_IntervalToMicroseconds(PT_NANOPERMICRO * tmo.tv_nsec); | |
255 | |
256 /* pthreads wants this in absolute time, off we go ... */ | |
257 (void)GETTIMEOFDAY(&now); | |
258 /* that one's usecs, this one's nsecs - grrrr! */ | |
259 tmo.tv_sec += now.tv_sec; | |
260 tmo.tv_nsec += (PT_NANOPERMICRO * now.tv_usec); | |
261 tmo.tv_sec += tmo.tv_nsec / PT_BILLION; | |
262 tmo.tv_nsec %= PT_BILLION; | |
263 | |
264 rv = pthread_cond_timedwait(cv, ml, &tmo); | |
265 | |
266 /* NSPR doesn't report timeouts */ | |
267 #ifdef _PR_DCETHREADS | |
268 if (rv == -1) return (errno == EAGAIN) ? 0 : errno; | |
269 else return rv; | |
270 #else | |
271 return (rv == ETIMEDOUT) ? 0 : rv; | |
272 #endif | |
273 } /* pt_TimedWait */ | |
274 | |
275 | |
276 /* | |
277 * Notifies just get posted to the protecting mutex. The | |
278 * actual notification is done when the lock is released so that | |
279 * MP systems don't contend for a lock that they can't have. | |
280 */ | |
281 static void pt_PostNotifyToCvar(PRCondVar *cvar, PRBool broadcast) | |
282 { | |
283 PRIntn index = 0; | |
284 _PT_Notified *notified = &cvar->lock->notified; | |
285 | |
286 PR_ASSERT(PR_TRUE == cvar->lock->locked); | |
287 PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self())); | |
288 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex)); | |
289 | |
290 while (1) | |
291 { | |
292 for (index = 0; index < notified->length; ++index) | |
293 { | |
294 if (notified->cv[index].cv == cvar) | |
295 { | |
296 if (broadcast) | |
297 notified->cv[index].times = -1; | |
298 else if (-1 != notified->cv[index].times) | |
299 notified->cv[index].times += 1; | |
300 return; /* we're finished */ | |
301 } | |
302 } | |
303 /* if not full, enter new CV in this array */ | |
304 if (notified->length < PT_CV_NOTIFIED_LENGTH) break; | |
305 | |
306 /* if there's no link, create an empty array and link it */ | |
307 if (NULL == notified->link) | |
308 notified->link = PR_NEWZAP(_PT_Notified); | |
309 notified = notified->link; | |
310 } | |
311 | |
312 /* A brand new entry in the array */ | |
313 (void)PR_ATOMIC_INCREMENT(&cvar->notify_pending); | |
314 notified->cv[index].times = (broadcast) ? -1 : 1; | |
315 notified->cv[index].cv = cvar; | |
316 notified->length += 1; | |
317 } /* pt_PostNotifyToCvar */ | |
318 | |
319 PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock *lock) | |
320 { | |
321 PRCondVar *cv = PR_NEW(PRCondVar); | |
322 PR_ASSERT(lock != NULL); | |
323 if (cv != NULL) | |
324 { | |
325 int rv = _PT_PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr); | |
326 PR_ASSERT(0 == rv); | |
327 cv->lock = lock; | |
328 cv->notify_pending = 0; | |
329 #if defined(DEBUG) | |
330 pt_debug.cvars_created += 1; | |
331 #endif | |
332 } | |
333 return cv; | |
334 } /* PR_NewCondVar */ | |
335 | |
336 PR_IMPLEMENT(void) PR_DestroyCondVar(PRCondVar *cvar) | |
337 { | |
338 if (0 > PR_ATOMIC_DECREMENT(&cvar->notify_pending)) | |
339 { | |
340 PRIntn rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv); | |
341 #if defined(DEBUG) | |
342 memset(cvar, 0xaf, sizeof(PRCondVar)); | |
343 pt_debug.cvars_destroyed += 1; | |
344 #endif | |
345 PR_Free(cvar); | |
346 } | |
347 } /* PR_DestroyCondVar */ | |
348 | |
349 PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout) | |
350 { | |
351 PRIntn rv; | |
352 PRThread *thred = PR_GetCurrentThread(); | |
353 | |
354 PR_ASSERT(cvar != NULL); | |
355 /* We'd better be locked */ | |
356 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex)); | |
357 PR_ASSERT(PR_TRUE == cvar->lock->locked); | |
358 /* and it better be by us */ | |
359 PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self())); | |
360 | |
361 if (_PT_THREAD_INTERRUPTED(thred)) goto aborted; | |
362 | |
363 /* | |
364 * The thread waiting is used for PR_Interrupt | |
365 */ | |
366 thred->waiting = cvar; /* this is where we're waiting */ | |
367 | |
368 /* | |
369 * If we have pending notifies, post them now. | |
370 * | |
371 * This is not optimal. We're going to post these notifies | |
372 * while we're holding the lock. That means on MP systems | |
373 * that they are going to collide for the lock that we will | |
374 * hold until we actually wait. | |
375 */ | |
376 if (0 != cvar->lock->notified.length) | |
377 pt_PostNotifies(cvar->lock, PR_FALSE); | |
378 | |
379 /* | |
380 * We're surrendering the lock, so clear out the locked field. | |
381 */ | |
382 cvar->lock->locked = PR_FALSE; | |
383 | |
384 if (timeout == PR_INTERVAL_NO_TIMEOUT) | |
385 rv = pthread_cond_wait(&cvar->cv, &cvar->lock->mutex); | |
386 else | |
387 rv = pt_TimedWait(&cvar->cv, &cvar->lock->mutex, timeout); | |
388 | |
389 /* We just got the lock back - this better be empty */ | |
390 PR_ASSERT(PR_FALSE == cvar->lock->locked); | |
391 cvar->lock->locked = PR_TRUE; | |
392 cvar->lock->owner = pthread_self(); | |
393 | |
394 PR_ASSERT(0 == cvar->lock->notified.length); | |
395 thred->waiting = NULL; /* and now we're not */ | |
396 if (_PT_THREAD_INTERRUPTED(thred)) goto aborted; | |
397 if (rv != 0) | |
398 { | |
399 _PR_MD_MAP_DEFAULT_ERROR(rv); | |
400 return PR_FAILURE; | |
401 } | |
402 return PR_SUCCESS; | |
403 | |
404 aborted: | |
405 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); | |
406 thred->state &= ~PT_THREAD_ABORTED; | |
407 return PR_FAILURE; | |
408 } /* PR_WaitCondVar */ | |
409 | |
410 PR_IMPLEMENT(PRStatus) PR_NotifyCondVar(PRCondVar *cvar) | |
411 { | |
412 PR_ASSERT(cvar != NULL); | |
413 pt_PostNotifyToCvar(cvar, PR_FALSE); | |
414 return PR_SUCCESS; | |
415 } /* PR_NotifyCondVar */ | |
416 | |
417 PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar) | |
418 { | |
419 PR_ASSERT(cvar != NULL); | |
420 pt_PostNotifyToCvar(cvar, PR_TRUE); | |
421 return PR_SUCCESS; | |
422 } /* PR_NotifyAllCondVar */ | |
423 | |
424 /**************************************************************/ | |
425 /**************************************************************/ | |
426 /***************************MONITORS***************************/ | |
427 /**************************************************************/ | |
428 /**************************************************************/ | |
429 | |
430 /* | |
431 * Notifies just get posted to the monitor. The actual notification is done | |
432 * when the monitor is fully exited so that MP systems don't contend for a | |
433 * monitor that they can't enter. | |
434 */ | |
435 static void pt_PostNotifyToMonitor(PRMonitor *mon, PRBool broadcast) | |
436 { | |
437 PR_ASSERT(NULL != mon); | |
438 PR_ASSERT_CURRENT_THREAD_IN_MONITOR(mon); | |
439 | |
440 /* mon->notifyTimes is protected by the monitor, so we don't need to | |
441 * acquire mon->lock. | |
442 */ | |
443 if (broadcast) | |
444 mon->notifyTimes = -1; | |
445 else if (-1 != mon->notifyTimes) | |
446 mon->notifyTimes += 1; | |
447 } /* pt_PostNotifyToMonitor */ | |
448 | |
449 static void pt_PostNotifiesFromMonitor(pthread_cond_t *cv, PRIntn times) | |
450 { | |
451 PRIntn rv; | |
452 | |
453 /* | |
454 * Time to actually notify any waits that were affected while the monitor | |
455 * was entered. | |
456 */ | |
457 PR_ASSERT(NULL != cv); | |
458 PR_ASSERT(0 != times); | |
459 if (-1 == times) | |
460 { | |
461 rv = pthread_cond_broadcast(cv); | |
462 PR_ASSERT(0 == rv); | |
463 } | |
464 else | |
465 { | |
466 while (times-- > 0) | |
467 { | |
468 rv = pthread_cond_signal(cv); | |
469 PR_ASSERT(0 == rv); | |
470 } | |
471 } | |
472 } /* pt_PostNotifiesFromMonitor */ | |
473 | |
474 PR_IMPLEMENT(PRMonitor*) PR_NewMonitor(void) | |
475 { | |
476 PRMonitor *mon; | |
477 int rv; | |
478 | |
479 if (!_pr_initialized) _PR_ImplicitInitialization(); | |
480 | |
481 mon = PR_NEWZAP(PRMonitor); | |
482 if (mon == NULL) | |
483 { | |
484 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); | |
485 return NULL; | |
486 } | |
487 | |
488 rv = _PT_PTHREAD_MUTEX_INIT(mon->lock, _pt_mattr); | |
489 PR_ASSERT(0 == rv); | |
490 if (0 != rv) | |
491 goto error1; | |
492 | |
493 _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); | |
494 | |
495 rv = _PT_PTHREAD_COND_INIT(mon->entryCV, _pt_cvar_attr); | |
496 PR_ASSERT(0 == rv); | |
497 if (0 != rv) | |
498 goto error2; | |
499 | |
500 rv = _PT_PTHREAD_COND_INIT(mon->waitCV, _pt_cvar_attr); | |
501 PR_ASSERT(0 == rv); | |
502 if (0 != rv) | |
503 goto error3; | |
504 | |
505 mon->notifyTimes = 0; | |
506 mon->entryCount = 0; | |
507 mon->refCount = 1; | |
508 mon->name = NULL; | |
509 return mon; | |
510 | |
511 error3: | |
512 pthread_cond_destroy(&mon->entryCV); | |
513 error2: | |
514 pthread_mutex_destroy(&mon->lock); | |
515 error1: | |
516 PR_Free(mon); | |
517 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0); | |
518 return NULL; | |
519 } /* PR_NewMonitor */ | |
520 | |
521 PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name) | |
522 { | |
523 PRMonitor* mon = PR_NewMonitor(); | |
524 if (mon) | |
525 mon->name = name; | |
526 return mon; | |
527 } | |
528 | |
529 PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor *mon) | |
530 { | |
531 int rv; | |
532 | |
533 PR_ASSERT(mon != NULL); | |
534 if (PR_ATOMIC_DECREMENT(&mon->refCount) == 0) | |
535 { | |
536 rv = pthread_cond_destroy(&mon->waitCV); PR_ASSERT(0 == rv); | |
537 rv = pthread_cond_destroy(&mon->entryCV); PR_ASSERT(0 == rv); | |
538 rv = pthread_mutex_destroy(&mon->lock); PR_ASSERT(0 == rv); | |
539 #if defined(DEBUG) | |
540 memset(mon, 0xaf, sizeof(PRMonitor)); | |
541 #endif | |
542 PR_Free(mon); | |
543 } | |
544 } /* PR_DestroyMonitor */ | |
545 | |
546 /* The GC uses this; it is quite arguably a bad interface. I'm just | |
547 * duplicating it for now - XXXMB | |
548 */ | |
549 PR_IMPLEMENT(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon) | |
550 { | |
551 pthread_t self = pthread_self(); | |
552 PRIntn rv; | |
553 PRIntn count = 0; | |
554 | |
555 rv = pthread_mutex_lock(&mon->lock); | |
556 PR_ASSERT(0 == rv); | |
557 if (pthread_equal(mon->owner, self)) | |
558 count = mon->entryCount; | |
559 rv = pthread_mutex_unlock(&mon->lock); | |
560 PR_ASSERT(0 == rv); | |
561 return count; | |
562 } | |
563 | |
564 PR_IMPLEMENT(void) PR_AssertCurrentThreadInMonitor(PRMonitor *mon) | |
565 { | |
566 #if defined(DEBUG) || defined(FORCE_PR_ASSERT) | |
567 PRIntn rv; | |
568 | |
569 rv = pthread_mutex_lock(&mon->lock); | |
570 PR_ASSERT(0 == rv); | |
571 PR_ASSERT(mon->entryCount != 0 && | |
572 pthread_equal(mon->owner, pthread_self())); | |
573 rv = pthread_mutex_unlock(&mon->lock); | |
574 PR_ASSERT(0 == rv); | |
575 #endif | |
576 } | |
577 | |
578 PR_IMPLEMENT(void) PR_EnterMonitor(PRMonitor *mon) | |
579 { | |
580 pthread_t self = pthread_self(); | |
581 PRIntn rv; | |
582 | |
583 PR_ASSERT(mon != NULL); | |
584 rv = pthread_mutex_lock(&mon->lock); | |
585 PR_ASSERT(0 == rv); | |
586 if (mon->entryCount != 0) | |
587 { | |
588 if (pthread_equal(mon->owner, self)) | |
589 goto done; | |
590 while (mon->entryCount != 0) | |
591 { | |
592 rv = pthread_cond_wait(&mon->entryCV, &mon->lock); | |
593 PR_ASSERT(0 == rv); | |
594 } | |
595 } | |
596 /* and now I have the monitor */ | |
597 PR_ASSERT(0 == mon->notifyTimes); | |
598 PR_ASSERT(_PT_PTHREAD_THR_HANDLE_IS_INVALID(mon->owner)); | |
599 _PT_PTHREAD_COPY_THR_HANDLE(self, mon->owner); | |
600 | |
601 done: | |
602 mon->entryCount += 1; | |
603 rv = pthread_mutex_unlock(&mon->lock); | |
604 PR_ASSERT(0 == rv); | |
605 } /* PR_EnterMonitor */ | |
606 | |
607 PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon) | |
608 { | |
609 pthread_t self = pthread_self(); | |
610 PRIntn rv; | |
611 PRBool notifyEntryWaiter = PR_FALSE; | |
612 PRIntn notifyTimes = 0; | |
613 | |
614 PR_ASSERT(mon != NULL); | |
615 rv = pthread_mutex_lock(&mon->lock); | |
616 PR_ASSERT(0 == rv); | |
617 /* the entries should be > 0 and we'd better be the owner */ | |
618 PR_ASSERT(mon->entryCount > 0); | |
619 PR_ASSERT(pthread_equal(mon->owner, self)); | |
620 if (mon->entryCount == 0 || !pthread_equal(mon->owner, self)) | |
621 { | |
622 rv = pthread_mutex_unlock(&mon->lock); | |
623 PR_ASSERT(0 == rv); | |
624 return PR_FAILURE; | |
625 } | |
626 | |
627 mon->entryCount -= 1; /* reduce by one */ | |
628 if (mon->entryCount == 0) | |
629 { | |
630 /* and if it transitioned to zero - notify an entry waiter */ | |
631 /* make the owner unknown */ | |
632 _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); | |
633 notifyEntryWaiter = PR_TRUE; | |
634 notifyTimes = mon->notifyTimes; | |
635 mon->notifyTimes = 0; | |
636 /* We will access the members of 'mon' after unlocking mon->lock. | |
637 * Add a reference. */ | |
638 PR_ATOMIC_INCREMENT(&mon->refCount); | |
639 } | |
640 rv = pthread_mutex_unlock(&mon->lock); | |
641 PR_ASSERT(0 == rv); | |
642 if (notifyEntryWaiter) | |
643 { | |
644 if (notifyTimes) | |
645 pt_PostNotifiesFromMonitor(&mon->waitCV, notifyTimes); | |
646 rv = pthread_cond_signal(&mon->entryCV); | |
647 PR_ASSERT(0 == rv); | |
648 /* We are done accessing the members of 'mon'. Release the | |
649 * reference. */ | |
650 PR_DestroyMonitor(mon); | |
651 } | |
652 return PR_SUCCESS; | |
653 } /* PR_ExitMonitor */ | |
654 | |
655 PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime timeout) | |
656 { | |
657 PRStatus rv; | |
658 PRUint32 saved_entries; | |
659 pthread_t saved_owner; | |
660 | |
661 PR_ASSERT(mon != NULL); | |
662 rv = pthread_mutex_lock(&mon->lock); | |
663 PR_ASSERT(0 == rv); | |
664 /* the entries better be positive */ | |
665 PR_ASSERT(mon->entryCount > 0); | |
666 /* and it better be owned by us */ | |
667 PR_ASSERT(pthread_equal(mon->owner, pthread_self())); | |
668 | |
669 /* tuck these away 'till later */ | |
670 saved_entries = mon->entryCount; | |
671 mon->entryCount = 0; | |
672 _PT_PTHREAD_COPY_THR_HANDLE(mon->owner, saved_owner); | |
673 _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); | |
674 /* | |
675 * If we have pending notifies, post them now. | |
676 * | |
677 * This is not optimal. We're going to post these notifies | |
678 * while we're holding the lock. That means on MP systems | |
679 * that they are going to collide for the lock that we will | |
680 * hold until we actually wait. | |
681 */ | |
682 if (0 != mon->notifyTimes) | |
683 { | |
684 pt_PostNotifiesFromMonitor(&mon->waitCV, mon->notifyTimes); | |
685 mon->notifyTimes = 0; | |
686 } | |
687 rv = pthread_cond_signal(&mon->entryCV); | |
688 PR_ASSERT(0 == rv); | |
689 | |
690 if (timeout == PR_INTERVAL_NO_TIMEOUT) | |
691 rv = pthread_cond_wait(&mon->waitCV, &mon->lock); | |
692 else | |
693 rv = pt_TimedWait(&mon->waitCV, &mon->lock, timeout); | |
694 PR_ASSERT(0 == rv); | |
695 | |
696 while (mon->entryCount != 0) | |
697 { | |
698 rv = pthread_cond_wait(&mon->entryCV, &mon->lock); | |
699 PR_ASSERT(0 == rv); | |
700 } | |
701 PR_ASSERT(0 == mon->notifyTimes); | |
702 /* reinstate the interesting information */ | |
703 mon->entryCount = saved_entries; | |
704 _PT_PTHREAD_COPY_THR_HANDLE(saved_owner, mon->owner); | |
705 | |
706 rv = pthread_mutex_unlock(&mon->lock); | |
707 PR_ASSERT(0 == rv); | |
708 return rv; | |
709 } /* PR_Wait */ | |
710 | |
711 PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon) | |
712 { | |
713 pt_PostNotifyToMonitor(mon, PR_FALSE); | |
714 return PR_SUCCESS; | |
715 } /* PR_Notify */ | |
716 | |
717 PR_IMPLEMENT(PRStatus) PR_NotifyAll(PRMonitor *mon) | |
718 { | |
719 pt_PostNotifyToMonitor(mon, PR_TRUE); | |
720 return PR_SUCCESS; | |
721 } /* PR_NotifyAll */ | |
722 | |
723 /**************************************************************/ | |
724 /**************************************************************/ | |
725 /**************************SEMAPHORES**************************/ | |
726 /**************************************************************/ | |
727 /**************************************************************/ | |
728 PR_IMPLEMENT(void) PR_PostSem(PRSemaphore *semaphore) | |
729 { | |
730 static PRBool unwarned = PR_TRUE; | |
731 if (unwarned) unwarned = _PR_Obsolete( | |
732 "PR_PostSem", "locks & condition variables"); | |
733 PR_Lock(semaphore->cvar->lock); | |
734 PR_NotifyCondVar(semaphore->cvar); | |
735 semaphore->count += 1; | |
736 PR_Unlock(semaphore->cvar->lock); | |
737 } /* PR_PostSem */ | |
738 | |
739 PR_IMPLEMENT(PRStatus) PR_WaitSem(PRSemaphore *semaphore) | |
740 { | |
741 PRStatus status = PR_SUCCESS; | |
742 static PRBool unwarned = PR_TRUE; | |
743 if (unwarned) unwarned = _PR_Obsolete( | |
744 "PR_WaitSem", "locks & condition variables"); | |
745 PR_Lock(semaphore->cvar->lock); | |
746 while ((semaphore->count == 0) && (PR_SUCCESS == status)) | |
747 status = PR_WaitCondVar(semaphore->cvar, PR_INTERVAL_NO_TIMEOUT); | |
748 if (PR_SUCCESS == status) semaphore->count -= 1; | |
749 PR_Unlock(semaphore->cvar->lock); | |
750 return status; | |
751 } /* PR_WaitSem */ | |
752 | |
753 PR_IMPLEMENT(void) PR_DestroySem(PRSemaphore *semaphore) | |
754 { | |
755 static PRBool unwarned = PR_TRUE; | |
756 if (unwarned) unwarned = _PR_Obsolete( | |
757 "PR_DestroySem", "locks & condition variables"); | |
758 PR_DestroyLock(semaphore->cvar->lock); | |
759 PR_DestroyCondVar(semaphore->cvar); | |
760 PR_Free(semaphore); | |
761 } /* PR_DestroySem */ | |
762 | |
763 PR_IMPLEMENT(PRSemaphore*) PR_NewSem(PRUintn value) | |
764 { | |
765 PRSemaphore *semaphore; | |
766 static PRBool unwarned = PR_TRUE; | |
767 if (!_pr_initialized) _PR_ImplicitInitialization(); | |
768 | |
769 if (unwarned) unwarned = _PR_Obsolete( | |
770 "PR_NewSem", "locks & condition variables"); | |
771 | |
772 semaphore = PR_NEWZAP(PRSemaphore); | |
773 if (NULL != semaphore) | |
774 { | |
775 PRLock *lock = PR_NewLock(); | |
776 if (NULL != lock) | |
777 { | |
778 semaphore->cvar = PR_NewCondVar(lock); | |
779 if (NULL != semaphore->cvar) | |
780 { | |
781 semaphore->count = value; | |
782 return semaphore; | |
783 } | |
784 PR_DestroyLock(lock); | |
785 } | |
786 PR_Free(semaphore); | |
787 } | |
788 return NULL; | |
789 } | |
790 | |
791 /* | |
792 * Define the interprocess named semaphore functions. | |
793 * There are three implementations: | |
794 * 1. POSIX semaphore based; | |
795 * 2. System V semaphore based; | |
796 * 3. unsupported (fails with PR_NOT_IMPLEMENTED_ERROR). | |
797 */ | |
798 | |
799 #ifdef _PR_HAVE_POSIX_SEMAPHORES | |
800 #include <fcntl.h> | |
801 | |
802 PR_IMPLEMENT(PRSem *) PR_OpenSemaphore( | |
803 const char *name, | |
804 PRIntn flags, | |
805 PRIntn mode, | |
806 PRUintn value) | |
807 { | |
808 PRSem *sem; | |
809 char osname[PR_IPC_NAME_SIZE]; | |
810 | |
811 if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) | |
812 == PR_FAILURE) | |
813 { | |
814 return NULL; | |
815 } | |
816 | |
817 sem = PR_NEW(PRSem); | |
818 if (NULL == sem) | |
819 { | |
820 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); | |
821 return NULL; | |
822 } | |
823 | |
824 if (flags & PR_SEM_CREATE) | |
825 { | |
826 int oflag = O_CREAT; | |
827 | |
828 if (flags & PR_SEM_EXCL) oflag |= O_EXCL; | |
829 sem->sem = sem_open(osname, oflag, mode, value); | |
830 } | |
831 else | |
832 { | |
833 #ifdef HPUX | |
834 /* Pass 0 as the mode and value arguments to work around a bug. */ | |
835 sem->sem = sem_open(osname, 0, 0, 0); | |
836 #else | |
837 sem->sem = sem_open(osname, 0); | |
838 #endif | |
839 } | |
840 if ((sem_t *) -1 == sem->sem) | |
841 { | |
842 _PR_MD_MAP_DEFAULT_ERROR(errno); | |
843 PR_Free(sem); | |
844 return NULL; | |
845 } | |
846 return sem; | |
847 } | |
848 | |
849 PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem) | |
850 { | |
851 int rv; | |
852 rv = sem_wait(sem->sem); | |
853 if (0 != rv) | |
854 { | |
855 _PR_MD_MAP_DEFAULT_ERROR(errno); | |
856 return PR_FAILURE; | |
857 } | |
858 return PR_SUCCESS; | |
859 } | |
860 | |
861 PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem) | |
862 { | |
863 int rv; | |
864 rv = sem_post(sem->sem); | |
865 if (0 != rv) | |
866 { | |
867 _PR_MD_MAP_DEFAULT_ERROR(errno); | |
868 return PR_FAILURE; | |
869 } | |
870 return PR_SUCCESS; | |
871 } | |
872 | |
873 PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem) | |
874 { | |
875 int rv; | |
876 rv = sem_close(sem->sem); | |
877 if (0 != rv) | |
878 { | |
879 _PR_MD_MAP_DEFAULT_ERROR(errno); | |
880 return PR_FAILURE; | |
881 } | |
882 PR_Free(sem); | |
883 return PR_SUCCESS; | |
884 } | |
885 | |
886 PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name) | |
887 { | |
888 int rv; | |
889 char osname[PR_IPC_NAME_SIZE]; | |
890 | |
891 if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) | |
892 == PR_FAILURE) | |
893 { | |
894 return PR_FAILURE; | |
895 } | |
896 rv = sem_unlink(osname); | |
897 if (0 != rv) | |
898 { | |
899 _PR_MD_MAP_DEFAULT_ERROR(errno); | |
900 return PR_FAILURE; | |
901 } | |
902 return PR_SUCCESS; | |
903 } | |
904 | |
905 #elif defined(_PR_HAVE_SYSV_SEMAPHORES) | |
906 | |
907 #include <fcntl.h> | |
908 #include <sys/sem.h> | |
909 | |
910 /* | |
911 * From the semctl(2) man page in glibc 2.0 | |
912 */ | |
913 #if (defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)) \ | |
914 || defined(FREEBSD) || defined(OPENBSD) || defined(BSDI) \ | |
915 || defined(DARWIN) || defined(SYMBIAN) | |
916 /* union semun is defined by including <sys/sem.h> */ | |
917 #else | |
918 /* according to X/OPEN we have to define it ourselves */ | |
919 union semun { | |
920 int val; | |
921 struct semid_ds *buf; | |
922 unsigned short *array; | |
923 }; | |
924 #endif | |
925 | |
926 /* | |
927 * 'a' (97) is the final closing price of NSCP stock. | |
928 */ | |
929 #define NSPR_IPC_KEY_ID 'a' /* the id argument for ftok() */ | |
930 | |
931 #define NSPR_SEM_MODE 0666 | |
932 | |
933 PR_IMPLEMENT(PRSem *) PR_OpenSemaphore( | |
934 const char *name, | |
935 PRIntn flags, | |
936 PRIntn mode, | |
937 PRUintn value) | |
938 { | |
939 PRSem *sem; | |
940 key_t key; | |
941 union semun arg; | |
942 struct sembuf sop; | |
943 struct semid_ds seminfo; | |
944 #define MAX_TRIES 60 | |
945 PRIntn i; | |
946 char osname[PR_IPC_NAME_SIZE]; | |
947 | |
948 if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) | |
949 == PR_FAILURE) | |
950 { | |
951 return NULL; | |
952 } | |
953 | |
954 /* Make sure the file exists before calling ftok. */ | |
955 if (flags & PR_SEM_CREATE) | |
956 { | |
957 int osfd = open(osname, O_RDWR|O_CREAT, mode); | |
958 if (-1 == osfd) | |
959 { | |
960 _PR_MD_MAP_OPEN_ERROR(errno); | |
961 return NULL; | |
962 } | |
963 if (close(osfd) == -1) | |
964 { | |
965 _PR_MD_MAP_CLOSE_ERROR(errno); | |
966 return NULL; | |
967 } | |
968 } | |
969 key = ftok(osname, NSPR_IPC_KEY_ID); | |
970 if ((key_t)-1 == key) | |
971 { | |
972 _PR_MD_MAP_DEFAULT_ERROR(errno); | |
973 return NULL; | |
974 } | |
975 | |
976 sem = PR_NEW(PRSem); | |
977 if (NULL == sem) | |
978 { | |
979 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); | |
980 return NULL; | |
981 } | |
982 | |
983 if (flags & PR_SEM_CREATE) | |
984 { | |
985 sem->semid = semget(key, 1, mode|IPC_CREAT|IPC_EXCL); | |
986 if (sem->semid >= 0) | |
987 { | |
988 /* creator of a semaphore is responsible for initializing it */ | |
989 arg.val = 0; | |
990 if (semctl(sem->semid, 0, SETVAL, arg) == -1) | |
991 { | |
992 _PR_MD_MAP_DEFAULT_ERROR(errno); | |
993 PR_Free(sem); | |
994 return NULL; | |
995 } | |
996 /* call semop to set sem_otime to nonzero */ | |
997 sop.sem_num = 0; | |
998 sop.sem_op = value; | |
999 sop.sem_flg = 0; | |
1000 if (semop(sem->semid, &sop, 1) == -1) | |
1001 { | |
1002 _PR_MD_MAP_DEFAULT_ERROR(errno); | |
1003 PR_Free(sem); | |
1004 return NULL; | |
1005 } | |
1006 return sem; | |
1007 } | |
1008 | |
1009 if (errno != EEXIST || flags & PR_SEM_EXCL) | |
1010 { | |
1011 _PR_MD_MAP_DEFAULT_ERROR(errno); | |
1012 PR_Free(sem); | |
1013 return NULL; | |
1014 } | |
1015 } | |
1016 | |
1017 sem->semid = semget(key, 1, NSPR_SEM_MODE); | |
1018 if (sem->semid == -1) | |
1019 { | |
1020 _PR_MD_MAP_DEFAULT_ERROR(errno); | |
1021 PR_Free(sem); | |
1022 return NULL; | |
1023 } | |
1024 for (i = 0; i < MAX_TRIES; i++) | |
1025 { | |
1026 arg.buf = &seminfo; | |
1027 semctl(sem->semid, 0, IPC_STAT, arg); | |
1028 if (seminfo.sem_otime != 0) break; | |
1029 sleep(1); | |
1030 } | |
1031 if (i == MAX_TRIES) | |
1032 { | |
1033 PR_SetError(PR_IO_TIMEOUT_ERROR, 0); | |
1034 PR_Free(sem); | |
1035 return NULL; | |
1036 } | |
1037 return sem; | |
1038 } | |
1039 | |
1040 PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem) | |
1041 { | |
1042 struct sembuf sop; | |
1043 | |
1044 sop.sem_num = 0; | |
1045 sop.sem_op = -1; | |
1046 sop.sem_flg = 0; | |
1047 if (semop(sem->semid, &sop, 1) == -1) | |
1048 { | |
1049 _PR_MD_MAP_DEFAULT_ERROR(errno); | |
1050 return PR_FAILURE; | |
1051 } | |
1052 return PR_SUCCESS; | |
1053 } | |
1054 | |
1055 PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem) | |
1056 { | |
1057 struct sembuf sop; | |
1058 | |
1059 sop.sem_num = 0; | |
1060 sop.sem_op = 1; | |
1061 sop.sem_flg = 0; | |
1062 if (semop(sem->semid, &sop, 1) == -1) | |
1063 { | |
1064 _PR_MD_MAP_DEFAULT_ERROR(errno); | |
1065 return PR_FAILURE; | |
1066 } | |
1067 return PR_SUCCESS; | |
1068 } | |
1069 | |
1070 PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem) | |
1071 { | |
1072 PR_Free(sem); | |
1073 return PR_SUCCESS; | |
1074 } | |
1075 | |
1076 PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name) | |
1077 { | |
1078 key_t key; | |
1079 int semid; | |
1080 /* On some systems (e.g., glibc 2.0) semctl requires a fourth argument */ | |
1081 union semun unused; | |
1082 char osname[PR_IPC_NAME_SIZE]; | |
1083 | |
1084 if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) | |
1085 == PR_FAILURE) | |
1086 { | |
1087 return PR_FAILURE; | |
1088 } | |
1089 key = ftok(osname, NSPR_IPC_KEY_ID); | |
1090 if ((key_t) -1 == key) | |
1091 { | |
1092 _PR_MD_MAP_DEFAULT_ERROR(errno); | |
1093 return PR_FAILURE; | |
1094 } | |
1095 if (unlink(osname) == -1) | |
1096 { | |
1097 _PR_MD_MAP_UNLINK_ERROR(errno); | |
1098 return PR_FAILURE; | |
1099 } | |
1100 semid = semget(key, 1, NSPR_SEM_MODE); | |
1101 if (-1 == semid) | |
1102 { | |
1103 _PR_MD_MAP_DEFAULT_ERROR(errno); | |
1104 return PR_FAILURE; | |
1105 } | |
1106 unused.val = 0; | |
1107 if (semctl(semid, 0, IPC_RMID, unused) == -1) | |
1108 { | |
1109 _PR_MD_MAP_DEFAULT_ERROR(errno); | |
1110 return PR_FAILURE; | |
1111 } | |
1112 return PR_SUCCESS; | |
1113 } | |
1114 | |
1115 #else /* neither POSIX nor System V semaphores are available */ | |
1116 | |
1117 PR_IMPLEMENT(PRSem *) PR_OpenSemaphore( | |
1118 const char *name, | |
1119 PRIntn flags, | |
1120 PRIntn mode, | |
1121 PRUintn value) | |
1122 { | |
1123 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); | |
1124 return NULL; | |
1125 } | |
1126 | |
1127 PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem) | |
1128 { | |
1129 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); | |
1130 return PR_FAILURE; | |
1131 } | |
1132 | |
1133 PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem) | |
1134 { | |
1135 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); | |
1136 return PR_FAILURE; | |
1137 } | |
1138 | |
1139 PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem) | |
1140 { | |
1141 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); | |
1142 return PR_FAILURE; | |
1143 } | |
1144 | |
1145 PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name) | |
1146 { | |
1147 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); | |
1148 return PR_FAILURE; | |
1149 } | |
1150 | |
1151 #endif /* end of interprocess named semaphore functions */ | |
1152 | |
1153 /**************************************************************/ | |
1154 /**************************************************************/ | |
1155 /******************ROUTINES FOR DCE EMULATION******************/ | |
1156 /**************************************************************/ | |
1157 /**************************************************************/ | |
1158 | |
1159 #include "prpdce.h" | |
1160 | |
1161 PR_IMPLEMENT(PRStatus) PRP_TryLock(PRLock *lock) | |
1162 { | |
1163 PRIntn rv = pthread_mutex_trylock(&lock->mutex); | |
1164 if (rv == PT_TRYLOCK_SUCCESS) | |
1165 { | |
1166 PR_ASSERT(PR_FALSE == lock->locked); | |
1167 lock->locked = PR_TRUE; | |
1168 lock->owner = pthread_self(); | |
1169 } | |
1170 /* XXX set error code? */ | |
1171 return (PT_TRYLOCK_SUCCESS == rv) ? PR_SUCCESS : PR_FAILURE; | |
1172 } /* PRP_TryLock */ | |
1173 | |
1174 PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar(void) | |
1175 { | |
1176 PRCondVar *cv; | |
1177 | |
1178 if (!_pr_initialized) _PR_ImplicitInitialization(); | |
1179 | |
1180 cv = PR_NEW(PRCondVar); | |
1181 if (cv != NULL) | |
1182 { | |
1183 int rv; | |
1184 rv = _PT_PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr); | |
1185 PR_ASSERT(0 == rv); | |
1186 cv->lock = _PR_NAKED_CV_LOCK; | |
1187 } | |
1188 return cv; | |
1189 } /* PRP_NewNakedCondVar */ | |
1190 | |
1191 PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar *cvar) | |
1192 { | |
1193 int rv; | |
1194 rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv); | |
1195 #if defined(DEBUG) | |
1196 memset(cvar, 0xaf, sizeof(PRCondVar)); | |
1197 #endif | |
1198 PR_Free(cvar); | |
1199 } /* PRP_DestroyNakedCondVar */ | |
1200 | |
1201 PR_IMPLEMENT(PRStatus) PRP_NakedWait( | |
1202 PRCondVar *cvar, PRLock *ml, PRIntervalTime timeout) | |
1203 { | |
1204 PRIntn rv; | |
1205 PR_ASSERT(cvar != NULL); | |
1206 /* XXX do we really want to assert this in a naked wait? */ | |
1207 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(ml->mutex)); | |
1208 if (timeout == PR_INTERVAL_NO_TIMEOUT) | |
1209 rv = pthread_cond_wait(&cvar->cv, &ml->mutex); | |
1210 else | |
1211 rv = pt_TimedWait(&cvar->cv, &ml->mutex, timeout); | |
1212 if (rv != 0) | |
1213 { | |
1214 _PR_MD_MAP_DEFAULT_ERROR(rv); | |
1215 return PR_FAILURE; | |
1216 } | |
1217 return PR_SUCCESS; | |
1218 } /* PRP_NakedWait */ | |
1219 | |
1220 PR_IMPLEMENT(PRStatus) PRP_NakedNotify(PRCondVar *cvar) | |
1221 { | |
1222 int rv; | |
1223 PR_ASSERT(cvar != NULL); | |
1224 rv = pthread_cond_signal(&cvar->cv); | |
1225 PR_ASSERT(0 == rv); | |
1226 return PR_SUCCESS; | |
1227 } /* PRP_NakedNotify */ | |
1228 | |
1229 PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar) | |
1230 { | |
1231 int rv; | |
1232 PR_ASSERT(cvar != NULL); | |
1233 rv = pthread_cond_broadcast(&cvar->cv); | |
1234 PR_ASSERT(0 == rv); | |
1235 return PR_SUCCESS; | |
1236 } /* PRP_NakedBroadcast */ | |
1237 | |
1238 #endif /* defined(_PR_PTHREADS) */ | |
1239 | |
1240 /* ptsynch.c */ |