OLD | NEW |
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | 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 | 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 | 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/. */ | 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
5 | 5 |
6 /* | 6 /* |
7 ** File: ptsynch.c | 7 ** File: ptsynch.c |
8 ** Descritpion: Implemenation for thread synchronization using pthreads | 8 ** Descritpion: Implemenation for thread synchronization using pthreads |
9 ** Exports: prlock.h, prcvar.h, prmon.h, prcmon.h | 9 ** Exports: prlock.h, prcvar.h, prmon.h, prcmon.h |
10 */ | 10 */ |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
162 PR_ASSERT(0 == rv); | 162 PR_ASSERT(0 == rv); |
163 #if defined(DEBUG) | 163 #if defined(DEBUG) |
164 memset(lock, 0xaf, sizeof(PRLock)); | 164 memset(lock, 0xaf, sizeof(PRLock)); |
165 pt_debug.locks_destroyed += 1; | 165 pt_debug.locks_destroyed += 1; |
166 #endif | 166 #endif |
167 PR_Free(lock); | 167 PR_Free(lock); |
168 } /* PR_DestroyLock */ | 168 } /* PR_DestroyLock */ |
169 | 169 |
170 PR_IMPLEMENT(void) PR_Lock(PRLock *lock) | 170 PR_IMPLEMENT(void) PR_Lock(PRLock *lock) |
171 { | 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. */ |
172 PRIntn rv; | 175 PRIntn rv; |
173 PR_ASSERT(lock != NULL); | 176 PR_ASSERT(lock != NULL); |
174 rv = pthread_mutex_lock(&lock->mutex); | 177 rv = pthread_mutex_lock(&lock->mutex); |
175 PR_ASSERT(0 == rv); | 178 PR_ASSERT(0 == rv); |
176 PR_ASSERT(0 == lock->notified.length); | 179 PR_ASSERT(0 == lock->notified.length); |
177 PR_ASSERT(NULL == lock->notified.link); | 180 PR_ASSERT(NULL == lock->notified.link); |
178 PR_ASSERT(PR_FALSE == lock->locked); | 181 PR_ASSERT(PR_FALSE == lock->locked); |
179 /* Nb: the order of the next two statements is not critical to | 182 /* Nb: the order of the next two statements is not critical to |
180 * the correctness of PR_AssertCurrentThreadOwnsLock(), but | 183 * the correctness of PR_AssertCurrentThreadOwnsLock(), but |
181 * this particular order makes the assertion more likely to | 184 * this particular order makes the assertion more likely to |
182 * catch errors. */ | 185 * catch errors. */ |
183 lock->owner = pthread_self(); | 186 lock->owner = pthread_self(); |
184 lock->locked = PR_TRUE; | 187 lock->locked = PR_TRUE; |
185 #if defined(DEBUG) | 188 #if defined(DEBUG) |
186 pt_debug.locks_acquired += 1; | 189 pt_debug.locks_acquired += 1; |
187 #endif | 190 #endif |
188 } /* PR_Lock */ | 191 } /* PR_Lock */ |
189 | 192 |
190 PR_IMPLEMENT(PRStatus) PR_Unlock(PRLock *lock) | 193 PR_IMPLEMENT(PRStatus) PR_Unlock(PRLock *lock) |
191 { | 194 { |
| 195 pthread_t self = pthread_self(); |
192 PRIntn rv; | 196 PRIntn rv; |
193 | 197 |
194 PR_ASSERT(lock != NULL); | 198 PR_ASSERT(lock != NULL); |
195 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(lock->mutex)); | 199 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(lock->mutex)); |
196 PR_ASSERT(PR_TRUE == lock->locked); | 200 PR_ASSERT(PR_TRUE == lock->locked); |
197 PR_ASSERT(pthread_equal(lock->owner, pthread_self())); | 201 PR_ASSERT(pthread_equal(lock->owner, self)); |
198 | 202 |
199 if (!lock->locked || !pthread_equal(lock->owner, pthread_self())) | 203 if (!lock->locked || !pthread_equal(lock->owner, self)) |
200 return PR_FAILURE; | 204 return PR_FAILURE; |
201 | 205 |
202 lock->locked = PR_FALSE; | 206 lock->locked = PR_FALSE; |
203 if (0 == lock->notified.length) /* shortcut */ | 207 if (0 == lock->notified.length) /* shortcut */ |
204 { | 208 { |
205 rv = pthread_mutex_unlock(&lock->mutex); | 209 rv = pthread_mutex_unlock(&lock->mutex); |
206 PR_ASSERT(0 == rv); | 210 PR_ASSERT(0 == rv); |
207 } | 211 } |
208 else pt_PostNotifies(lock, PR_TRUE); | 212 else pt_PostNotifies(lock, PR_TRUE); |
209 | 213 |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
286 while (1) | 290 while (1) |
287 { | 291 { |
288 for (index = 0; index < notified->length; ++index) | 292 for (index = 0; index < notified->length; ++index) |
289 { | 293 { |
290 if (notified->cv[index].cv == cvar) | 294 if (notified->cv[index].cv == cvar) |
291 { | 295 { |
292 if (broadcast) | 296 if (broadcast) |
293 notified->cv[index].times = -1; | 297 notified->cv[index].times = -1; |
294 else if (-1 != notified->cv[index].times) | 298 else if (-1 != notified->cv[index].times) |
295 notified->cv[index].times += 1; | 299 notified->cv[index].times += 1; |
296 goto finished; /* we're finished */ | 300 return; /* we're finished */ |
297 } | 301 } |
298 } | 302 } |
299 /* if not full, enter new CV in this array */ | 303 /* if not full, enter new CV in this array */ |
300 if (notified->length < PT_CV_NOTIFIED_LENGTH) break; | 304 if (notified->length < PT_CV_NOTIFIED_LENGTH) break; |
301 | 305 |
302 /* if there's no link, create an empty array and link it */ | 306 /* if there's no link, create an empty array and link it */ |
303 if (NULL == notified->link) | 307 if (NULL == notified->link) |
304 notified->link = PR_NEWZAP(_PT_Notified); | 308 notified->link = PR_NEWZAP(_PT_Notified); |
305 notified = notified->link; | 309 notified = notified->link; |
306 } | 310 } |
307 | 311 |
308 /* A brand new entry in the array */ | 312 /* A brand new entry in the array */ |
309 (void)PR_ATOMIC_INCREMENT(&cvar->notify_pending); | 313 (void)PR_ATOMIC_INCREMENT(&cvar->notify_pending); |
310 notified->cv[index].times = (broadcast) ? -1 : 1; | 314 notified->cv[index].times = (broadcast) ? -1 : 1; |
311 notified->cv[index].cv = cvar; | 315 notified->cv[index].cv = cvar; |
312 notified->length += 1; | 316 notified->length += 1; |
313 | |
314 finished: | |
315 PR_ASSERT(PR_TRUE == cvar->lock->locked); | |
316 PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self())); | |
317 } /* pt_PostNotifyToCvar */ | 317 } /* pt_PostNotifyToCvar */ |
318 | 318 |
319 PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock *lock) | 319 PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock *lock) |
320 { | 320 { |
321 PRCondVar *cv = PR_NEW(PRCondVar); | 321 PRCondVar *cv = PR_NEW(PRCondVar); |
322 PR_ASSERT(lock != NULL); | 322 PR_ASSERT(lock != NULL); |
323 if (cv != NULL) | 323 if (cv != NULL) |
324 { | 324 { |
325 int rv = _PT_PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr); | 325 int rv = _PT_PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr); |
326 PR_ASSERT(0 == rv); | 326 PR_ASSERT(0 == rv); |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
420 pt_PostNotifyToCvar(cvar, PR_TRUE); | 420 pt_PostNotifyToCvar(cvar, PR_TRUE); |
421 return PR_SUCCESS; | 421 return PR_SUCCESS; |
422 } /* PR_NotifyAllCondVar */ | 422 } /* PR_NotifyAllCondVar */ |
423 | 423 |
424 /**************************************************************/ | 424 /**************************************************************/ |
425 /**************************************************************/ | 425 /**************************************************************/ |
426 /***************************MONITORS***************************/ | 426 /***************************MONITORS***************************/ |
427 /**************************************************************/ | 427 /**************************************************************/ |
428 /**************************************************************/ | 428 /**************************************************************/ |
429 | 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 |
430 PR_IMPLEMENT(PRMonitor*) PR_NewMonitor(void) | 474 PR_IMPLEMENT(PRMonitor*) PR_NewMonitor(void) |
431 { | 475 { |
432 PRMonitor *mon; | 476 PRMonitor *mon; |
433 PRCondVar *cvar; | |
434 int rv; | 477 int rv; |
435 | 478 |
436 if (!_pr_initialized) _PR_ImplicitInitialization(); | 479 if (!_pr_initialized) _PR_ImplicitInitialization(); |
437 | 480 |
438 cvar = PR_NEWZAP(PRCondVar); | 481 mon = PR_NEWZAP(PRMonitor); |
439 if (NULL == cvar) | 482 if (mon == NULL) |
440 { | 483 { |
441 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); | 484 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); |
442 return NULL; | 485 return NULL; |
443 } | 486 } |
444 mon = PR_NEWZAP(PRMonitor); | |
445 if (mon == NULL) | |
446 { | |
447 PR_Free(cvar); | |
448 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); | |
449 return NULL; | |
450 } | |
451 | 487 |
452 rv = _PT_PTHREAD_MUTEX_INIT(mon->lock.mutex, _pt_mattr); | 488 rv = _PT_PTHREAD_MUTEX_INIT(mon->lock, _pt_mattr); |
453 PR_ASSERT(0 == rv); | 489 PR_ASSERT(0 == rv); |
454 if (0 != rv) | 490 if (0 != rv) |
455 { | 491 goto error1; |
456 PR_Free(mon); | |
457 PR_Free(cvar); | |
458 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0); | |
459 return NULL; | |
460 } | |
461 | 492 |
462 _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); | 493 _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); |
463 | 494 |
464 mon->cvar = cvar; | 495 rv = _PT_PTHREAD_COND_INIT(mon->entryCV, _pt_cvar_attr); |
465 rv = _PT_PTHREAD_COND_INIT(mon->cvar->cv, _pt_cvar_attr); | |
466 PR_ASSERT(0 == rv); | 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; |
467 mon->entryCount = 0; | 506 mon->entryCount = 0; |
468 mon->cvar->lock = &mon->lock; | 507 mon->refCount = 1; |
469 if (0 != rv) | 508 mon->name = NULL; |
470 { | |
471 pthread_mutex_destroy(&mon->lock.mutex); | |
472 PR_Free(mon); | |
473 PR_Free(cvar); | |
474 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0); | |
475 return NULL; | |
476 } | |
477 return mon; | 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; |
478 } /* PR_NewMonitor */ | 519 } /* PR_NewMonitor */ |
479 | 520 |
480 PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name) | 521 PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name) |
481 { | 522 { |
482 PRMonitor* mon = PR_NewMonitor(); | 523 PRMonitor* mon = PR_NewMonitor(); |
483 if (mon) | 524 if (mon) |
484 mon->name = name; | 525 mon->name = name; |
485 return mon; | 526 return mon; |
486 } | 527 } |
487 | 528 |
488 PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor *mon) | 529 PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor *mon) |
489 { | 530 { |
490 int rv; | 531 int rv; |
| 532 |
491 PR_ASSERT(mon != NULL); | 533 PR_ASSERT(mon != NULL); |
492 PR_DestroyCondVar(mon->cvar); | 534 if (PR_ATOMIC_DECREMENT(&mon->refCount) == 0) |
493 rv = pthread_mutex_destroy(&mon->lock.mutex); PR_ASSERT(0 == rv); | 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); |
494 #if defined(DEBUG) | 539 #if defined(DEBUG) |
495 memset(mon, 0xaf, sizeof(PRMonitor)); | 540 memset(mon, 0xaf, sizeof(PRMonitor)); |
496 #endif | 541 #endif |
497 PR_Free(mon); | 542 PR_Free(mon); |
| 543 } |
498 } /* PR_DestroyMonitor */ | 544 } /* PR_DestroyMonitor */ |
499 | 545 |
500 | |
501 /* The GC uses this; it is quite arguably a bad interface. I'm just | 546 /* The GC uses this; it is quite arguably a bad interface. I'm just |
502 * duplicating it for now - XXXMB | 547 * duplicating it for now - XXXMB |
503 */ | 548 */ |
504 PR_IMPLEMENT(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon) | 549 PR_IMPLEMENT(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon) |
505 { | 550 { |
506 pthread_t self = pthread_self(); | 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); |
507 if (pthread_equal(mon->owner, self)) | 557 if (pthread_equal(mon->owner, self)) |
508 return mon->entryCount; | 558 count = mon->entryCount; |
509 return 0; | 559 rv = pthread_mutex_unlock(&mon->lock); |
| 560 PR_ASSERT(0 == rv); |
| 561 return count; |
510 } | 562 } |
511 | 563 |
512 PR_IMPLEMENT(void) PR_AssertCurrentThreadInMonitor(PRMonitor *mon) | 564 PR_IMPLEMENT(void) PR_AssertCurrentThreadInMonitor(PRMonitor *mon) |
513 { | 565 { |
514 PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(&mon->lock); | 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 |
515 } | 576 } |
516 | 577 |
517 PR_IMPLEMENT(void) PR_EnterMonitor(PRMonitor *mon) | 578 PR_IMPLEMENT(void) PR_EnterMonitor(PRMonitor *mon) |
518 { | 579 { |
519 pthread_t self = pthread_self(); | 580 pthread_t self = pthread_self(); |
| 581 PRIntn rv; |
520 | 582 |
521 PR_ASSERT(mon != NULL); | 583 PR_ASSERT(mon != NULL); |
522 /* | 584 rv = pthread_mutex_lock(&mon->lock); |
523 * This is safe only if mon->owner (a pthread_t) can be | 585 PR_ASSERT(0 == rv); |
524 * read in one instruction. Perhaps mon->owner should be | 586 if (mon->entryCount != 0) |
525 * a "PRThread *"? | |
526 */ | |
527 if (!pthread_equal(mon->owner, self)) | |
528 { | 587 { |
529 PR_Lock(&mon->lock); | 588 if (pthread_equal(mon->owner, self)) |
530 /* and now I have the lock */ | 589 goto done; |
531 PR_ASSERT(0 == mon->entryCount); | 590 while (mon->entryCount != 0) |
532 PR_ASSERT(_PT_PTHREAD_THR_HANDLE_IS_INVALID(mon->owner)); | 591 { |
533 _PT_PTHREAD_COPY_THR_HANDLE(self, mon->owner); | 592 rv = pthread_cond_wait(&mon->entryCV, &mon->lock); |
| 593 PR_ASSERT(0 == rv); |
| 594 } |
534 } | 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: |
535 mon->entryCount += 1; | 602 mon->entryCount += 1; |
| 603 rv = pthread_mutex_unlock(&mon->lock); |
| 604 PR_ASSERT(0 == rv); |
536 } /* PR_EnterMonitor */ | 605 } /* PR_EnterMonitor */ |
537 | 606 |
538 PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon) | 607 PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon) |
539 { | 608 { |
540 pthread_t self = pthread_self(); | 609 pthread_t self = pthread_self(); |
| 610 PRIntn rv; |
| 611 PRBool notifyEntryWaiter = PR_FALSE; |
| 612 PRIntn notifyTimes = 0; |
541 | 613 |
542 PR_ASSERT(mon != NULL); | 614 PR_ASSERT(mon != NULL); |
543 /* The lock better be that - locked */ | 615 rv = pthread_mutex_lock(&mon->lock); |
544 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex)); | 616 PR_ASSERT(0 == rv); |
545 /* we'd better be the owner */ | 617 /* the entries should be > 0 and we'd better be the owner */ |
| 618 PR_ASSERT(mon->entryCount > 0); |
546 PR_ASSERT(pthread_equal(mon->owner, self)); | 619 PR_ASSERT(pthread_equal(mon->owner, self)); |
547 if (!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); |
548 return PR_FAILURE; | 624 return PR_FAILURE; |
| 625 } |
549 | 626 |
550 /* if it's locked and we have it, then the entries should be > 0 */ | |
551 PR_ASSERT(mon->entryCount > 0); | |
552 mon->entryCount -= 1; /* reduce by one */ | 627 mon->entryCount -= 1; /* reduce by one */ |
553 if (mon->entryCount == 0) | 628 if (mon->entryCount == 0) |
554 { | 629 { |
555 /* and if it transitioned to zero - unlock */ | 630 /* and if it transitioned to zero - notify an entry waiter */ |
556 _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); /* make the owner unknow
n */ | 631 /* make the owner unknown */ |
557 PR_Unlock(&mon->lock); | 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); |
558 } | 651 } |
559 return PR_SUCCESS; | 652 return PR_SUCCESS; |
560 } /* PR_ExitMonitor */ | 653 } /* PR_ExitMonitor */ |
561 | 654 |
562 PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime timeout) | 655 PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime timeout) |
563 { | 656 { |
564 PRStatus rv; | 657 PRStatus rv; |
565 PRInt16 saved_entries; | 658 PRUint32 saved_entries; |
566 pthread_t saved_owner; | 659 pthread_t saved_owner; |
567 | 660 |
568 PR_ASSERT(mon != NULL); | 661 PR_ASSERT(mon != NULL); |
569 /* we'd better be locked */ | 662 rv = pthread_mutex_lock(&mon->lock); |
570 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex)); | 663 PR_ASSERT(0 == rv); |
571 /* and the entries better be positive */ | 664 /* the entries better be positive */ |
572 PR_ASSERT(mon->entryCount > 0); | 665 PR_ASSERT(mon->entryCount > 0); |
573 /* and it better be by us */ | 666 /* and it better be owned by us */ |
574 PR_ASSERT(pthread_equal(mon->owner, pthread_self())); | 667 PR_ASSERT(pthread_equal(mon->owner, pthread_self())); |
575 | 668 |
576 /* tuck these away 'till later */ | 669 /* tuck these away 'till later */ |
577 saved_entries = mon->entryCount; | 670 saved_entries = mon->entryCount; |
578 mon->entryCount = 0; | 671 mon->entryCount = 0; |
579 _PT_PTHREAD_COPY_THR_HANDLE(mon->owner, saved_owner); | 672 _PT_PTHREAD_COPY_THR_HANDLE(mon->owner, saved_owner); |
580 _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); | 673 _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); |
581 | 674 /* |
582 rv = PR_WaitCondVar(mon->cvar, timeout); | 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); |
583 | 689 |
584 /* reinstate the intresting information */ | 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 */ |
585 mon->entryCount = saved_entries; | 703 mon->entryCount = saved_entries; |
586 _PT_PTHREAD_COPY_THR_HANDLE(saved_owner, mon->owner); | 704 _PT_PTHREAD_COPY_THR_HANDLE(saved_owner, mon->owner); |
587 | 705 |
| 706 rv = pthread_mutex_unlock(&mon->lock); |
| 707 PR_ASSERT(0 == rv); |
588 return rv; | 708 return rv; |
589 } /* PR_Wait */ | 709 } /* PR_Wait */ |
590 | 710 |
591 PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon) | 711 PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon) |
592 { | 712 { |
593 PR_ASSERT(NULL != mon); | 713 pt_PostNotifyToMonitor(mon, PR_FALSE); |
594 /* we'd better be locked */ | |
595 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex)); | |
596 /* and the entries better be positive */ | |
597 PR_ASSERT(mon->entryCount > 0); | |
598 /* and it better be by us */ | |
599 PR_ASSERT(pthread_equal(mon->owner, pthread_self())); | |
600 | |
601 pt_PostNotifyToCvar(mon->cvar, PR_FALSE); | |
602 | |
603 return PR_SUCCESS; | 714 return PR_SUCCESS; |
604 } /* PR_Notify */ | 715 } /* PR_Notify */ |
605 | 716 |
606 PR_IMPLEMENT(PRStatus) PR_NotifyAll(PRMonitor *mon) | 717 PR_IMPLEMENT(PRStatus) PR_NotifyAll(PRMonitor *mon) |
607 { | 718 { |
608 PR_ASSERT(mon != NULL); | 719 pt_PostNotifyToMonitor(mon, PR_TRUE); |
609 /* we'd better be locked */ | |
610 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex)); | |
611 /* and the entries better be positive */ | |
612 PR_ASSERT(mon->entryCount > 0); | |
613 /* and it better be by us */ | |
614 PR_ASSERT(pthread_equal(mon->owner, pthread_self())); | |
615 | |
616 pt_PostNotifyToCvar(mon->cvar, PR_TRUE); | |
617 | |
618 return PR_SUCCESS; | 720 return PR_SUCCESS; |
619 } /* PR_NotifyAll */ | 721 } /* PR_NotifyAll */ |
620 | 722 |
621 /**************************************************************/ | 723 /**************************************************************/ |
622 /**************************************************************/ | 724 /**************************************************************/ |
623 /**************************SEMAPHORES**************************/ | 725 /**************************SEMAPHORES**************************/ |
624 /**************************************************************/ | 726 /**************************************************************/ |
625 /**************************************************************/ | 727 /**************************************************************/ |
626 PR_IMPLEMENT(void) PR_PostSem(PRSemaphore *semaphore) | 728 PR_IMPLEMENT(void) PR_PostSem(PRSemaphore *semaphore) |
627 { | 729 { |
(...skipping 501 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1129 int rv; | 1231 int rv; |
1130 PR_ASSERT(cvar != NULL); | 1232 PR_ASSERT(cvar != NULL); |
1131 rv = pthread_cond_broadcast(&cvar->cv); | 1233 rv = pthread_cond_broadcast(&cvar->cv); |
1132 PR_ASSERT(0 == rv); | 1234 PR_ASSERT(0 == rv); |
1133 return PR_SUCCESS; | 1235 return PR_SUCCESS; |
1134 } /* PRP_NakedBroadcast */ | 1236 } /* PRP_NakedBroadcast */ |
1135 | 1237 |
1136 #endif /* defined(_PR_PTHREADS) */ | 1238 #endif /* defined(_PR_PTHREADS) */ |
1137 | 1239 |
1138 /* ptsynch.c */ | 1240 /* ptsynch.c */ |
OLD | NEW |