Upload Tizen:Base source
[toolchains/nspr.git] / mozilla / nsprpub / pr / src / bthreads / btmon.c
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  * http://www.mozilla.org/MPL/
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  *
15  * The Original Code is the Netscape Portable Runtime (NSPR).
16  *
17  * The Initial Developer of the Original Code is
18  * Netscape Communications Corporation.
19  * Portions created by the Initial Developer are Copyright (C) 1998-2000
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s):
23  *
24  * Alternatively, the contents of this file may be used under the terms of
25  * either the GNU General Public License Version 2 or later (the "GPL"), or
26  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27  * in which case the provisions of the GPL or the LGPL are applicable instead
28  * of those above. If you wish to allow use of your version of this file only
29  * under the terms of either the GPL or the LGPL, and not to allow others to
30  * use your version of this file under the terms of the MPL, indicate your
31  * decision by deleting the provisions above and replace them with the notice
32  * and other provisions required by the GPL or the LGPL. If you do not delete
33  * the provisions above, a recipient may use your version of this file under
34  * the terms of any one of the MPL, the GPL or the LGPL.
35  *
36  * ***** END LICENSE BLOCK ***** */
37
38 #include <kernel/OS.h>
39
40 #include "primpl.h"
41
42 /*
43 ** Create a new monitor. Monitors are re-entrant locks with a single built-in
44 ** condition variable.
45 **
46 ** This may fail if memory is tight or if some operating system resource
47 ** is low.
48 */
49 PR_IMPLEMENT(PRMonitor*)
50     PR_NewMonitor (void)
51 {
52     PRMonitor *mon;
53     PRCondVar *cvar;
54     PRLock    *lock;
55
56     mon = PR_NEWZAP( PRMonitor );
57     if( mon )
58     {
59         lock = PR_NewLock();
60         if( !lock )
61         {
62             PR_DELETE( mon );
63             return( 0 );
64         }
65
66         cvar = PR_NewCondVar( lock );
67         if( !cvar )
68         {
69             PR_DestroyLock( lock );
70             PR_DELETE( mon );
71             return( 0 );
72         }
73
74         mon->cvar = cvar;
75         mon->name = NULL;
76     }
77
78     return( mon );
79 }
80
81 PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name)
82 {
83     PRMonitor* mon = PR_NewMonitor();
84     if( mon )
85     {
86         mon->name = name;
87     }
88     return mon;
89 }
90
91 /*
92 ** Destroy a monitor. The caller is responsible for guaranteeing that the
93 ** monitor is no longer in use. There must be no thread waiting on the
94 ** monitor's condition variable and that the lock is not held.
95 **
96 */
97 PR_IMPLEMENT(void)
98     PR_DestroyMonitor (PRMonitor *mon)
99 {
100     PR_DestroyLock( mon->cvar->lock );
101     PR_DestroyCondVar( mon->cvar );
102     PR_DELETE( mon );
103 }
104
105 /*
106 ** Enter the lock associated with the monitor. If the calling thread currently
107 ** is in the monitor, the call to enter will silently succeed. In either case,
108 ** it will increment the entry count by one.
109 */
110 PR_IMPLEMENT(void)
111     PR_EnterMonitor (PRMonitor *mon)
112 {
113     if( mon->cvar->lock->owner == find_thread( NULL ) )
114     {
115         mon->entryCount++;
116
117     } else
118     {
119         PR_Lock( mon->cvar->lock );
120         mon->entryCount = 1;
121     }
122 }
123
124 /*
125 ** Decrement the entry count associated with the monitor. If the decremented
126 ** entry count is zero, the monitor is exited. Returns PR_FAILURE if the
127 ** calling thread has not entered the monitor.
128 */
129 PR_IMPLEMENT(PRStatus)
130     PR_ExitMonitor (PRMonitor *mon)
131 {
132     if( mon->cvar->lock->owner != find_thread( NULL ) )
133     {
134         return( PR_FAILURE );
135     }
136     if( --mon->entryCount == 0 )
137     {
138         return( PR_Unlock( mon->cvar->lock ) );
139     }
140     return( PR_SUCCESS );
141 }
142
143 /*
144 ** Wait for a notify on the monitor's condition variable. Sleep for "ticks"
145 ** amount of time (if "ticks" is PR_INTERVAL_NO_TIMEOUT then the sleep is
146 ** indefinite).
147 **
148 ** While the thread is waiting it exits the monitor (as if it called
149 ** PR_ExitMonitor as many times as it had called PR_EnterMonitor).  When
150 ** the wait has finished the thread regains control of the monitors lock
151 ** with the same entry count as before the wait began.
152 **
153 ** The thread waiting on the monitor will be resumed when the monitor is
154 ** notified (assuming the thread is the next in line to receive the
155 ** notify) or when the "ticks" timeout elapses.
156 **
157 ** Returns PR_FAILURE if the caller has not entered the monitor.
158 */
159 PR_IMPLEMENT(PRStatus)
160     PR_Wait (PRMonitor *mon, PRIntervalTime ticks)
161 {
162     PRUint32 entryCount;
163     PRUintn  status;
164     PRThread *meThread;
165     thread_id me = find_thread( NULL );
166     meThread = PR_GetCurrentThread();
167
168     if( mon->cvar->lock->owner != me ) return( PR_FAILURE );
169
170     entryCount = mon->entryCount;
171     mon->entryCount = 0;
172
173     status = PR_WaitCondVar( mon->cvar, ticks );
174
175     mon->entryCount = entryCount;
176
177     return( status );
178 }
179
180 /*
181 ** Notify a thread waiting on the monitor's condition variable. If a thread
182 ** is waiting on the condition variable (using PR_Wait) then it is awakened
183 ** and attempts to reenter the monitor.
184 */
185 PR_IMPLEMENT(PRStatus)
186     PR_Notify (PRMonitor *mon)
187 {
188     if( mon->cvar->lock->owner != find_thread( NULL ) )
189     {
190         return( PR_FAILURE );
191     }
192
193     PR_NotifyCondVar( mon->cvar );
194     return( PR_SUCCESS );
195 }
196
197 /*
198 ** Notify all of the threads waiting on the monitor's condition variable.
199 ** All of threads waiting on the condition are scheduled to reenter the
200 ** monitor.
201 */
202 PR_IMPLEMENT(PRStatus)
203     PR_NotifyAll (PRMonitor *mon)
204 {
205     if( mon->cvar->lock->owner != find_thread( NULL ) )
206     {
207         return( PR_FAILURE );
208     }
209
210     PR_NotifyAllCondVar( mon->cvar );
211     return( PR_SUCCESS );
212 }
213
214 /*
215 ** Return the number of times that the current thread has entered the
216 ** lock. Returns zero if the current thread has not entered the lock.
217 */
218 PR_IMPLEMENT(PRIntn)
219     PR_GetMonitorEntryCount(PRMonitor *mon)
220 {
221     return( (mon->cvar->lock->owner == find_thread( NULL )) ?
222             mon->entryCount : 0 );
223 }
224
225 /*
226 ** If the current thread is in |mon|, this assertion is guaranteed to
227 ** succeed.  Otherwise, the behavior of this function is undefined.
228 */
229 PR_IMPLEMENT(void)
230     PR_AssertCurrentThreadInMonitor(PRMonitor *mon)
231 {
232     PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(mon->cvar->lock);
233 }