home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / threads / prmon.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  5.7 KB  |  203 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. #include "primpl.h"
  20.  
  21. /************************************************************************/
  22.  
  23. /*
  24. ** Create a new monitor.
  25. */
  26. PR_IMPLEMENT(PRMonitor*) PR_NewMonitor()
  27. {
  28.     PRMonitor *mon;
  29.     PRCondVar *cvar;
  30.     PRLock *lock;
  31.  
  32.     mon = PR_NEWZAP(PRMonitor);
  33.     if (mon) {
  34.         lock = PR_NewLock();
  35.         if (!lock) {
  36.             PR_DELETE(mon);
  37.             return 0;
  38.         }
  39.  
  40.         cvar = PR_NewCondVar(lock);
  41.         if (!cvar) {
  42.             PR_DestroyLock(lock);
  43.             PR_DELETE(mon);
  44.             return 0;
  45.         }
  46.         mon->cvar = cvar;
  47.     mon->name = NULL;
  48.     }
  49.     return mon;
  50. }
  51.  
  52. PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name)
  53. {
  54.     PRMonitor* mon = PR_NewMonitor();
  55.     mon->name = name;
  56.     return mon;
  57. }
  58.  
  59. /*
  60. ** Destroy a monitor. There must be no thread waiting on the monitor's
  61. ** condition variable. The caller is responsible for guaranteeing that the
  62. ** monitor is no longer in use.
  63. */
  64. PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor *mon)
  65. {
  66.     PR_DestroyLock(mon->cvar->lock);
  67.     PR_DestroyCondVar(mon->cvar);
  68.     PR_DELETE(mon);
  69. }
  70.  
  71. /*
  72. ** Enter the lock associated with the monitor.
  73. */
  74. PR_IMPLEMENT(void) PR_EnterMonitor(PRMonitor *mon)
  75. {
  76.     if (mon->cvar->lock->owner == _PR_MD_CURRENT_THREAD()) {
  77.         mon->entryCount++;
  78.     } else {
  79.         PR_Lock(mon->cvar->lock);
  80.         mon->entryCount = 1;
  81.     }
  82. }
  83.  
  84. /*
  85. ** Test and then enter the lock associated with the monitor if it's not
  86. ** already entered by some other thread. Return PR_FALSE if some other
  87. ** thread owned the lock at the time of the call.
  88. */
  89. PR_IMPLEMENT(PRBool) PR_TestAndEnterMonitor(PRMonitor *mon)
  90. {
  91.     if (mon->cvar->lock->owner == _PR_MD_CURRENT_THREAD()) {
  92.         mon->entryCount++;
  93.         return PR_TRUE;
  94.     } else {
  95.         if (PR_TestAndLock(mon->cvar->lock)) {
  96.             mon->entryCount = 1;
  97.                 return PR_TRUE;
  98.         }
  99.     }
  100.     return PR_FALSE;
  101. }
  102.  
  103. /*
  104. ** Exit the lock associated with the monitor once.
  105. */
  106. PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon)
  107. {
  108.     if (mon->cvar->lock->owner != _PR_MD_CURRENT_THREAD()) {
  109.         return PR_FAILURE;
  110.     }
  111.     if (--mon->entryCount == 0) {
  112.         return PR_Unlock(mon->cvar->lock);
  113.     }
  114.     return PR_SUCCESS;
  115. }
  116.  
  117. /*
  118. ** Return the number of times that the current thread has entered the
  119. ** lock. Returns zero if the current thread has not entered the lock.
  120. */
  121. PR_IMPLEMENT(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon)
  122. {
  123.     return (mon->cvar->lock->owner == _PR_MD_CURRENT_THREAD()) ?
  124.         mon->entryCount : 0;
  125. }
  126.  
  127. /*
  128. ** Wait for a notify on the condition variable. Sleep for "ticks" amount
  129. ** of time (if "tick" is 0 then the sleep is indefinite). While
  130. ** the thread is waiting it exits the monitors lock (as if it called
  131. ** PR_ExitMonitor as many times as it had called PR_EnterMonitor).  When
  132. ** the wait has finished the thread regains control of the monitors lock
  133. ** with the same entry count as before the wait began.
  134. **
  135. ** The thread waiting on the monitor will be resumed when the monitor is
  136. ** notified (assuming the thread is the next in line to receive the
  137. ** notify) or when the "ticks" elapses.
  138. **
  139. ** Returns PR_FAILURE if the caller has not locked the lock associated
  140. ** with the condition variable.
  141. ** This routine can return PR_PENDING_INTERRUPT if the waiting thread 
  142. ** has been interrupted.
  143. */
  144. PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime ticks)
  145. {
  146.     PRUintn entryCount;
  147.     PRStatus status;
  148.     PRThread *me = _PR_MD_CURRENT_THREAD();
  149.  
  150.     if (mon->cvar->lock->owner != me) return PR_FAILURE;
  151.  
  152.     entryCount = mon->entryCount;
  153.     mon->entryCount = 0;
  154.  
  155.     status = _PR_WaitCondVar(me, mon->cvar, mon->cvar->lock, ticks);
  156.  
  157.     mon->entryCount = entryCount;
  158.  
  159.     return status;
  160. }
  161.  
  162. /*
  163. ** Notify the highest priority thread waiting on the condition
  164. ** variable. If a thread is waiting on the condition variable (using
  165. ** PR_Wait) then it is awakened and begins waiting on the monitor's lock.
  166. */
  167. PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon)
  168. {
  169.     PRThread *me = _PR_MD_CURRENT_THREAD();
  170.     if (mon->cvar->lock->owner != me) return PR_FAILURE;
  171.     PR_NotifyCondVar(mon->cvar);
  172.     return PR_SUCCESS;
  173. }
  174.  
  175. /*
  176. ** Notify all of the threads waiting on the condition variable. All of
  177. ** threads are notified in turn. The highest priority thread will
  178. ** probably acquire the monitor first when the monitor is exited.
  179. */
  180. PR_IMPLEMENT(PRStatus) PR_NotifyAll(PRMonitor *mon)
  181. {
  182.     PRThread *me = _PR_MD_CURRENT_THREAD();
  183.     if (mon->cvar->lock->owner != me) return PR_FAILURE;
  184.     PR_NotifyAllCondVar(mon->cvar);
  185.     return PR_SUCCESS;
  186. }
  187.  
  188. /************************************************************************/
  189.  
  190. PRUint32 _PR_MonitorToString(PRMonitor *mon, char *buf, PRUint32 buflen)
  191. {
  192.     PRUint32 nb;
  193.  
  194.     if (mon->cvar->lock->owner) {
  195.     nb = PR_snprintf(buf, buflen, "[%p] owner=%d[%p] count=%ld",
  196.              mon, mon->cvar->lock->owner->id,
  197.              mon->cvar->lock->owner, mon->entryCount);
  198.     } else {
  199.     nb = PR_snprintf(buf, buflen, "[%p]", mon);
  200.     }
  201.     return nb;
  202. }
  203.