Bug 1931425 - Limit how often moz-label's #setStyles runs r=reusable-components-revie...
[gecko.git] / nsprpub / pr / src / threads / prcthr.c
blob03586b63b382e5df7a0ab6eb1a836a52537cb51f
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/. */
6 #include "primpl.h"
8 #if defined(WIN95)
9 /*
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)
16 #endif
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);
34 thread->dump = 0;
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;
45 if (warning)
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.
71 PRIntn is;
72 PRThread* me = PR_GetCurrentThread();
73 PRUintn pri = me->priority;
74 _PRCPU* cpu = _PR_MD_CURRENT_CPU();
76 if (_PR_IS_NATIVE_THREAD(me)) {
77 _PR_MD_YIELD();
78 } else {
79 _PR_INTSOFF(is);
80 _PR_RUNQ_LOCK(cpu);
81 if (_PR_RUNQREADYMASK(cpu) >> pri) {
82 me->cpu = cpu;
83 me->state = _PR_RUNNABLE;
84 _PR_ADD_RUNQ(me, cpu, pri);
85 _PR_RUNQ_UNLOCK(cpu);
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"));
91 _PR_FAST_INTSON(is);
92 } else {
93 _PR_RUNQ_UNLOCK(cpu);
94 _PR_INTSON(is);
97 } else {
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.
104 PRCondVar* cv;
105 PRIntervalTime timein;
107 timein = PR_IntervalNow();
108 cv = PR_NewCondVar(_pr_sleeplock);
109 PR_ASSERT(cv != NULL);
110 PR_Lock(_pr_sleeplock);
111 do {
112 PRIntervalTime delta = PR_IntervalNow() - timein;
113 if (delta > timeout) {
114 break;
116 rv = PR_WaitCondVar(cv, timeout - delta);
117 } while (rv == PR_SUCCESS);
118 PR_Unlock(_pr_sleeplock);
119 PR_DestroyCondVar(cv);
121 return rv;
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
145 PRCondVar* victim;
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());
154 if (!haveLock) {
155 PR_Lock(victim->lock);
157 PR_NotifyAllCondVar(victim);
158 if (!haveLock) {
159 PR_Unlock(victim->lock);
162 return PR_SUCCESS;
163 #else /* ! _PR_GLOBAL_THREADS_ONLY */
164 PRIntn is;
165 PRThread* me = _PR_MD_CURRENT_THREAD();
167 if (!_PR_IS_NATIVE_THREAD(me)) {
168 _PR_INTSOFF(is);
171 _PR_THREAD_LOCK(thread);
172 thread->flags |= _PR_INTERRUPT;
173 switch (thread->state) {
174 case _PR_COND_WAIT:
176 * call is made with thread locked;
177 * on return lock is released
179 if (!(thread->flags & _PR_INTERRUPT_BLOCKED)) {
180 _PR_NotifyLockedThread(thread);
182 break;
183 case _PR_IO_WAIT:
185 * Need to hold the thread lock when calling
186 * _PR_Unblock_IO_Wait(). On return lock is
187 * released.
189 # if defined(XP_UNIX) || defined(WINNT)
190 if (!(thread->flags & _PR_INTERRUPT_BLOCKED)) {
191 _PR_Unblock_IO_Wait(thread);
193 # else
194 _PR_THREAD_UNLOCK(thread);
195 # endif
196 break;
197 case _PR_RUNNING:
198 case _PR_RUNNABLE:
199 case _PR_LOCK_WAIT:
200 default:
201 _PR_THREAD_UNLOCK(thread);
202 break;
204 if (!_PR_IS_NATIVE_THREAD(me)) {
205 _PR_INTSON(is);
207 return PR_SUCCESS;
208 #endif /* _PR_GLOBAL_THREADS_ONLY */
212 ** Clear the interrupt flag for self.
214 PR_IMPLEMENT(void) PR_ClearInterrupt() {
215 PRIntn is;
216 PRThread* me = _PR_MD_CURRENT_THREAD();
218 if (!_PR_IS_NATIVE_THREAD(me)) {
219 _PR_INTSOFF(is);
221 _PR_THREAD_LOCK(me);
222 me->flags &= ~_PR_INTERRUPT;
223 _PR_THREAD_UNLOCK(me);
224 if (!_PR_IS_NATIVE_THREAD(me)) {
225 _PR_INTSON(is);
229 PR_IMPLEMENT(void) PR_BlockInterrupt() {
230 PRIntn is;
231 PRThread* me = _PR_MD_CURRENT_THREAD();
233 if (!_PR_IS_NATIVE_THREAD(me)) {
234 _PR_INTSOFF(is);
236 _PR_THREAD_LOCK(me);
237 _PR_THREAD_BLOCK_INTERRUPT(me);
238 _PR_THREAD_UNLOCK(me);
239 if (!_PR_IS_NATIVE_THREAD(me)) {
240 _PR_INTSON(is);
242 } /* PR_BlockInterrupt */
244 PR_IMPLEMENT(void) PR_UnblockInterrupt() {
245 PRIntn is;
246 PRThread* me = _PR_MD_CURRENT_THREAD();
248 if (!_PR_IS_NATIVE_THREAD(me)) {
249 _PR_INTSOFF(is);
251 _PR_THREAD_LOCK(me);
252 _PR_THREAD_UNBLOCK_INTERRUPT(me);
253 _PR_THREAD_UNLOCK(me);
254 if (!_PR_IS_NATIVE_THREAD(me)) {
255 _PR_INTSON(is);
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);
278 #else
279 return 0;
280 #endif
283 PR_IMPLEMENT(PRInt32)
284 PR_SetThreadAffinityMask(PRThread* thread, PRUint32 mask) {
285 #ifdef HAVE_THREAD_AFFINITY
286 return _PR_MD_SETTHREADAFFINITYMASK(thread, mask);
287 #else
288 return 0;
289 #endif
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
296 PRCList* qp;
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()) {
307 _PRCPU* cpu;
309 cpu = _PR_CPU_PTR(qp);
310 PR_SetThreadAffinityMask(cpu->thread, mask);
312 qp = qp->next;
314 #endif
316 return 0;
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,
329 _PR_GCABLE_THREAD);
332 #ifdef SOLARIS
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,
338 _PR_BOUND_THREAD);
340 #endif
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);
347 return NULL;
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
375 : PR_GLOBAL_THREAD;
376 } else {
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 */