1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/bthreads/btmon.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,201 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include <kernel/OS.h> 1.10 + 1.11 +#include "primpl.h" 1.12 + 1.13 +/* 1.14 +** Create a new monitor. Monitors are re-entrant locks with a single built-in 1.15 +** condition variable. 1.16 +** 1.17 +** This may fail if memory is tight or if some operating system resource 1.18 +** is low. 1.19 +*/ 1.20 +PR_IMPLEMENT(PRMonitor*) 1.21 + PR_NewMonitor (void) 1.22 +{ 1.23 + PRMonitor *mon; 1.24 + PRCondVar *cvar; 1.25 + PRLock *lock; 1.26 + 1.27 + mon = PR_NEWZAP( PRMonitor ); 1.28 + if( mon ) 1.29 + { 1.30 + lock = PR_NewLock(); 1.31 + if( !lock ) 1.32 + { 1.33 + PR_DELETE( mon ); 1.34 + return( 0 ); 1.35 + } 1.36 + 1.37 + cvar = PR_NewCondVar( lock ); 1.38 + if( !cvar ) 1.39 + { 1.40 + PR_DestroyLock( lock ); 1.41 + PR_DELETE( mon ); 1.42 + return( 0 ); 1.43 + } 1.44 + 1.45 + mon->cvar = cvar; 1.46 + mon->name = NULL; 1.47 + } 1.48 + 1.49 + return( mon ); 1.50 +} 1.51 + 1.52 +PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name) 1.53 +{ 1.54 + PRMonitor* mon = PR_NewMonitor(); 1.55 + if( mon ) 1.56 + { 1.57 + mon->name = name; 1.58 + } 1.59 + return mon; 1.60 +} 1.61 + 1.62 +/* 1.63 +** Destroy a monitor. The caller is responsible for guaranteeing that the 1.64 +** monitor is no longer in use. There must be no thread waiting on the 1.65 +** monitor's condition variable and that the lock is not held. 1.66 +** 1.67 +*/ 1.68 +PR_IMPLEMENT(void) 1.69 + PR_DestroyMonitor (PRMonitor *mon) 1.70 +{ 1.71 + PR_DestroyLock( mon->cvar->lock ); 1.72 + PR_DestroyCondVar( mon->cvar ); 1.73 + PR_DELETE( mon ); 1.74 +} 1.75 + 1.76 +/* 1.77 +** Enter the lock associated with the monitor. If the calling thread currently 1.78 +** is in the monitor, the call to enter will silently succeed. In either case, 1.79 +** it will increment the entry count by one. 1.80 +*/ 1.81 +PR_IMPLEMENT(void) 1.82 + PR_EnterMonitor (PRMonitor *mon) 1.83 +{ 1.84 + if( mon->cvar->lock->owner == find_thread( NULL ) ) 1.85 + { 1.86 + mon->entryCount++; 1.87 + 1.88 + } else 1.89 + { 1.90 + PR_Lock( mon->cvar->lock ); 1.91 + mon->entryCount = 1; 1.92 + } 1.93 +} 1.94 + 1.95 +/* 1.96 +** Decrement the entry count associated with the monitor. If the decremented 1.97 +** entry count is zero, the monitor is exited. Returns PR_FAILURE if the 1.98 +** calling thread has not entered the monitor. 1.99 +*/ 1.100 +PR_IMPLEMENT(PRStatus) 1.101 + PR_ExitMonitor (PRMonitor *mon) 1.102 +{ 1.103 + if( mon->cvar->lock->owner != find_thread( NULL ) ) 1.104 + { 1.105 + return( PR_FAILURE ); 1.106 + } 1.107 + if( --mon->entryCount == 0 ) 1.108 + { 1.109 + return( PR_Unlock( mon->cvar->lock ) ); 1.110 + } 1.111 + return( PR_SUCCESS ); 1.112 +} 1.113 + 1.114 +/* 1.115 +** Wait for a notify on the monitor's condition variable. Sleep for "ticks" 1.116 +** amount of time (if "ticks" is PR_INTERVAL_NO_TIMEOUT then the sleep is 1.117 +** indefinite). 1.118 +** 1.119 +** While the thread is waiting it exits the monitor (as if it called 1.120 +** PR_ExitMonitor as many times as it had called PR_EnterMonitor). When 1.121 +** the wait has finished the thread regains control of the monitors lock 1.122 +** with the same entry count as before the wait began. 1.123 +** 1.124 +** The thread waiting on the monitor will be resumed when the monitor is 1.125 +** notified (assuming the thread is the next in line to receive the 1.126 +** notify) or when the "ticks" timeout elapses. 1.127 +** 1.128 +** Returns PR_FAILURE if the caller has not entered the monitor. 1.129 +*/ 1.130 +PR_IMPLEMENT(PRStatus) 1.131 + PR_Wait (PRMonitor *mon, PRIntervalTime ticks) 1.132 +{ 1.133 + PRUint32 entryCount; 1.134 + PRUintn status; 1.135 + PRThread *meThread; 1.136 + thread_id me = find_thread( NULL ); 1.137 + meThread = PR_GetCurrentThread(); 1.138 + 1.139 + if( mon->cvar->lock->owner != me ) return( PR_FAILURE ); 1.140 + 1.141 + entryCount = mon->entryCount; 1.142 + mon->entryCount = 0; 1.143 + 1.144 + status = PR_WaitCondVar( mon->cvar, ticks ); 1.145 + 1.146 + mon->entryCount = entryCount; 1.147 + 1.148 + return( status ); 1.149 +} 1.150 + 1.151 +/* 1.152 +** Notify a thread waiting on the monitor's condition variable. If a thread 1.153 +** is waiting on the condition variable (using PR_Wait) then it is awakened 1.154 +** and attempts to reenter the monitor. 1.155 +*/ 1.156 +PR_IMPLEMENT(PRStatus) 1.157 + PR_Notify (PRMonitor *mon) 1.158 +{ 1.159 + if( mon->cvar->lock->owner != find_thread( NULL ) ) 1.160 + { 1.161 + return( PR_FAILURE ); 1.162 + } 1.163 + 1.164 + PR_NotifyCondVar( mon->cvar ); 1.165 + return( PR_SUCCESS ); 1.166 +} 1.167 + 1.168 +/* 1.169 +** Notify all of the threads waiting on the monitor's condition variable. 1.170 +** All of threads waiting on the condition are scheduled to reenter the 1.171 +** monitor. 1.172 +*/ 1.173 +PR_IMPLEMENT(PRStatus) 1.174 + PR_NotifyAll (PRMonitor *mon) 1.175 +{ 1.176 + if( mon->cvar->lock->owner != find_thread( NULL ) ) 1.177 + { 1.178 + return( PR_FAILURE ); 1.179 + } 1.180 + 1.181 + PR_NotifyAllCondVar( mon->cvar ); 1.182 + return( PR_SUCCESS ); 1.183 +} 1.184 + 1.185 +/* 1.186 +** Return the number of times that the current thread has entered the 1.187 +** lock. Returns zero if the current thread has not entered the lock. 1.188 +*/ 1.189 +PR_IMPLEMENT(PRIntn) 1.190 + PR_GetMonitorEntryCount(PRMonitor *mon) 1.191 +{ 1.192 + return( (mon->cvar->lock->owner == find_thread( NULL )) ? 1.193 + mon->entryCount : 0 ); 1.194 +} 1.195 + 1.196 +/* 1.197 +** If the current thread is in |mon|, this assertion is guaranteed to 1.198 +** succeed. Otherwise, the behavior of this function is undefined. 1.199 +*/ 1.200 +PR_IMPLEMENT(void) 1.201 + PR_AssertCurrentThreadInMonitor(PRMonitor *mon) 1.202 +{ 1.203 + PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(mon->cvar->lock); 1.204 +}