home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / pthreads / ptsynch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  21.4 KB  |  703 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /*
  20. ** File:            ptsynch.c
  21. ** Descritpion:        Implemenation for thread synchronization using pthreads
  22. ** Exports:            prlock.h, prcvar.h, prmon.h, prcmon.h
  23. */
  24.  
  25. #if defined(_PR_PTHREADS)
  26.  
  27. #include "primpl.h"
  28. #include "obsolete/prsem.h"
  29.  
  30. #include <string.h>
  31. #include <pthread.h>
  32. #include <sys/time.h>
  33.  
  34. static pthread_condattr_t _pt_cvar_attr;
  35.  
  36. #if defined(DEBUG) && defined(_PR_DCETHREADS)
  37. static pthread_t pt_zero_tid;  /* a null pthread_t (pthread_t is a struct
  38.                                 * in DCE threads) to compare with */
  39. #endif
  40.  
  41. /**************************************************************/
  42. /**************************************************************/
  43. /*****************************LOCKS****************************/
  44. /**************************************************************/
  45. /**************************************************************/
  46.  
  47. void _PR_InitLocks(void)
  48. {
  49.     int rv = PTHREAD_CONDATTR_INIT(&_pt_cvar_attr); 
  50.     PR_ASSERT(0 == rv);
  51.     _PR_MD_INIT_LOCKS();
  52. }
  53.  
  54. static void pt_PostNotifies(PRLock *lock, PRBool unlock)
  55. {
  56.     PRIntn index, rv;
  57.     _PT_Notified post;
  58.     _PT_Notified *notified, *prev = NULL;
  59.     /*
  60.      * Time to actually notify any conditions that were affected
  61.      * while the lock was held. Get a copy of the list that's in
  62.      * the lock structure and then zero the original. If it's
  63.      * linked to other such structures, we own that storage.
  64.      */
  65.     post = lock->notified;  /* a safe copy; we own the lock */
  66.  
  67. #if defined(DEBUG)
  68.     memset(&lock->notified, 0, sizeof(_PT_Notified));  /* reset */
  69. #else
  70.     lock->notified.length = 0;  /* these are really sufficient */
  71.     lock->notified.link = NULL;
  72. #endif
  73.  
  74.     /* should (may) we release lock before notifying? */
  75.     if (unlock)
  76.     {
  77.         rv = pthread_mutex_unlock(&lock->mutex);
  78.         PR_ASSERT(0 == rv);
  79.     }
  80.  
  81.     notified = &post;  /* this is where we start */
  82.     do
  83.     {
  84.         for (index = 0; index < notified->length; ++index)
  85.         {
  86.             PR_ASSERT(NULL != notified->cv[index].cv);
  87.             PR_ASSERT(0 != notified->cv[index].times);
  88.             if (-1 == notified->cv[index].times)
  89.             {
  90.                 rv = pthread_cond_broadcast(¬ified->cv[index].cv->cv);
  91.                 PR_ASSERT(0 == rv);
  92.             }
  93.             else
  94.             {
  95.                 while (notified->cv[index].times-- > 0)
  96.                 {
  97.                     rv = pthread_cond_signal(¬ified->cv[index].cv->cv);
  98.                     PR_ASSERT(0 == rv);
  99.                 }
  100.             }
  101.         }
  102.         prev = notified;
  103.         notified = notified->link;
  104.         if (&post != prev) PR_DELETE(prev);
  105.     } while (NULL != notified);
  106. }  /* pt_PostNotifies */
  107.  
  108. PR_IMPLEMENT(PRLock*) PR_NewLock(void)
  109. {
  110.     PRIntn rv;
  111.     PRLock *lock;
  112.  
  113.     if (!_pr_initialized) _PR_ImplicitInitialization();
  114.  
  115.     lock = PR_NEWZAP(PRLock);
  116.     if (lock != NULL)
  117.     {
  118.         pthread_mutexattr_t mattr;
  119.         rv = PTHREAD_MUTEXATTR_INIT(&mattr); 
  120.         PR_ASSERT(0 == rv);
  121.         rv = PTHREAD_MUTEX_INIT(lock->mutex, mattr); 
  122.         PR_ASSERT(0 == rv);
  123.         rv = PTHREAD_MUTEXATTR_DESTROY(&mattr); 
  124.         PR_ASSERT(0 == rv);
  125.     }
  126.     return lock;
  127. }  /* PR_NewLock */
  128.  
  129. PR_IMPLEMENT(void) PR_DestroyLock(PRLock *lock)
  130. {
  131.     PRIntn rv;
  132.     PR_ASSERT(NULL != lock);
  133.     PR_ASSERT(PTHREAD_THR_HANDLE_IS_ZERO(lock->owner));
  134.     PR_ASSERT(0 == lock->notified.length);
  135.     PR_ASSERT(NULL == lock->notified.link);
  136.     rv = pthread_mutex_destroy(&lock->mutex);
  137.     PR_ASSERT(0 == rv);
  138. #if defined(DEBUG)
  139.     memset(lock, 0xaf, sizeof(PRLock));
  140. #endif
  141.     PR_DELETE(lock);
  142. }  /* PR_DestroyLock */
  143.  
  144. PR_IMPLEMENT(void) PR_Lock(PRLock *lock)
  145. {
  146.     PRIntn rv;
  147.     PR_ASSERT(lock != NULL);
  148.     rv = pthread_mutex_lock(&lock->mutex);
  149.     PR_ASSERT(0 == rv);
  150.     PR_ASSERT(0 == lock->notified.length);
  151.     PR_ASSERT(NULL == lock->notified.link);
  152.     PR_ASSERT(PTHREAD_THR_HANDLE_IS_ZERO(lock->owner));
  153.     PTHREAD_COPY_THR_HANDLE(pthread_self(), lock->owner);
  154. }  /* PR_Lock */
  155.  
  156. PR_IMPLEMENT(PRStatus) PR_Unlock(PRLock *lock)
  157. {
  158.     PRIntn rv;
  159.  
  160.     PR_ASSERT(lock != NULL);
  161.     PR_ASSERT(PTHREAD_MUTEX_IS_LOCKED(lock->mutex));
  162.     PR_ASSERT(pthread_equal(lock->owner, pthread_self()));
  163.  
  164.     if (!pthread_equal(lock->owner, pthread_self()))
  165.         return PR_FAILURE;
  166.  
  167.     PTHREAD_ZERO_THR_HANDLE(lock->owner);
  168.     if (0 == lock->notified.length)  /* shortcut */
  169.     {
  170.         rv = pthread_mutex_unlock(&lock->mutex);
  171.         PR_ASSERT(0 == rv);
  172.     }
  173.     else pt_PostNotifies(lock, PR_TRUE);
  174.  
  175.     return PR_SUCCESS;
  176. }  /* PR_Unlock */
  177.  
  178.  
  179. /**************************************************************/
  180. /**************************************************************/
  181. /***************************CONDITIONS*************************/
  182. /**************************************************************/
  183. /**************************************************************/
  184.  
  185.  
  186. /*
  187.  * This code is used to compute the absolute time for the wakeup.
  188.  * It's moderately ugly, so it's defined here and called in a
  189.  * couple of places.
  190.  */
  191. #define PT_NANOPERMICRO 1000UL
  192. #define PT_BILLION 1000000000UL
  193.  
  194. static PRIntn pt_TimedWait(
  195.     pthread_cond_t *cv, pthread_mutex_t *ml, PRIntervalTime timeout)
  196. {
  197.     int rv;
  198.     struct timeval now;
  199.     struct timespec tmo;
  200.     PRUint32 ticks = PR_TicksPerSecond();
  201.  
  202.     tmo.tv_sec = (PRInt32)(timeout / ticks);
  203.     tmo.tv_nsec = (PRInt32)(timeout - (tmo.tv_sec * ticks));
  204.     tmo.tv_nsec = (PRInt32)PR_IntervalToMicroseconds(PT_NANOPERMICRO * tmo.tv_nsec);
  205.  
  206.     /* pthreads wants this in absolute time, off we go ... */
  207. #if defined(SOLARIS) && defined(_SVID_GETTOD)
  208.     (void)gettimeofday(&now);
  209. #else
  210.     (void)gettimeofday(&now, NULL);
  211. #endif
  212.     /* that one's usecs, this one's nsecs - grrrr! */
  213.     tmo.tv_sec += now.tv_sec;
  214.     tmo.tv_nsec += (PT_NANOPERMICRO * now.tv_usec);
  215.     tmo.tv_sec += tmo.tv_nsec / PT_BILLION;
  216.     tmo.tv_nsec %= PT_BILLION;
  217.  
  218.     rv = pthread_cond_timedwait(cv, ml, &tmo);
  219.  
  220.     /* NSPR doesn't report timeouts */
  221. #ifdef _PR_DCETHREADS
  222.     return (rv == -1 && errno == EAGAIN) ? 0 : rv;
  223. #else
  224.     return (rv == ETIMEDOUT) ? 0 : rv;
  225. #endif
  226. }  /* pt_TimedWait */
  227.  
  228.  
  229. /*
  230.  * Notifies just get posted to the to the protecting mutex. The
  231.  * actual notification is done when the lock is released so that
  232.  * MP systems don't contend for a lock that they can't have.
  233.  */
  234. static void pt_PostNotifyToCvar(PRCondVar *cvar, PRBool broadcast)
  235. {
  236.     PRIntn index = 0;
  237.     _PT_Notified *notified = &cvar->lock->notified;
  238.  
  239.     PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self()));
  240.     PR_ASSERT(PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex));
  241.  
  242.     while (1)
  243.     {
  244.         for (index = 0; index < notified->length; ++index)
  245.         {
  246.             if (notified->cv[index].cv == cvar)
  247.             {
  248.                 if (broadcast)
  249.                     notified->cv[index].times = -1;
  250.                 else if (-1 != notified->cv[index].times)
  251.                     notified->cv[index].times += 1;
  252.                 goto finished;  /* we're finished */
  253.             }
  254.         }
  255.         /* if not full, enter new CV in this array */
  256.         if (notified->length < PT_CV_NOTIFIED_LENGTH) break;
  257.  
  258.         /* if there's no link, create an empty array and link it */
  259.         if (NULL == notified->link)
  260.             notified->link = PR_NEWZAP(_PT_Notified);
  261.         notified = notified->link;
  262.     }
  263.  
  264.     /* A brand new entry in the array */
  265.     notified->cv[index].times = (broadcast) ? -1 : 1;
  266.     notified->cv[index].cv = cvar;
  267.     notified->length += 1;
  268.  
  269. finished:
  270.     PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self()));
  271. }  /* pt_PostNotifyToCvar */
  272.  
  273. PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock *lock)
  274. {
  275.     PRCondVar *cv = PR_NEW(PRCondVar);
  276.     PR_ASSERT(lock != NULL);
  277.     if (cv != NULL)
  278.     {
  279.         int rv = PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr); 
  280.         PR_ASSERT(0 == rv);
  281.         cv->lock = lock;
  282.     }
  283.     return cv;
  284. }  /* PR_NewCondVar */
  285.  
  286. PR_IMPLEMENT(void) PR_DestroyCondVar(PRCondVar *cvar)
  287. {
  288.     int rv;
  289.     rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv);
  290. #if defined(DEBUG)
  291.         memset(cvar, 0xaf, sizeof(PRCondVar));
  292. #endif
  293.     PR_DELETE(cvar);
  294. }  /* PR_DestroyCondVar */
  295.  
  296. PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout)
  297. {
  298.     PRIntn rv;
  299.     PRThread *thred = PR_CurrentThread();
  300.  
  301.     PR_ASSERT(cvar != NULL);
  302.     /* We'd better be locked */
  303.     PR_ASSERT(PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex));
  304.     /* and it better be by us */
  305.     PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self()));
  306.  
  307.     if (thred->state & PT_THREAD_ABORTED) goto aborted;
  308.  
  309.     /*
  310.      * The thread waiting is used for PR_Interrupt
  311.      */
  312.     thred->waiting = cvar;  /* this is where we're waiting */
  313.  
  314.     /*
  315.      * If we have pending notifies, post them now.
  316.      *
  317.      * This is not optimal. We're going to post these notifies
  318.      * while we're holding the lock. That means on MP systems
  319.      * that they are going to collide for the lock that we will
  320.      * hold until we actually wait.
  321.      */
  322.     if (0 != cvar->lock->notified.length)
  323.         pt_PostNotifies(cvar->lock, PR_FALSE);
  324.  
  325.     /*
  326.      * We're surrendering the lock, so clear out the owner field.
  327.      */
  328.     PTHREAD_ZERO_THR_HANDLE(cvar->lock->owner);
  329.  
  330.     if (timeout == PR_INTERVAL_NO_TIMEOUT)
  331.         rv = pthread_cond_wait(&cvar->cv, &cvar->lock->mutex);
  332.     else
  333.         rv = pt_TimedWait(&cvar->cv, &cvar->lock->mutex, timeout);
  334.  
  335.     /* We just got the lock back - this better be empty */
  336.     PR_ASSERT(PTHREAD_THR_HANDLE_IS_ZERO(cvar->lock->owner));
  337.     PTHREAD_COPY_THR_HANDLE(pthread_self(), cvar->lock->owner);
  338.  
  339.     PR_ASSERT(0 == cvar->lock->notified.length);
  340.     thred->waiting = NULL;  /* and now we're not */
  341.     if (thred->state & PT_THREAD_ABORTED) goto aborted;
  342.     return (rv == 0) ? PR_SUCCESS : PR_FAILURE;
  343.  
  344. aborted:
  345.     PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  346.     thred->state &= ~PT_THREAD_ABORTED;
  347.     return PR_FAILURE;
  348. }  /* PR_WaitCondVar */
  349.  
  350. PR_IMPLEMENT(PRStatus) PR_NotifyCondVar(PRCondVar *cvar)
  351. {
  352.     PR_ASSERT(cvar != NULL);   
  353.     pt_PostNotifyToCvar(cvar, PR_FALSE);
  354.     return PR_SUCCESS;
  355. }  /* PR_NotifyCondVar */
  356.  
  357. PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar)
  358. {
  359.     PR_ASSERT(cvar != NULL);
  360.     pt_PostNotifyToCvar(cvar, PR_TRUE);
  361.     return PR_SUCCESS;
  362. }  /* PR_NotifyAllCondVar */
  363.  
  364. /**************************************************************/
  365. /**************************************************************/
  366. /***************************MONITORS***************************/
  367. /**************************************************************/
  368. /**************************************************************/
  369.  
  370. PR_IMPLEMENT(PRMonitor*) PR_NewMonitor(void)
  371. {
  372.     PRMonitor *ml;
  373.  
  374.     if (!_pr_initialized) _PR_ImplicitInitialization();
  375.  
  376.     ml = PR_NEWZAP(PRMonitor);
  377.     if (ml != NULL)
  378.     {
  379.         int rv;
  380.         pthread_mutexattr_t mattr;
  381.         rv = PTHREAD_MUTEXATTR_INIT(&mattr); 
  382.         PR_ASSERT(0 == rv);
  383.         rv += PTHREAD_MUTEX_INIT(ml->lock.mutex, mattr); 
  384.         PR_ASSERT(0 == rv);
  385.         rv += PTHREAD_MUTEXATTR_DESTROY(&mattr); 
  386.         PR_ASSERT(0 == rv);
  387.  
  388.         rv += PTHREAD_COND_INIT(ml->cvar.cv, _pt_cvar_attr); 
  389.         PR_ASSERT(0 == rv);
  390.         ml->entryCount = 0;
  391.         ml->cvar.lock = &ml->lock;
  392.         if (0 != rv)
  393.         {
  394.             PR_DELETE(ml);
  395.             ml = NULL;
  396.         }
  397.     }
  398.     return ml;
  399. }  /* PR_NewMonitor */
  400.  
  401. PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name)
  402. {
  403.     PRMonitor* mon = PR_NewMonitor();
  404.     mon->name = name;
  405.     return mon;
  406. }
  407.  
  408. PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor *mon)
  409. {
  410.     int rv;
  411.     PR_ASSERT(mon != NULL);
  412.     rv = pthread_cond_destroy(&mon->cvar.cv); PR_ASSERT(0 == rv);
  413.     rv = pthread_mutex_destroy(&mon->lock.mutex); PR_ASSERT(0 == rv);
  414. #if defined(DEBUG)
  415.         memset(mon, 0xaf, sizeof(PRMonitor));
  416. #endif
  417.     PR_DELETE(mon);    
  418. }  /* PR_DestroyMonitor */
  419.  
  420.  
  421. /* The GC uses this; it is quite arguably a bad interface.  I'm just 
  422.  * duplicating it for now - XXXMB
  423.  */
  424. PR_IMPLEMENT(PRInt32) PR_GetMonitorEntryCount(PRMonitor *mon)
  425. {
  426.     pthread_t self = pthread_self();
  427.     if (pthread_equal(mon->owner, self))
  428.         return mon->entryCount;
  429.     return 0;
  430. }
  431.  
  432. PR_IMPLEMENT(void) PR_EnterMonitor(PRMonitor *mon)
  433. {
  434.     int rv;
  435.     pthread_t self = pthread_self();
  436.  
  437.     PR_ASSERT(mon != NULL);
  438.     rv = pthread_mutex_trylock(&mon->lock.mutex);
  439. #ifdef _PR_DCETHREADS
  440.     if (1 == rv)
  441. #else
  442.     if (0 == rv)
  443. #endif
  444.     {
  445.         /* I now have the lock - I can play in the sandbox */
  446.         /* could/should/would not have gotten lock if entries != 0 */
  447.         PR_ASSERT(0 == mon->entryCount);
  448.         PR_ASSERT(PTHREAD_THR_HANDLE_IS_ZERO(mon->lock.owner));
  449.         PTHREAD_COPY_THR_HANDLE(pthread_self(), mon->lock.owner);
  450.         PTHREAD_COPY_THR_HANDLE(self, mon->owner);
  451.     }
  452.     else
  453.     {
  454.         PR_ASSERT(PT_TRYLOCK_BUSY == rv);  /* and if it isn't? */
  455.         /* somebody has it locked - is it me? */
  456.         if (!pthread_equal(mon->owner, self))
  457.         {
  458.             /* it's not me - this should block */
  459.             PR_Lock(&mon->lock);
  460.             /* and now I have the lock */
  461.             PR_ASSERT(0 == mon->entryCount);
  462.             PTHREAD_COPY_THR_HANDLE(self, mon->owner);
  463.         }
  464.     }
  465.     mon->entryCount += 1;
  466. }  /* PR_EnterMonitor */
  467.  
  468. PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon)
  469. {
  470.     pthread_t self = pthread_self();
  471.  
  472.     PR_ASSERT(mon != NULL);
  473.     /* The lock better be that - locked */
  474.     PR_ASSERT(PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex));
  475.     /* we'd better be the owner */
  476.     PR_ASSERT(pthread_equal(mon->owner, self));
  477.     if (!pthread_equal(mon->owner, self))
  478.         return PR_FAILURE;
  479.  
  480.     /* if it's locked and we have it, then the entries should be > 0 */
  481.     PR_ASSERT(mon->entryCount > 0);
  482.     mon->entryCount -= 1;  /* reduce by one */
  483.     if (mon->entryCount == 0)
  484.     {
  485.         /* and if it transitioned to zero - unlock */
  486.         PTHREAD_ZERO_THR_HANDLE(mon->owner);  /* make the owner unknown */
  487.         PR_Unlock(&mon->lock);
  488.     }
  489.     return PR_SUCCESS;
  490. }  /* PR_ExitMonitor */
  491.  
  492. PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime timeout)
  493. {
  494.     PRStatus rv;
  495.     PRInt16 saved_entries;
  496.     pthread_t saved_owner;
  497.  
  498.     PR_ASSERT(mon != NULL);
  499.     /* we'd better be locked */
  500.     PR_ASSERT(PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex));
  501.     /* and the entries better be positive */
  502.     PR_ASSERT(mon->entryCount > 0);
  503.     /* and it better be by us */
  504.     PR_ASSERT(pthread_equal(mon->owner, pthread_self()));
  505.  
  506.     /* tuck these away 'till later */
  507.     saved_entries = mon->entryCount; 
  508.     mon->entryCount = 0;
  509.     PTHREAD_COPY_THR_HANDLE(mon->owner, saved_owner);
  510.     PTHREAD_ZERO_THR_HANDLE(mon->owner);
  511.     
  512.     rv = PR_WaitCondVar(&mon->cvar, timeout);
  513.  
  514.     /* reinstate the intresting information */
  515.     mon->entryCount = saved_entries;
  516.     PTHREAD_COPY_THR_HANDLE(saved_owner, mon->owner);
  517.  
  518.     return rv;
  519. }  /* PR_Wait */
  520.  
  521. PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon)
  522. {
  523.     PR_ASSERT(NULL != mon);
  524.     /* we'd better be locked */
  525.     PR_ASSERT(PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex));
  526.     /* and the entries better be positive */
  527.     PR_ASSERT(mon->entryCount > 0);
  528.     /* and it better be by us */
  529.     PR_ASSERT(pthread_equal(mon->owner, pthread_self()));
  530.  
  531.     pt_PostNotifyToCvar(&mon->cvar, PR_FALSE);
  532.  
  533.     return PR_SUCCESS;
  534. }  /* PR_Notify */
  535.  
  536. PR_IMPLEMENT(PRStatus) PR_NotifyAll(PRMonitor *mon)
  537. {
  538.     PR_ASSERT(mon != NULL);
  539.     /* we'd better be locked */
  540.     PR_ASSERT(PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex));
  541.     /* and the entries better be positive */
  542.     PR_ASSERT(mon->entryCount > 0);
  543.     /* and it better be by us */
  544.     PR_ASSERT(pthread_equal(mon->owner, pthread_self()));
  545.  
  546.     pt_PostNotifyToCvar(&mon->cvar, PR_TRUE);
  547.  
  548.     return PR_SUCCESS;
  549. }  /* PR_NotifyAll */
  550.  
  551. /**************************************************************/
  552. /**************************************************************/
  553. /**************************SEMAPHORES**************************/
  554. /**************************************************************/
  555. /**************************************************************/
  556. PR_IMPLEMENT(void) PR_PostSem(PRSemaphore *semaphore)
  557. {
  558.     static PRBool unwarned = PR_TRUE;
  559.     if (unwarned) unwarned = _PR_Obsolete(
  560.         "PR_PostSem", "locks & condition variables");
  561.     PR_Lock(semaphore->cvar->lock);
  562.     PR_NotifyCondVar(semaphore->cvar);
  563.     semaphore->count += 1;
  564.     PR_Unlock(semaphore->cvar->lock);
  565. }  /* PR_PostSem */
  566.  
  567. PR_IMPLEMENT(PRStatus) PR_WaitSem(PRSemaphore *semaphore)
  568. {
  569.     PRStatus status = PR_SUCCESS;
  570.     static PRBool unwarned = PR_TRUE;
  571.     if (unwarned) unwarned = _PR_Obsolete(
  572.         "PR_WaitSem", "locks & condition variables");
  573.     PR_Lock(semaphore->cvar->lock);
  574.     while ((semaphore->count == 0) && (PR_SUCCESS == status))
  575.         status = PR_WaitCondVar(semaphore->cvar, PR_INTERVAL_NO_TIMEOUT);
  576.     if (PR_SUCCESS == status) semaphore->count -= 1;
  577.     PR_Unlock(semaphore->cvar->lock);
  578.     return status;
  579. }  /* PR_WaitSem */
  580.  
  581. PR_IMPLEMENT(void) PR_DestroySem(PRSemaphore *semaphore)
  582. {
  583.     static PRBool unwarned = PR_TRUE;
  584.     if (unwarned) unwarned = _PR_Obsolete(
  585.         "PR_DestroySem", "locks & condition variables");
  586.     PR_DestroyLock(semaphore->cvar->lock);
  587.     PR_DestroyCondVar(semaphore->cvar);
  588.     PR_DELETE(semaphore);
  589. }  /* PR_DestroySem */
  590.  
  591. PR_IMPLEMENT(PRSemaphore*) PR_NewSem(PRUintn value)
  592. {
  593.     PRSemaphore *semaphore;
  594.     static PRBool unwarned = PR_TRUE;
  595.     if (!_pr_initialized) _PR_ImplicitInitialization();
  596.  
  597.     if (unwarned) unwarned = _PR_Obsolete(
  598.         "PR_NewSem", "locks & condition variables");
  599.  
  600.     semaphore = PR_NEWZAP(PRSemaphore);
  601.     if (NULL != semaphore)
  602.     {
  603.         PRLock *lock = PR_NewLock();
  604.         if (NULL != lock)
  605.         {
  606.             semaphore->cvar = PR_NewCondVar(lock);
  607.             if (NULL != semaphore->cvar)
  608.             {
  609.                 semaphore->count = value;
  610.                 return semaphore;
  611.             }
  612.             PR_DestroyLock(lock);
  613.         }
  614.         PR_DELETE(semaphore);
  615.     }
  616.     return NULL;
  617. }
  618.  
  619. /**************************************************************/
  620. /**************************************************************/
  621. /******************ROUTINES FOR DCE EMULATION******************/
  622. /**************************************************************/
  623. /**************************************************************/
  624.  
  625. #include "prpdce.h"
  626.  
  627. PR_IMPLEMENT(PRStatus) PRP_TryLock(PRLock *lock)
  628. {
  629.     PRIntn rv = pthread_mutex_trylock(&lock->mutex);
  630.     if (rv == PT_TRYLOCK_SUCCESS)
  631.     {
  632.         PR_ASSERT(PTHREAD_THR_HANDLE_IS_ZERO(lock->owner));
  633.         PTHREAD_COPY_THR_HANDLE(pthread_self(), lock->owner); 
  634.     }
  635.     else
  636.         PR_ASSERT(!PTHREAD_THR_HANDLE_IS_ZERO(lock->owner));
  637.     /* XXX set error code? */
  638.     return (PT_TRYLOCK_SUCCESS == rv) ? PR_SUCCESS : PR_FAILURE;
  639. }  /* PRP_TryLock */
  640.  
  641. PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar()
  642. {
  643.     PRCondVar *cv;
  644.  
  645.     if (!_pr_initialized) _PR_ImplicitInitialization();
  646.  
  647.     cv = PR_NEW(PRCondVar);
  648.     if (cv != NULL)
  649.     {
  650.         int rv;
  651.         rv = PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr); 
  652.         PR_ASSERT(0 == rv);
  653.         cv->lock = _PR_NAKED_CV_LOCK;
  654.     }
  655.     return cv;
  656. }  /* PRP_NewNakedCondVar */
  657.  
  658. PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar *cvar)
  659. {
  660.     int rv;
  661.     rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv);
  662. #if defined(DEBUG)
  663.         memset(cvar, 0xaf, sizeof(PRCondVar));
  664. #endif
  665.     PR_DELETE(cvar);
  666. }  /* PRP_DestroyNakedCondVar */
  667.  
  668. PR_IMPLEMENT(PRStatus) PRP_NakedWait(
  669.     PRCondVar *cvar, PRLock *ml, PRIntervalTime timeout)
  670. {
  671.     PRIntn rv;
  672.     PR_ASSERT(cvar != NULL);
  673.     /* XXX do we really want to assert this in a naked wait? */
  674.     PR_ASSERT(PTHREAD_MUTEX_IS_LOCKED(ml->mutex));
  675.     if (timeout == PR_INTERVAL_NO_TIMEOUT)
  676.         rv = pthread_cond_wait(&cvar->cv, &ml->mutex);
  677.     else
  678.         rv = pt_TimedWait(&cvar->cv, &ml->mutex, timeout);
  679.     return (rv == 0) ? PR_SUCCESS : PR_FAILURE;
  680. }  /* PRP_NakedWait */
  681.  
  682. PR_IMPLEMENT(PRStatus) PRP_NakedNotify(PRCondVar *cvar)
  683. {
  684.     int rv;
  685.     PR_ASSERT(cvar != NULL);
  686.     rv = pthread_cond_signal(&cvar->cv);
  687.     PR_ASSERT(0 == rv);
  688.     return PR_SUCCESS;
  689. }  /* PRP_NakedNotify */
  690.  
  691. PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar)
  692. {
  693.     int rv;
  694.     PR_ASSERT(cvar != NULL);
  695.     rv = pthread_cond_broadcast(&cvar->cv);
  696.     PR_ASSERT(0 == rv);
  697.     return PR_SUCCESS;
  698. }  /* PRP_NakedBroadcast */
  699.  
  700. #endif  /* defined(_PR_PTHREADS) */
  701.  
  702. /* ptsynch.c */
  703.