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
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/. */
10 ** Some local variables report warnings on Win95 because the code paths
11 ** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
12 ** The pragma suppresses the warning.
15 # pragma warning(disable : 4101)
18 extern PRLock
* _pr_sleeplock
; /* allocated and initialized in prinit */
20 ** Routines common to both native and user threads.
23 ** Clean up a thread object, releasing all of the attached data. Do not
24 ** free the object itself (it may not have been malloc'd)
26 void _PR_CleanupThread(PRThread
* thread
) {
27 /* Free up per-thread-data */
28 _PR_DestroyThreadPrivate(thread
);
30 /* Free any thread dump procs */
31 if (thread
->dumpArg
) {
32 PR_DELETE(thread
->dumpArg
);
36 PR_DELETE(thread
->name
);
37 PR_DELETE(thread
->errorString
);
38 thread
->errorStringSize
= 0;
39 thread
->errorStringLength
= 0;
40 thread
->environment
= NULL
;
43 PR_IMPLEMENT(PRStatus
) PR_Yield() {
44 static PRBool warning
= PR_TRUE
;
46 warning
= _PR_Obsolete("PR_Yield()", "PR_Sleep(PR_INTERVAL_NO_WAIT)");
47 return (PR_Sleep(PR_INTERVAL_NO_WAIT
));
51 ** Make the current thread sleep until "timeout" ticks amount of time
52 ** has expired. If "timeout" is PR_INTERVAL_NO_WAIT then the call is
53 ** equivalent to a yield. Waiting for an infinite amount of time is
54 ** allowed in the expectation that another thread will interrupt().
56 ** A single lock is used for all threads calling sleep. Each caller
57 ** does get its own condition variable since each is expected to have
58 ** a unique 'timeout'.
60 PR_IMPLEMENT(PRStatus
) PR_Sleep(PRIntervalTime timeout
) {
61 PRStatus rv
= PR_SUCCESS
;
63 if (!_pr_initialized
) {
64 _PR_ImplicitInitialization();
67 if (PR_INTERVAL_NO_WAIT
== timeout
) {
69 ** This is a simple yield, nothing more, nothing less.
72 PRThread
* me
= PR_GetCurrentThread();
73 PRUintn pri
= me
->priority
;
74 _PRCPU
* cpu
= _PR_MD_CURRENT_CPU();
76 if (_PR_IS_NATIVE_THREAD(me
)) {
81 if (_PR_RUNQREADYMASK(cpu
) >> pri
) {
83 me
->state
= _PR_RUNNABLE
;
84 _PR_ADD_RUNQ(me
, cpu
, pri
);
87 PR_LOG(_pr_sched_lm
, PR_LOG_MIN
, ("PR_Yield: yielding"));
88 _PR_MD_SWITCH_CONTEXT(me
);
89 PR_LOG(_pr_sched_lm
, PR_LOG_MIN
, ("PR_Yield: done"));
99 ** This is waiting for some finite period of time.
100 ** A thread in this state is interruptible (PR_Interrupt()),
101 ** but the lock and cvar used are local to the implementation
102 ** and not visible to the caller, therefore not notifiable.
105 PRIntervalTime timein
;
107 timein
= PR_IntervalNow();
108 cv
= PR_NewCondVar(_pr_sleeplock
);
109 PR_ASSERT(cv
!= NULL
);
110 PR_Lock(_pr_sleeplock
);
112 PRIntervalTime delta
= PR_IntervalNow() - timein
;
113 if (delta
> timeout
) {
116 rv
= PR_WaitCondVar(cv
, timeout
- delta
);
117 } while (rv
== PR_SUCCESS
);
118 PR_Unlock(_pr_sleeplock
);
119 PR_DestroyCondVar(cv
);
124 PR_IMPLEMENT(PRUint32
) PR_GetThreadID(PRThread
* thread
) { return thread
->id
; }
126 PR_IMPLEMENT(PRThreadPriority
) PR_GetThreadPriority(const PRThread
* thread
) {
127 return (PRThreadPriority
)thread
->priority
;
130 PR_IMPLEMENT(PRThread
*) PR_GetCurrentThread() {
131 if (!_pr_initialized
) {
132 _PR_ImplicitInitialization();
134 return _PR_MD_CURRENT_THREAD();
138 ** Set the interrupt flag for a thread. The thread will be unable to
139 ** block in i/o functions when this happens. Also, any PR_Wait's in
140 ** progress will be undone. The interrupt remains in force until
141 ** PR_ClearInterrupt is called.
143 PR_IMPLEMENT(PRStatus
) PR_Interrupt(PRThread
* thread
) {
144 #ifdef _PR_GLOBAL_THREADS_ONLY
147 _PR_THREAD_LOCK(thread
);
148 thread
->flags
|= _PR_INTERRUPT
;
149 victim
= thread
->wait
.cvar
;
150 _PR_THREAD_UNLOCK(thread
);
151 if ((NULL
!= victim
) && (!(thread
->flags
& _PR_INTERRUPT_BLOCKED
))) {
152 int haveLock
= (victim
->lock
->owner
== _PR_MD_CURRENT_THREAD());
155 PR_Lock(victim
->lock
);
157 PR_NotifyAllCondVar(victim
);
159 PR_Unlock(victim
->lock
);
163 #else /* ! _PR_GLOBAL_THREADS_ONLY */
165 PRThread
* me
= _PR_MD_CURRENT_THREAD();
167 if (!_PR_IS_NATIVE_THREAD(me
)) {
171 _PR_THREAD_LOCK(thread
);
172 thread
->flags
|= _PR_INTERRUPT
;
173 switch (thread
->state
) {
176 * call is made with thread locked;
177 * on return lock is released
179 if (!(thread
->flags
& _PR_INTERRUPT_BLOCKED
)) {
180 _PR_NotifyLockedThread(thread
);
185 * Need to hold the thread lock when calling
186 * _PR_Unblock_IO_Wait(). On return lock is
189 # if defined(XP_UNIX) || defined(WINNT)
190 if (!(thread
->flags
& _PR_INTERRUPT_BLOCKED
)) {
191 _PR_Unblock_IO_Wait(thread
);
194 _PR_THREAD_UNLOCK(thread
);
201 _PR_THREAD_UNLOCK(thread
);
204 if (!_PR_IS_NATIVE_THREAD(me
)) {
208 #endif /* _PR_GLOBAL_THREADS_ONLY */
212 ** Clear the interrupt flag for self.
214 PR_IMPLEMENT(void) PR_ClearInterrupt() {
216 PRThread
* me
= _PR_MD_CURRENT_THREAD();
218 if (!_PR_IS_NATIVE_THREAD(me
)) {
222 me
->flags
&= ~_PR_INTERRUPT
;
223 _PR_THREAD_UNLOCK(me
);
224 if (!_PR_IS_NATIVE_THREAD(me
)) {
229 PR_IMPLEMENT(void) PR_BlockInterrupt() {
231 PRThread
* me
= _PR_MD_CURRENT_THREAD();
233 if (!_PR_IS_NATIVE_THREAD(me
)) {
237 _PR_THREAD_BLOCK_INTERRUPT(me
);
238 _PR_THREAD_UNLOCK(me
);
239 if (!_PR_IS_NATIVE_THREAD(me
)) {
242 } /* PR_BlockInterrupt */
244 PR_IMPLEMENT(void) PR_UnblockInterrupt() {
246 PRThread
* me
= _PR_MD_CURRENT_THREAD();
248 if (!_PR_IS_NATIVE_THREAD(me
)) {
252 _PR_THREAD_UNBLOCK_INTERRUPT(me
);
253 _PR_THREAD_UNLOCK(me
);
254 if (!_PR_IS_NATIVE_THREAD(me
)) {
257 } /* PR_UnblockInterrupt */
260 ** Return the thread stack pointer of the given thread.
262 PR_IMPLEMENT(void*) PR_GetSP(PRThread
* thread
) {
263 return (void*)_PR_MD_GET_SP(thread
);
266 PR_IMPLEMENT(void*) GetExecutionEnvironment(PRThread
* thread
) {
267 return thread
->environment
;
270 PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread
* thread
, void* env
) {
271 thread
->environment
= env
;
274 PR_IMPLEMENT(PRInt32
)
275 PR_GetThreadAffinityMask(PRThread
* thread
, PRUint32
* mask
) {
276 #ifdef HAVE_THREAD_AFFINITY
277 return _PR_MD_GETTHREADAFFINITYMASK(thread
, mask
);
283 PR_IMPLEMENT(PRInt32
)
284 PR_SetThreadAffinityMask(PRThread
* thread
, PRUint32 mask
) {
285 #ifdef HAVE_THREAD_AFFINITY
286 return _PR_MD_SETTHREADAFFINITYMASK(thread
, mask
);
292 /* This call is thread unsafe if another thread is calling SetConcurrency()
294 PR_IMPLEMENT(PRInt32
) PR_SetCPUAffinityMask(PRUint32 mask
) {
295 #ifdef HAVE_THREAD_AFFINITY
297 extern PRUint32 _pr_cpu_affinity_mask
;
299 if (!_pr_initialized
) {
300 _PR_ImplicitInitialization();
303 _pr_cpu_affinity_mask
= mask
;
305 qp
= _PR_CPUQ().next
;
306 while (qp
!= &_PR_CPUQ()) {
309 cpu
= _PR_CPU_PTR(qp
);
310 PR_SetThreadAffinityMask(cpu
->thread
, mask
);
319 PRUint32 _pr_recycleThreads
= 0;
320 PR_IMPLEMENT(void) PR_SetThreadRecycleMode(PRUint32 count
) {
321 _pr_recycleThreads
= count
;
324 PR_IMPLEMENT(PRThread
*)
325 PR_CreateThreadGCAble(PRThreadType type
, void (*start
)(void* arg
), void* arg
,
326 PRThreadPriority priority
, PRThreadScope scope
,
327 PRThreadState state
, PRUint32 stackSize
) {
328 return _PR_CreateThread(type
, start
, arg
, priority
, scope
, state
, stackSize
,
333 PR_IMPLEMENT(PRThread
*)
334 PR_CreateThreadBound(PRThreadType type
, void (*start
)(void* arg
), void* arg
,
335 PRUintn priority
, PRThreadScope scope
, PRThreadState state
,
336 PRUint32 stackSize
) {
337 return _PR_CreateThread(type
, start
, arg
, priority
, scope
, state
, stackSize
,
342 PR_IMPLEMENT(PRThread
*)
343 PR_AttachThreadGCAble(PRThreadType type
, PRThreadPriority priority
,
344 PRThreadStack
* stack
) {
345 /* $$$$ not sure how to finese this one */
346 PR_SetError(PR_NOT_IMPLEMENTED_ERROR
, 0);
350 PR_IMPLEMENT(void) PR_SetThreadGCAble() {
351 if (!_pr_initialized
) {
352 _PR_ImplicitInitialization();
354 PR_Lock(_pr_activeLock
);
355 _PR_MD_CURRENT_THREAD()->flags
|= _PR_GCABLE_THREAD
;
356 PR_Unlock(_pr_activeLock
);
359 PR_IMPLEMENT(void) PR_ClearThreadGCAble() {
360 if (!_pr_initialized
) {
361 _PR_ImplicitInitialization();
363 PR_Lock(_pr_activeLock
);
364 _PR_MD_CURRENT_THREAD()->flags
&= (~_PR_GCABLE_THREAD
);
365 PR_Unlock(_pr_activeLock
);
368 PR_IMPLEMENT(PRThreadScope
) PR_GetThreadScope(const PRThread
* thread
) {
369 if (!_pr_initialized
) {
370 _PR_ImplicitInitialization();
373 if (_PR_IS_NATIVE_THREAD(thread
)) {
374 return (thread
->flags
& _PR_BOUND_THREAD
) ? PR_GLOBAL_BOUND_THREAD
377 return PR_LOCAL_THREAD
;
381 PR_IMPLEMENT(PRThreadType
) PR_GetThreadType(const PRThread
* thread
) {
382 return (thread
->flags
& _PR_SYSTEM
) ? PR_SYSTEM_THREAD
: PR_USER_THREAD
;
385 PR_IMPLEMENT(PRThreadState
) PR_GetThreadState(const PRThread
* thread
) {
386 return (NULL
== thread
->term
) ? PR_UNJOINABLE_THREAD
: PR_JOINABLE_THREAD
;
387 } /* PR_GetThreadState */