1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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 : /*
39 : ** File: ptthread.c
40 : ** Descritpion: Implemenation for threds using pthreds
41 : ** Exports: ptthread.h
42 : */
43 :
44 : #if defined(_PR_PTHREADS) || defined(_PR_DCETHREADS)
45 :
46 : #include "prlog.h"
47 : #include "primpl.h"
48 : #include "prpdce.h"
49 :
50 : #include <pthread.h>
51 : #include <unistd.h>
52 : #include <string.h>
53 : #include <signal.h>
54 :
55 : #ifdef SYMBIAN
56 : /* In Open C sched_get_priority_min/max do not work properly, so we undefine
57 : * _POSIX_THREAD_PRIORITY_SCHEDULING here.
58 : */
59 : #undef _POSIX_THREAD_PRIORITY_SCHEDULING
60 : #endif
61 :
62 : /*
63 : * Record whether or not we have the privilege to set the scheduling
64 : * policy and priority of threads. 0 means that privilege is available.
65 : * EPERM means that privilege is not available.
66 : */
67 :
68 : static PRIntn pt_schedpriv = 0;
69 : extern PRLock *_pr_sleeplock;
70 :
71 : static struct _PT_Bookeeping
72 : {
73 : PRLock *ml; /* a lock to protect ourselves */
74 : PRCondVar *cv; /* used to signal global things */
75 : PRInt32 system, user; /* a count of the two different types */
76 : PRUintn this_many; /* number of threads allowed for exit */
77 : pthread_key_t key; /* private private data key */
78 : PRThread *first, *last; /* list of threads we know about */
79 : #if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
80 : PRInt32 minPrio, maxPrio; /* range of scheduling priorities */
81 : #endif
82 : } pt_book = {0};
83 :
84 : static void _pt_thread_death(void *arg);
85 : static void _pt_thread_death_internal(void *arg, PRBool callDestructors);
86 : static void init_pthread_gc_support(void);
87 :
88 : #if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
89 50573 : static PRIntn pt_PriorityMap(PRThreadPriority pri)
90 : {
91 : #ifdef NTO
92 : /* This priority algorithm causes lots of problems on Neutrino
93 : * for now I have just hard coded everything to run at priority 10
94 : * until I can come up with a new algorithm.
95 : * Jerry.Kirk@Nexwarecorp.com
96 : */
97 : return 10;
98 : #else
99 101146 : return pt_book.minPrio +
100 50573 : pri * (pt_book.maxPrio - pt_book.minPrio) / PR_PRIORITY_LAST;
101 : #endif
102 : }
103 : #endif
104 :
105 : /*
106 : ** Initialize a stack for a native pthread thread
107 : */
108 50512 : static void _PR_InitializeStack(PRThreadStack *ts)
109 : {
110 50512 : if( ts && (ts->stackTop == 0) ) {
111 50512 : ts->allocBase = (char *) &ts;
112 50512 : ts->allocSize = ts->stackSize;
113 :
114 : /*
115 : ** Setup stackTop and stackBottom values.
116 : */
117 : #ifdef HAVE_STACK_GROWING_UP
118 : ts->stackBottom = ts->allocBase + ts->stackSize;
119 : ts->stackTop = ts->allocBase;
120 : #else
121 50512 : ts->stackTop = ts->allocBase;
122 50512 : ts->stackBottom = ts->allocBase - ts->stackSize;
123 : #endif
124 : }
125 50512 : }
126 :
127 30477 : static void *_pt_root(void *arg)
128 : {
129 : PRIntn rv;
130 30477 : PRThread *thred = (PRThread*)arg;
131 30477 : PRBool detached = (thred->state & PT_THREAD_DETACHED) ? PR_TRUE : PR_FALSE;
132 :
133 : /*
134 : * Both the parent thread and this new thread set thred->id.
135 : * The new thread must ensure that thred->id is set before
136 : * it executes its startFunc. The parent thread must ensure
137 : * that thred->id is set before PR_CreateThread() returns.
138 : * Both threads set thred->id without holding a lock. Since
139 : * they are writing the same value, this unprotected double
140 : * write should be safe.
141 : */
142 30477 : thred->id = pthread_self();
143 :
144 : /*
145 : ** DCE Threads can't detach during creation, so do it late.
146 : ** I would like to do it only here, but that doesn't seem
147 : ** to work.
148 : */
149 : #if defined(_PR_DCETHREADS)
150 : if (detached)
151 : {
152 : /* pthread_detach() modifies its argument, so we must pass a copy */
153 : pthread_t self = thred->id;
154 : rv = pthread_detach(&self);
155 : PR_ASSERT(0 == rv);
156 : }
157 : #endif /* defined(_PR_DCETHREADS) */
158 :
159 : /* Set up the thread stack information */
160 30478 : _PR_InitializeStack(thred->stack);
161 :
162 : /*
163 : * Set within the current thread the pointer to our object.
164 : * This object will be deleted when the thread termintates,
165 : * whether in a join or detached (see _PR_InitThreads()).
166 : */
167 30478 : rv = pthread_setspecific(pt_book.key, thred);
168 30478 : PR_ASSERT(0 == rv);
169 :
170 : /* make the thread visible to the rest of the runtime */
171 30478 : PR_Lock(pt_book.ml);
172 :
173 : /* If this is a GCABLE thread, set its state appropriately */
174 30478 : if (thred->suspend & PT_THREAD_SETGCABLE)
175 0 : thred->state |= PT_THREAD_GCABLE;
176 30478 : thred->suspend = 0;
177 :
178 30478 : thred->prev = pt_book.last;
179 30478 : if (pt_book.last)
180 30478 : pt_book.last->next = thred;
181 : else
182 0 : pt_book.first = thred;
183 30478 : thred->next = NULL;
184 30478 : pt_book.last = thred;
185 30478 : PR_Unlock(pt_book.ml);
186 :
187 30478 : thred->startFunc(thred->arg); /* make visible to the client */
188 :
189 : /* unhook the thread from the runtime */
190 30462 : PR_Lock(pt_book.ml);
191 : /*
192 : * At this moment, PR_CreateThread() may not have set thred->id yet.
193 : * It is safe for a detached thread to free thred only after
194 : * PR_CreateThread() has set thred->id.
195 : */
196 30462 : if (detached)
197 : {
198 3352 : while (!thred->okToDelete)
199 0 : PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT);
200 : }
201 :
202 30462 : if (thred->state & PT_THREAD_SYSTEM)
203 1287 : pt_book.system -= 1;
204 29175 : else if (--pt_book.user == pt_book.this_many)
205 19914 : PR_NotifyAllCondVar(pt_book.cv);
206 30462 : if (NULL == thred->prev)
207 0 : pt_book.first = thred->next;
208 : else
209 30462 : thred->prev->next = thred->next;
210 30462 : if (NULL == thred->next)
211 22536 : pt_book.last = thred->prev;
212 : else
213 7926 : thred->next->prev = thred->prev;
214 30462 : PR_Unlock(pt_book.ml);
215 :
216 : /*
217 : * Here we set the pthread's backpointer to the PRThread to NULL.
218 : * Otherwise the destructor would get called eagerly as the thread
219 : * returns to the pthread runtime. The joining thread would them be
220 : * the proud possessor of a dangling reference. However, this is the
221 : * last chance to delete the object if the thread is detached, so
222 : * just let the destructor do the work.
223 : */
224 30462 : if (PR_FALSE == detached)
225 : {
226 : /* Call TPD destructors on this thread. */
227 28786 : _PR_DestroyThreadPrivate(thred);
228 28786 : rv = pthread_setspecific(pt_book.key, NULL);
229 28786 : PR_ASSERT(0 == rv);
230 : }
231 :
232 30462 : return NULL;
233 : } /* _pt_root */
234 :
235 0 : static PRThread* pt_AttachThread(void)
236 : {
237 0 : PRThread *thred = NULL;
238 :
239 : /*
240 : * NSPR must have been initialized when PR_AttachThread is called.
241 : * We cannot have PR_AttachThread call implicit initialization
242 : * because if multiple threads call PR_AttachThread simultaneously,
243 : * NSPR may be initialized more than once.
244 : * We can't call any function that calls PR_GetCurrentThread()
245 : * either (e.g., PR_SetError()) as that will result in infinite
246 : * recursion.
247 : */
248 0 : if (!_pr_initialized) return NULL;
249 :
250 : /* PR_NEWZAP must not call PR_GetCurrentThread() */
251 0 : thred = PR_NEWZAP(PRThread);
252 0 : if (NULL != thred)
253 : {
254 : int rv;
255 :
256 0 : thred->priority = PR_PRIORITY_NORMAL;
257 0 : thred->id = pthread_self();
258 0 : rv = pthread_setspecific(pt_book.key, thred);
259 0 : PR_ASSERT(0 == rv);
260 :
261 0 : thred->state = PT_THREAD_GLOBAL | PT_THREAD_FOREIGN;
262 0 : PR_Lock(pt_book.ml);
263 :
264 : /* then put it into the list */
265 0 : thred->prev = pt_book.last;
266 0 : if (pt_book.last)
267 0 : pt_book.last->next = thred;
268 : else
269 0 : pt_book.first = thred;
270 0 : thred->next = NULL;
271 0 : pt_book.last = thred;
272 0 : PR_Unlock(pt_book.ml);
273 :
274 : }
275 0 : return thred; /* may be NULL */
276 : } /* pt_AttachThread */
277 :
278 30478 : static PRThread* _PR_CreateThread(
279 : PRThreadType type, void (*start)(void *arg),
280 : void *arg, PRThreadPriority priority, PRThreadScope scope,
281 : PRThreadState state, PRUint32 stackSize, PRBool isGCAble)
282 : {
283 : int rv;
284 : PRThread *thred;
285 : pthread_attr_t tattr;
286 :
287 30478 : if (!_pr_initialized) _PR_ImplicitInitialization();
288 :
289 30478 : if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)priority)
290 0 : priority = PR_PRIORITY_FIRST;
291 30478 : else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)priority)
292 0 : priority = PR_PRIORITY_LAST;
293 :
294 30478 : rv = _PT_PTHREAD_ATTR_INIT(&tattr);
295 30478 : PR_ASSERT(0 == rv);
296 :
297 30478 : if (EPERM != pt_schedpriv)
298 : {
299 : #if !defined(_PR_DCETHREADS) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
300 : struct sched_param schedule;
301 : #endif
302 :
303 : #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
304 30478 : rv = pthread_attr_setinheritsched(&tattr, PTHREAD_EXPLICIT_SCHED);
305 30478 : PR_ASSERT(0 == rv);
306 : #endif
307 :
308 : /* Use the default scheduling policy */
309 :
310 : #if defined(_PR_DCETHREADS)
311 : rv = pthread_attr_setprio(&tattr, pt_PriorityMap(priority));
312 : PR_ASSERT(0 == rv);
313 : #elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
314 30478 : rv = pthread_attr_getschedparam(&tattr, &schedule);
315 30478 : PR_ASSERT(0 == rv);
316 30478 : schedule.sched_priority = pt_PriorityMap(priority);
317 30478 : rv = pthread_attr_setschedparam(&tattr, &schedule);
318 30478 : PR_ASSERT(0 == rv);
319 : #ifdef NTO
320 : rv = pthread_attr_setschedpolicy(&tattr, SCHED_RR); /* Round Robin */
321 : PR_ASSERT(0 == rv);
322 : #endif
323 : #endif /* !defined(_PR_DCETHREADS) */
324 : }
325 :
326 : /*
327 : * DCE threads can't set detach state before creating the thread.
328 : * AIX can't set detach late. Why can't we all just get along?
329 : */
330 : #if !defined(_PR_DCETHREADS)
331 30478 : rv = pthread_attr_setdetachstate(&tattr,
332 : ((PR_JOINABLE_THREAD == state) ?
333 : PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED));
334 30478 : PR_ASSERT(0 == rv);
335 : #endif /* !defined(_PR_DCETHREADS) */
336 :
337 : /*
338 : * If stackSize is 0, we use the default pthread stack size.
339 : */
340 30478 : if (stackSize)
341 : {
342 : #ifdef _MD_MINIMUM_STACK_SIZE
343 : if (stackSize < _MD_MINIMUM_STACK_SIZE)
344 : stackSize = _MD_MINIMUM_STACK_SIZE;
345 : #endif
346 0 : rv = pthread_attr_setstacksize(&tattr, stackSize);
347 0 : PR_ASSERT(0 == rv);
348 : }
349 :
350 30478 : thred = PR_NEWZAP(PRThread);
351 30478 : if (NULL == thred)
352 : {
353 0 : PR_SetError(PR_OUT_OF_MEMORY_ERROR, errno);
354 0 : goto done;
355 : }
356 : else
357 : {
358 : pthread_t id;
359 :
360 30478 : thred->arg = arg;
361 30478 : thred->startFunc = start;
362 30478 : thred->priority = priority;
363 30478 : if (PR_UNJOINABLE_THREAD == state)
364 1677 : thred->state |= PT_THREAD_DETACHED;
365 :
366 30478 : if (PR_LOCAL_THREAD == scope)
367 22661 : scope = PR_GLOBAL_THREAD;
368 :
369 30478 : if (PR_GLOBAL_BOUND_THREAD == scope) {
370 : #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
371 0 : rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
372 0 : if (rv) {
373 : /*
374 : * system scope not supported
375 : */
376 0 : scope = PR_GLOBAL_THREAD;
377 : /*
378 : * reset scope
379 : */
380 0 : rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_PROCESS);
381 0 : PR_ASSERT(0 == rv);
382 : }
383 : #endif
384 : }
385 30478 : if (PR_GLOBAL_THREAD == scope)
386 30478 : thred->state |= PT_THREAD_GLOBAL;
387 0 : else if (PR_GLOBAL_BOUND_THREAD == scope)
388 0 : thred->state |= (PT_THREAD_GLOBAL | PT_THREAD_BOUND);
389 : else /* force it global */
390 0 : thred->state |= PT_THREAD_GLOBAL;
391 30478 : if (PR_SYSTEM_THREAD == type)
392 1300 : thred->state |= PT_THREAD_SYSTEM;
393 :
394 30478 : thred->suspend =(isGCAble) ? PT_THREAD_SETGCABLE : 0;
395 :
396 30478 : thred->stack = PR_NEWZAP(PRThreadStack);
397 30478 : if (thred->stack == NULL) {
398 0 : PRIntn oserr = errno;
399 0 : PR_Free(thred); /* all that work ... poof! */
400 0 : PR_SetError(PR_OUT_OF_MEMORY_ERROR, oserr);
401 0 : thred = NULL; /* and for what? */
402 0 : goto done;
403 : }
404 30478 : thred->stack->stackSize = stackSize;
405 30478 : thred->stack->thr = thred;
406 :
407 : #ifdef PT_NO_SIGTIMEDWAIT
408 30478 : pthread_mutex_init(&thred->suspendResumeMutex,NULL);
409 30478 : pthread_cond_init(&thred->suspendResumeCV,NULL);
410 : #endif
411 :
412 : /* make the thread counted to the rest of the runtime */
413 30478 : PR_Lock(pt_book.ml);
414 30478 : if (PR_SYSTEM_THREAD == type)
415 1300 : pt_book.system += 1;
416 29178 : else pt_book.user += 1;
417 30478 : PR_Unlock(pt_book.ml);
418 :
419 : /*
420 : * We pass a pointer to a local copy (instead of thred->id)
421 : * to pthread_create() because who knows what wacky things
422 : * pthread_create() may be doing to its argument.
423 : */
424 30478 : rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred);
425 :
426 : #if !defined(_PR_DCETHREADS)
427 30478 : if (EPERM == rv)
428 : {
429 : #if defined(IRIX)
430 : if (PR_GLOBAL_BOUND_THREAD == scope) {
431 : /*
432 : * SCOPE_SYSTEM requires appropriate privilege
433 : * reset to process scope and try again
434 : */
435 : rv = pthread_attr_setscope(&tattr, PTHREAD_SCOPE_PROCESS);
436 : PR_ASSERT(0 == rv);
437 : thred->state &= ~PT_THREAD_BOUND;
438 : }
439 : #else
440 : /* Remember that we don't have thread scheduling privilege. */
441 0 : pt_schedpriv = EPERM;
442 0 : PR_LOG(_pr_thread_lm, PR_LOG_MIN,
443 : ("_PR_CreateThread: no thread scheduling privilege"));
444 : /* Try creating the thread again without setting priority. */
445 : #if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
446 0 : rv = pthread_attr_setinheritsched(&tattr, PTHREAD_INHERIT_SCHED);
447 0 : PR_ASSERT(0 == rv);
448 : #endif
449 : #endif /* IRIX */
450 0 : rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred);
451 : }
452 : #endif
453 :
454 30478 : if (0 != rv)
455 : {
456 : #if defined(_PR_DCETHREADS)
457 : PRIntn oserr = errno;
458 : #else
459 0 : PRIntn oserr = rv;
460 : #endif
461 0 : PR_Lock(pt_book.ml);
462 0 : if (thred->state & PT_THREAD_SYSTEM)
463 0 : pt_book.system -= 1;
464 0 : else if (--pt_book.user == pt_book.this_many)
465 0 : PR_NotifyAllCondVar(pt_book.cv);
466 0 : PR_Unlock(pt_book.ml);
467 :
468 0 : PR_Free(thred->stack);
469 0 : PR_Free(thred); /* all that work ... poof! */
470 0 : PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, oserr);
471 0 : thred = NULL; /* and for what? */
472 0 : goto done;
473 : }
474 :
475 : /*
476 : * Both the parent thread and this new thread set thred->id.
477 : * The parent thread must ensure that thred->id is set before
478 : * PR_CreateThread() returns. (See comments in _pt_root().)
479 : */
480 30478 : thred->id = id;
481 :
482 : /*
483 : * If the new thread is detached, tell it that PR_CreateThread()
484 : * has set thred->id so it's ok to delete thred.
485 : */
486 30478 : if (PR_UNJOINABLE_THREAD == state)
487 : {
488 1677 : PR_Lock(pt_book.ml);
489 1677 : thred->okToDelete = PR_TRUE;
490 1677 : PR_NotifyAllCondVar(pt_book.cv);
491 1677 : PR_Unlock(pt_book.ml);
492 : }
493 : }
494 :
495 : done:
496 30478 : rv = _PT_PTHREAD_ATTR_DESTROY(&tattr);
497 30478 : PR_ASSERT(0 == rv);
498 :
499 30478 : return thred;
500 : } /* _PR_CreateThread */
501 :
502 30478 : PR_IMPLEMENT(PRThread*) PR_CreateThread(
503 : PRThreadType type, void (*start)(void *arg), void *arg,
504 : PRThreadPriority priority, PRThreadScope scope,
505 : PRThreadState state, PRUint32 stackSize)
506 : {
507 30478 : return _PR_CreateThread(
508 : type, start, arg, priority, scope, state, stackSize, PR_FALSE);
509 : } /* PR_CreateThread */
510 :
511 0 : PR_IMPLEMENT(PRThread*) PR_CreateThreadGCAble(
512 : PRThreadType type, void (*start)(void *arg), void *arg,
513 : PRThreadPriority priority, PRThreadScope scope,
514 : PRThreadState state, PRUint32 stackSize)
515 : {
516 0 : return _PR_CreateThread(
517 : type, start, arg, priority, scope, state, stackSize, PR_TRUE);
518 : } /* PR_CreateThreadGCAble */
519 :
520 0 : PR_IMPLEMENT(void*) GetExecutionEnvironment(PRThread *thred)
521 : {
522 0 : return thred->environment;
523 : } /* GetExecutionEnvironment */
524 :
525 0 : PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread *thred, void *env)
526 : {
527 0 : thred->environment = env;
528 0 : } /* SetExecutionEnvironment */
529 :
530 0 : PR_IMPLEMENT(PRThread*) PR_AttachThread(
531 : PRThreadType type, PRThreadPriority priority, PRThreadStack *stack)
532 : {
533 0 : return PR_GetCurrentThread();
534 : } /* PR_AttachThread */
535 :
536 :
537 28786 : PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thred)
538 : {
539 28786 : int rv = -1;
540 28786 : void *result = NULL;
541 28786 : PR_ASSERT(thred != NULL);
542 :
543 28786 : if ((0xafafafaf == thred->state)
544 28786 : || (PT_THREAD_DETACHED == (PT_THREAD_DETACHED & thred->state))
545 28786 : || (PT_THREAD_FOREIGN == (PT_THREAD_FOREIGN & thred->state)))
546 : {
547 : /*
548 : * This might be a bad address, but if it isn't, the state should
549 : * either be an unjoinable thread or it's already had the object
550 : * deleted. However, the client that called join on a detached
551 : * thread deserves all the rath I can muster....
552 : */
553 0 : PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
554 0 : PR_LogPrint(
555 : "PR_JoinThread: %p not joinable | already smashed\n", thred);
556 : }
557 : else
558 : {
559 28786 : pthread_t id = thred->id;
560 28786 : rv = pthread_join(id, &result);
561 28786 : PR_ASSERT(rv == 0 && result == NULL);
562 28786 : if (0 == rv)
563 : {
564 : #ifdef _PR_DCETHREADS
565 : rv = pthread_detach(&id);
566 : PR_ASSERT(0 == rv);
567 : #endif
568 : /*
569 : * PR_FALSE, because the thread already called the TPD
570 : * destructors before exiting _pt_root.
571 : */
572 28786 : _pt_thread_death_internal(thred, PR_FALSE);
573 : }
574 : else
575 : {
576 : PRErrorCode prerror;
577 0 : switch (rv)
578 : {
579 : case EINVAL: /* not a joinable thread */
580 : case ESRCH: /* no thread with given ID */
581 0 : prerror = PR_INVALID_ARGUMENT_ERROR;
582 0 : break;
583 : case EDEADLK: /* a thread joining with itself */
584 0 : prerror = PR_DEADLOCK_ERROR;
585 0 : break;
586 : default:
587 0 : prerror = PR_UNKNOWN_ERROR;
588 0 : break;
589 : }
590 0 : PR_SetError(prerror, rv);
591 : }
592 : }
593 28786 : return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
594 : } /* PR_JoinThread */
595 :
596 0 : PR_IMPLEMENT(void) PR_DetachThread(void)
597 : {
598 : void *thred;
599 : int rv;
600 :
601 0 : _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred);
602 0 : if (NULL == thred) return;
603 0 : _pt_thread_death(thred);
604 0 : rv = pthread_setspecific(pt_book.key, NULL);
605 0 : PR_ASSERT(0 == rv);
606 : } /* PR_DetachThread */
607 :
608 1543952866 : PR_IMPLEMENT(PRThread*) PR_GetCurrentThread(void)
609 : {
610 : void *thred;
611 :
612 1543952866 : if (!_pr_initialized) _PR_ImplicitInitialization();
613 :
614 1543952866 : _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred);
615 1543950557 : if (NULL == thred) thred = pt_AttachThread();
616 1543940844 : PR_ASSERT(NULL != thred);
617 1543940844 : return (PRThread*)thred;
618 : } /* PR_GetCurrentThread */
619 :
620 0 : PR_IMPLEMENT(PRThreadScope) PR_GetThreadScope(const PRThread *thred)
621 : {
622 0 : return (thred->state & PT_THREAD_BOUND) ?
623 : PR_GLOBAL_BOUND_THREAD : PR_GLOBAL_THREAD;
624 : } /* PR_GetThreadScope() */
625 :
626 0 : PR_IMPLEMENT(PRThreadType) PR_GetThreadType(const PRThread *thred)
627 : {
628 0 : return (thred->state & PT_THREAD_SYSTEM) ?
629 : PR_SYSTEM_THREAD : PR_USER_THREAD;
630 : }
631 :
632 0 : PR_IMPLEMENT(PRThreadState) PR_GetThreadState(const PRThread *thred)
633 : {
634 0 : return (thred->state & PT_THREAD_DETACHED) ?
635 0 : PR_UNJOINABLE_THREAD : PR_JOINABLE_THREAD;
636 : } /* PR_GetThreadState */
637 :
638 0 : PR_IMPLEMENT(PRThreadPriority) PR_GetThreadPriority(const PRThread *thred)
639 : {
640 0 : PR_ASSERT(thred != NULL);
641 0 : return thred->priority;
642 : } /* PR_GetThreadPriority */
643 :
644 20095 : PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred, PRThreadPriority newPri)
645 : {
646 20095 : PRIntn rv = -1;
647 :
648 20095 : PR_ASSERT(NULL != thred);
649 :
650 20095 : if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)newPri)
651 0 : newPri = PR_PRIORITY_FIRST;
652 20095 : else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)newPri)
653 0 : newPri = PR_PRIORITY_LAST;
654 :
655 : #if defined(_PR_DCETHREADS)
656 : rv = pthread_setprio(thred->id, pt_PriorityMap(newPri));
657 : /* pthread_setprio returns the old priority */
658 : #elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
659 20095 : if (EPERM != pt_schedpriv)
660 : {
661 : int policy;
662 : struct sched_param schedule;
663 :
664 20095 : rv = pthread_getschedparam(thred->id, &policy, &schedule);
665 20095 : if(0 == rv) {
666 20095 : schedule.sched_priority = pt_PriorityMap(newPri);
667 20095 : rv = pthread_setschedparam(thred->id, policy, &schedule);
668 20095 : if (EPERM == rv)
669 : {
670 0 : pt_schedpriv = EPERM;
671 0 : PR_LOG(_pr_thread_lm, PR_LOG_MIN,
672 : ("PR_SetThreadPriority: no thread scheduling privilege"));
673 : }
674 : }
675 20095 : if (rv != 0)
676 0 : rv = -1;
677 : }
678 : #endif
679 :
680 20095 : thred->priority = newPri;
681 20095 : } /* PR_SetThreadPriority */
682 :
683 0 : PR_IMPLEMENT(PRStatus) PR_Interrupt(PRThread *thred)
684 : {
685 : /*
686 : ** If the target thread indicates that it's waiting,
687 : ** find the condition and broadcast to it. Broadcast
688 : ** since we don't know which thread (if there are more
689 : ** than one). This sounds risky, but clients must
690 : ** test their invariants when resumed from a wait and
691 : ** I don't expect very many threads to be waiting on
692 : ** a single condition and I don't expect interrupt to
693 : ** be used very often.
694 : **
695 : ** I don't know why I thought this would work. Must have
696 : ** been one of those weaker momements after I'd been
697 : ** smelling the vapors.
698 : **
699 : ** Even with the followng changes it is possible that
700 : ** the pointer to the condition variable is pointing
701 : ** at a bogus value. Will the unerlying code detect
702 : ** that?
703 : */
704 : PRCondVar *cv;
705 0 : PR_ASSERT(NULL != thred);
706 0 : if (NULL == thred) return PR_FAILURE;
707 :
708 0 : thred->state |= PT_THREAD_ABORTED;
709 :
710 0 : cv = thred->waiting;
711 0 : if ((NULL != cv) && !thred->interrupt_blocked)
712 : {
713 : PRIntn rv;
714 0 : (void)PR_ATOMIC_INCREMENT(&cv->notify_pending);
715 0 : rv = pthread_cond_broadcast(&cv->cv);
716 0 : PR_ASSERT(0 == rv);
717 0 : if (0 > PR_ATOMIC_DECREMENT(&cv->notify_pending))
718 0 : PR_DestroyCondVar(cv);
719 : }
720 0 : return PR_SUCCESS;
721 : } /* PR_Interrupt */
722 :
723 0 : PR_IMPLEMENT(void) PR_ClearInterrupt(void)
724 : {
725 0 : PRThread *me = PR_GetCurrentThread();
726 0 : me->state &= ~PT_THREAD_ABORTED;
727 0 : } /* PR_ClearInterrupt */
728 :
729 0 : PR_IMPLEMENT(void) PR_BlockInterrupt(void)
730 : {
731 0 : PRThread *me = PR_GetCurrentThread();
732 0 : _PT_THREAD_BLOCK_INTERRUPT(me);
733 0 : } /* PR_BlockInterrupt */
734 :
735 0 : PR_IMPLEMENT(void) PR_UnblockInterrupt(void)
736 : {
737 0 : PRThread *me = PR_GetCurrentThread();
738 0 : _PT_THREAD_UNBLOCK_INTERRUPT(me);
739 0 : } /* PR_UnblockInterrupt */
740 :
741 0 : PR_IMPLEMENT(PRStatus) PR_Yield(void)
742 : {
743 : static PRBool warning = PR_TRUE;
744 0 : if (warning) warning = _PR_Obsolete(
745 : "PR_Yield()", "PR_Sleep(PR_INTERVAL_NO_WAIT)");
746 0 : return PR_Sleep(PR_INTERVAL_NO_WAIT);
747 : }
748 :
749 434 : PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime ticks)
750 : {
751 434 : PRStatus rv = PR_SUCCESS;
752 :
753 434 : if (!_pr_initialized) _PR_ImplicitInitialization();
754 :
755 434 : if (PR_INTERVAL_NO_WAIT == ticks)
756 : {
757 0 : _PT_PTHREAD_YIELD();
758 : }
759 : else
760 : {
761 : PRCondVar *cv;
762 : PRIntervalTime timein;
763 :
764 434 : timein = PR_IntervalNow();
765 434 : cv = PR_NewCondVar(_pr_sleeplock);
766 434 : PR_ASSERT(cv != NULL);
767 434 : PR_Lock(_pr_sleeplock);
768 : do
769 : {
770 896 : PRIntervalTime now = PR_IntervalNow();
771 896 : PRIntervalTime delta = now - timein;
772 896 : if (delta > ticks) break;
773 462 : rv = PR_WaitCondVar(cv, ticks - delta);
774 462 : } while (PR_SUCCESS == rv);
775 434 : PR_Unlock(_pr_sleeplock);
776 434 : PR_DestroyCondVar(cv);
777 : }
778 434 : return rv;
779 : } /* PR_Sleep */
780 :
781 1816 : static void _pt_thread_death(void *arg)
782 : {
783 : void *thred;
784 : int rv;
785 :
786 1816 : _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred);
787 1816 : if (NULL == thred)
788 : {
789 : /*
790 : * Have PR_GetCurrentThread return the expected value to the
791 : * destructors.
792 : */
793 1676 : rv = pthread_setspecific(pt_book.key, arg);
794 1676 : PR_ASSERT(0 == rv);
795 : }
796 :
797 : /* PR_TRUE for: call destructors */
798 1816 : _pt_thread_death_internal(arg, PR_TRUE);
799 :
800 1816 : if (NULL == thred)
801 : {
802 1676 : rv = pthread_setspecific(pt_book.key, NULL);
803 1676 : PR_ASSERT(0 == rv);
804 : }
805 1816 : }
806 :
807 30602 : static void _pt_thread_death_internal(void *arg, PRBool callDestructors)
808 : {
809 30602 : PRThread *thred = (PRThread*)arg;
810 :
811 30602 : if (thred->state & (PT_THREAD_FOREIGN|PT_THREAD_PRIMORD))
812 : {
813 140 : PR_Lock(pt_book.ml);
814 140 : if (NULL == thred->prev)
815 140 : pt_book.first = thred->next;
816 : else
817 0 : thred->prev->next = thred->next;
818 140 : if (NULL == thred->next)
819 140 : pt_book.last = thred->prev;
820 : else
821 0 : thred->next->prev = thred->prev;
822 140 : PR_Unlock(pt_book.ml);
823 : }
824 30602 : if (callDestructors)
825 1816 : _PR_DestroyThreadPrivate(thred);
826 30602 : PR_Free(thred->privateData);
827 30602 : if (NULL != thred->errorString)
828 140 : PR_Free(thred->errorString);
829 30602 : PR_Free(thred->stack);
830 30602 : if (NULL != thred->syspoll_list)
831 0 : PR_Free(thred->syspoll_list);
832 : #if defined(_PR_POLL_WITH_SELECT)
833 : if (NULL != thred->selectfd_list)
834 : PR_Free(thred->selectfd_list);
835 : #endif
836 : #if defined(DEBUG)
837 30602 : memset(thred, 0xaf, sizeof(PRThread));
838 : #endif /* defined(DEBUG) */
839 30602 : PR_Free(thred);
840 30602 : } /* _pt_thread_death */
841 :
842 20034 : void _PR_InitThreads(
843 : PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs)
844 : {
845 : int rv;
846 : PRThread *thred;
847 :
848 : #ifdef _PR_NEED_PTHREAD_INIT
849 : /*
850 : * On BSD/OS (3.1 and 4.0), the pthread subsystem is lazily
851 : * initialized, but pthread_self() fails to initialize
852 : * pthreads and hence returns a null thread ID if invoked
853 : * by the primordial thread before any other pthread call.
854 : * So we explicitly initialize pthreads here.
855 : */
856 : pthread_init();
857 : #endif
858 :
859 : #if defined(_PR_DCETHREADS) || defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
860 : #if defined(FREEBSD)
861 : {
862 : pthread_attr_t attr;
863 : int policy;
864 : /* get the min and max priorities of the default policy */
865 : pthread_attr_init(&attr);
866 : pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
867 : pthread_attr_getschedpolicy(&attr, &policy);
868 : pt_book.minPrio = sched_get_priority_min(policy);
869 : PR_ASSERT(-1 != pt_book.minPrio);
870 : pt_book.maxPrio = sched_get_priority_max(policy);
871 : PR_ASSERT(-1 != pt_book.maxPrio);
872 : pthread_attr_destroy(&attr);
873 : }
874 : #else
875 : /*
876 : ** These might be function evaluations
877 : */
878 20034 : pt_book.minPrio = PT_PRIO_MIN;
879 20034 : pt_book.maxPrio = PT_PRIO_MAX;
880 : #endif
881 : #endif
882 :
883 20034 : PR_ASSERT(NULL == pt_book.ml);
884 20034 : pt_book.ml = PR_NewLock();
885 20034 : PR_ASSERT(NULL != pt_book.ml);
886 20034 : pt_book.cv = PR_NewCondVar(pt_book.ml);
887 20034 : PR_ASSERT(NULL != pt_book.cv);
888 20034 : thred = PR_NEWZAP(PRThread);
889 20034 : PR_ASSERT(NULL != thred);
890 20034 : thred->arg = NULL;
891 20034 : thred->startFunc = NULL;
892 20034 : thred->priority = priority;
893 20034 : thred->id = pthread_self();
894 :
895 20034 : thred->state = (PT_THREAD_DETACHED | PT_THREAD_PRIMORD);
896 20034 : if (PR_SYSTEM_THREAD == type)
897 : {
898 0 : thred->state |= PT_THREAD_SYSTEM;
899 0 : pt_book.system += 1;
900 0 : pt_book.this_many = 0;
901 : }
902 : else
903 : {
904 20034 : pt_book.user += 1;
905 20034 : pt_book.this_many = 1;
906 : }
907 20034 : thred->next = thred->prev = NULL;
908 20034 : pt_book.first = pt_book.last = thred;
909 :
910 20034 : thred->stack = PR_NEWZAP(PRThreadStack);
911 20034 : PR_ASSERT(thred->stack != NULL);
912 20034 : thred->stack->stackSize = 0;
913 20034 : thred->stack->thr = thred;
914 20034 : _PR_InitializeStack(thred->stack);
915 :
916 : /*
917 : * Create a key for our use to store a backpointer in the pthread
918 : * to our PRThread object. This object gets deleted when the thread
919 : * returns from its root in the case of a detached thread. Other
920 : * threads delete the objects in Join.
921 : *
922 : * NB: The destructor logic seems to have a bug so it isn't used.
923 : * NBB: Oh really? I'm going to give it a spin - AOF 19 June 1998.
924 : * More info - the problem is that pthreads calls the destructor
925 : * eagerly as the thread returns from its root, rather than lazily
926 : * after the thread is joined. Therefore, threads that are joining
927 : * and holding PRThread references are actually holding pointers to
928 : * nothing.
929 : */
930 20034 : rv = _PT_PTHREAD_KEY_CREATE(&pt_book.key, _pt_thread_death);
931 20034 : PR_ASSERT(0 == rv);
932 20034 : rv = pthread_setspecific(pt_book.key, thred);
933 20034 : PR_ASSERT(0 == rv);
934 20034 : PR_SetThreadPriority(thred, priority);
935 20034 : } /* _PR_InitThreads */
936 :
937 : #ifdef __GNUC__
938 : /*
939 : * GCC supports the constructor and destructor attributes as of
940 : * version 2.5.
941 : */
942 : static void _PR_Fini(void) __attribute__ ((destructor));
943 : #elif defined(__SUNPRO_C)
944 : /*
945 : * Sun Studio compiler
946 : */
947 : #pragma fini(_PR_Fini)
948 : static void _PR_Fini(void);
949 : #elif defined(HPUX)
950 : /*
951 : * Current versions of HP C compiler define __HP_cc.
952 : * HP C compiler A.11.01.20 doesn't define __HP_cc.
953 : */
954 : #if defined(__ia64) || defined(_LP64)
955 : #pragma FINI "_PR_Fini"
956 : static void _PR_Fini(void);
957 : #else
958 : /*
959 : * Only HP-UX 10.x style initializers are supported in 32-bit links.
960 : * Need to use the +I PR_HPUX10xInit linker option.
961 : */
962 : #include <dl.h>
963 :
964 : static void _PR_Fini(void);
965 :
966 : void PR_HPUX10xInit(shl_t handle, int loading)
967 : {
968 : /*
969 : * This function is called when a shared library is loaded as well
970 : * as when the shared library is unloaded. Note that it may not
971 : * be called when the user's program terminates.
972 : *
973 : * handle is the shl_load API handle for the shared library being
974 : * initialized.
975 : *
976 : * loading is non-zero at startup and zero at termination.
977 : */
978 : if (loading) {
979 : /* ... do some initializations ... */
980 : } else {
981 : _PR_Fini();
982 : }
983 : }
984 : #endif
985 : #elif defined(AIX)
986 : /* Need to use the -binitfini::_PR_Fini linker option. */
987 : #endif
988 :
989 0 : void _PR_Fini(void)
990 : {
991 : void *thred;
992 : int rv;
993 :
994 0 : if (!_pr_initialized) return;
995 :
996 0 : _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred);
997 0 : if (NULL != thred)
998 : {
999 : /*
1000 : * PR_FALSE, because it is unsafe to call back to the
1001 : * thread private data destructors at final cleanup.
1002 : */
1003 0 : _pt_thread_death_internal(thred, PR_FALSE);
1004 0 : rv = pthread_setspecific(pt_book.key, NULL);
1005 0 : PR_ASSERT(0 == rv);
1006 : }
1007 : /* TODO: free other resources used by NSPR */
1008 : /* _pr_initialized = PR_FALSE; */
1009 : } /* _PR_Fini */
1010 :
1011 140 : PR_IMPLEMENT(PRStatus) PR_Cleanup(void)
1012 : {
1013 140 : PRThread *me = PR_GetCurrentThread();
1014 : int rv;
1015 140 : PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR"));
1016 140 : PR_ASSERT(me->state & PT_THREAD_PRIMORD);
1017 140 : if (me->state & PT_THREAD_PRIMORD)
1018 : {
1019 140 : PR_Lock(pt_book.ml);
1020 280 : while (pt_book.user > pt_book.this_many)
1021 0 : PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT);
1022 140 : if (me->state & PT_THREAD_SYSTEM)
1023 0 : pt_book.system -= 1;
1024 : else
1025 140 : pt_book.user -= 1;
1026 140 : PR_Unlock(pt_book.ml);
1027 :
1028 140 : _PR_MD_EARLY_CLEANUP();
1029 :
1030 140 : _PR_CleanupMW();
1031 140 : _PR_CleanupTime();
1032 140 : _PR_CleanupDtoa();
1033 140 : _PR_CleanupCallOnce();
1034 140 : _PR_ShutdownLinker();
1035 140 : _PR_LogCleanup();
1036 140 : _PR_CleanupNet();
1037 : /* Close all the fd's before calling _PR_CleanupIO */
1038 140 : _PR_CleanupIO();
1039 140 : _PR_CleanupCMon();
1040 :
1041 140 : _pt_thread_death(me);
1042 140 : rv = pthread_setspecific(pt_book.key, NULL);
1043 140 : PR_ASSERT(0 == rv);
1044 : /*
1045 : * I am not sure if it's safe to delete the cv and lock here,
1046 : * since there may still be "system" threads around. If this
1047 : * call isn't immediately prior to exiting, then there's a
1048 : * problem.
1049 : */
1050 140 : if (0 == pt_book.system)
1051 : {
1052 140 : PR_DestroyCondVar(pt_book.cv); pt_book.cv = NULL;
1053 140 : PR_DestroyLock(pt_book.ml); pt_book.ml = NULL;
1054 : }
1055 140 : PR_DestroyLock(_pr_sleeplock);
1056 140 : _pr_sleeplock = NULL;
1057 140 : _PR_CleanupLayerCache();
1058 140 : _PR_CleanupEnv();
1059 : #ifdef _PR_ZONE_ALLOCATOR
1060 140 : _PR_DestroyZones();
1061 : #endif
1062 140 : _pr_initialized = PR_FALSE;
1063 140 : return PR_SUCCESS;
1064 : }
1065 0 : return PR_FAILURE;
1066 : } /* PR_Cleanup */
1067 :
1068 0 : PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status)
1069 : {
1070 0 : _exit(status);
1071 : }
1072 :
1073 0 : PR_IMPLEMENT(PRUint32) PR_GetThreadID(PRThread *thred)
1074 : {
1075 : #if defined(_PR_DCETHREADS)
1076 : return (PRUint32)&thred->id; /* this is really a sham! */
1077 : #else
1078 0 : return (PRUint32)thred->id; /* and I don't know what they will do with it */
1079 : #endif
1080 : }
1081 :
1082 : /*
1083 : * $$$
1084 : * The following two thread-to-processor affinity functions are not
1085 : * yet implemented for pthreads. By the way, these functions should return
1086 : * PRStatus rather than PRInt32 to indicate the success/failure status.
1087 : * $$$
1088 : */
1089 :
1090 0 : PR_IMPLEMENT(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask)
1091 : {
1092 0 : return 0; /* not implemented */
1093 : }
1094 :
1095 0 : PR_IMPLEMENT(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask )
1096 : {
1097 0 : return 0; /* not implemented */
1098 : }
1099 :
1100 : PR_IMPLEMENT(void)
1101 0 : PR_SetThreadDumpProc(PRThread* thread, PRThreadDumpProc dump, void *arg)
1102 : {
1103 0 : thread->dump = dump;
1104 0 : thread->dumpArg = arg;
1105 0 : }
1106 :
1107 : /*
1108 : * Garbage collection support follows.
1109 : */
1110 :
1111 : #if defined(_PR_DCETHREADS)
1112 :
1113 : /*
1114 : * statics for Garbage Collection support. We don't need to protect these
1115 : * signal masks since the garbage collector itself is protected by a lock
1116 : * and multiple threads will not be garbage collecting at the same time.
1117 : */
1118 : static sigset_t javagc_vtalarm_sigmask;
1119 : static sigset_t javagc_intsoff_sigmask;
1120 :
1121 : #else /* defined(_PR_DCETHREADS) */
1122 :
1123 : /* a bogus signal mask for forcing a timed wait */
1124 : /* Not so bogus in AIX as we really do a sigwait */
1125 : static sigset_t sigwait_set;
1126 :
1127 : static struct timespec onemillisec = {0, 1000000L};
1128 : #ifndef PT_NO_SIGTIMEDWAIT
1129 : static struct timespec hundredmillisec = {0, 100000000L};
1130 : #endif
1131 :
1132 : static void suspend_signal_handler(PRIntn sig);
1133 :
1134 : #ifdef PT_NO_SIGTIMEDWAIT
1135 : static void null_signal_handler(PRIntn sig);
1136 : #endif
1137 :
1138 : #endif /* defined(_PR_DCETHREADS) */
1139 :
1140 : /*
1141 : * Linux pthreads use SIGUSR1 and SIGUSR2 internally, which
1142 : * conflict with the use of these two signals in our GC support.
1143 : * So we don't know how to support GC on Linux pthreads.
1144 : */
1145 0 : static void init_pthread_gc_support(void)
1146 : {
1147 : #ifndef SYMBIAN
1148 : PRIntn rv;
1149 :
1150 : #if defined(_PR_DCETHREADS)
1151 : rv = sigemptyset(&javagc_vtalarm_sigmask);
1152 : PR_ASSERT(0 == rv);
1153 : rv = sigaddset(&javagc_vtalarm_sigmask, SIGVTALRM);
1154 : PR_ASSERT(0 == rv);
1155 : #else /* defined(_PR_DCETHREADS) */
1156 : {
1157 : struct sigaction sigact_usr2;
1158 :
1159 0 : sigact_usr2.sa_handler = suspend_signal_handler;
1160 0 : sigact_usr2.sa_flags = SA_RESTART;
1161 0 : sigemptyset (&sigact_usr2.sa_mask);
1162 :
1163 0 : rv = sigaction (SIGUSR2, &sigact_usr2, NULL);
1164 0 : PR_ASSERT(0 == rv);
1165 :
1166 0 : sigemptyset (&sigwait_set);
1167 : #if defined(PT_NO_SIGTIMEDWAIT)
1168 0 : sigaddset (&sigwait_set, SIGUSR1);
1169 : #else
1170 : sigaddset (&sigwait_set, SIGUSR2);
1171 : #endif /* defined(PT_NO_SIGTIMEDWAIT) */
1172 : }
1173 : #if defined(PT_NO_SIGTIMEDWAIT)
1174 : {
1175 : struct sigaction sigact_null;
1176 0 : sigact_null.sa_handler = null_signal_handler;
1177 0 : sigact_null.sa_flags = SA_RESTART;
1178 0 : sigemptyset (&sigact_null.sa_mask);
1179 0 : rv = sigaction (SIGUSR1, &sigact_null, NULL);
1180 0 : PR_ASSERT(0 ==rv);
1181 : }
1182 : #endif /* defined(PT_NO_SIGTIMEDWAIT) */
1183 : #endif /* defined(_PR_DCETHREADS) */
1184 : #endif /* SYMBIAN */
1185 0 : }
1186 :
1187 0 : PR_IMPLEMENT(void) PR_SetThreadGCAble(void)
1188 : {
1189 0 : PR_Lock(pt_book.ml);
1190 0 : PR_GetCurrentThread()->state |= PT_THREAD_GCABLE;
1191 0 : PR_Unlock(pt_book.ml);
1192 0 : }
1193 :
1194 0 : PR_IMPLEMENT(void) PR_ClearThreadGCAble(void)
1195 : {
1196 0 : PR_Lock(pt_book.ml);
1197 0 : PR_GetCurrentThread()->state &= (~PT_THREAD_GCABLE);
1198 0 : PR_Unlock(pt_book.ml);
1199 0 : }
1200 :
1201 : #if defined(DEBUG)
1202 : static PRBool suspendAllOn = PR_FALSE;
1203 : #endif
1204 :
1205 : static PRBool suspendAllSuspended = PR_FALSE;
1206 :
1207 0 : PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg)
1208 : {
1209 0 : PRIntn count = 0;
1210 0 : PRStatus rv = PR_SUCCESS;
1211 0 : PRThread* thred = pt_book.first;
1212 :
1213 : #if defined(DEBUG) || defined(FORCE_PR_ASSERT)
1214 : #if !defined(_PR_DCETHREADS)
1215 0 : PRThread *me = PR_GetCurrentThread();
1216 : #endif
1217 : #endif
1218 :
1219 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_EnumerateThreads\n"));
1220 : /*
1221 : * $$$
1222 : * Need to suspend all threads other than me before doing this.
1223 : * This is really a gross and disgusting thing to do. The only
1224 : * good thing is that since all other threads are suspended, holding
1225 : * the lock during a callback seems like child's play.
1226 : * $$$
1227 : */
1228 0 : PR_ASSERT(suspendAllOn);
1229 :
1230 0 : while (thred != NULL)
1231 : {
1232 : /* Steve Morse, 4-23-97: Note that we can't walk a queue by taking
1233 : * qp->next after applying the function "func". In particular, "func"
1234 : * might remove the thread from the queue and put it into another one in
1235 : * which case qp->next no longer points to the next entry in the original
1236 : * queue.
1237 : *
1238 : * To get around this problem, we save qp->next in qp_next before applying
1239 : * "func" and use that saved value as the next value after applying "func".
1240 : */
1241 0 : PRThread* next = thred->next;
1242 :
1243 0 : if (_PT_IS_GCABLE_THREAD(thred))
1244 : {
1245 : #if !defined(_PR_DCETHREADS)
1246 0 : PR_ASSERT((thred == me) || (thred->suspend & PT_THREAD_SUSPENDED));
1247 : #endif
1248 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
1249 : ("In PR_EnumerateThreads callback thread %p thid = %X\n",
1250 : thred, thred->id));
1251 :
1252 0 : rv = func(thred, count++, arg);
1253 0 : if (rv != PR_SUCCESS)
1254 0 : return rv;
1255 : }
1256 0 : thred = next;
1257 : }
1258 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
1259 : ("End PR_EnumerateThreads count = %d \n", count));
1260 0 : return rv;
1261 : } /* PR_EnumerateThreads */
1262 :
1263 : /*
1264 : * PR_SuspendAll and PR_ResumeAll are called during garbage collection. The strategy
1265 : * we use is to send a SIGUSR2 signal to every gc able thread that we intend to suspend.
1266 : * The signal handler will record the stack pointer and will block until resumed by
1267 : * the resume call. Since the signal handler is the last routine called for the
1268 : * suspended thread, the stack pointer will also serve as a place where all the
1269 : * registers have been saved on the stack for the previously executing routines.
1270 : *
1271 : * Through global variables, we also make sure that PR_Suspend and PR_Resume does not
1272 : * proceed until the thread is suspended or resumed.
1273 : */
1274 :
1275 : #if !defined(_PR_DCETHREADS)
1276 :
1277 : /*
1278 : * In the signal handler, we can not use condition variable notify or wait.
1279 : * This does not work consistently across all pthread platforms. We also can not
1280 : * use locking since that does not seem to work reliably across platforms.
1281 : * Only thing we can do is yielding while testing for a global condition
1282 : * to change. This does work on pthread supported platforms. We may have
1283 : * to play with priortities if there are any problems detected.
1284 : */
1285 :
1286 : /*
1287 : * In AIX, you cannot use ANY pthread calls in the signal handler except perhaps
1288 : * pthread_yield. But that is horribly inefficient. Hence we use only sigwait, no
1289 : * sigtimedwait is available. We need to use another user signal, SIGUSR1. Actually
1290 : * SIGUSR1 is also used by exec in Java. So our usage here breaks the exec in Java,
1291 : * for AIX. You cannot use pthread_cond_wait or pthread_delay_np in the signal
1292 : * handler as all synchronization mechanisms just break down.
1293 : */
1294 :
1295 : #if defined(PT_NO_SIGTIMEDWAIT)
1296 0 : static void null_signal_handler(PRIntn sig)
1297 : {
1298 : return;
1299 : }
1300 : #endif
1301 :
1302 0 : static void suspend_signal_handler(PRIntn sig)
1303 : {
1304 0 : PRThread *me = PR_GetCurrentThread();
1305 :
1306 0 : PR_ASSERT(me != NULL);
1307 0 : PR_ASSERT(_PT_IS_GCABLE_THREAD(me));
1308 0 : PR_ASSERT((me->suspend & PT_THREAD_SUSPENDED) == 0);
1309 :
1310 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
1311 : ("Begin suspend_signal_handler thred %p thread id = %X\n",
1312 : me, me->id));
1313 :
1314 : /*
1315 : * save stack pointer
1316 : */
1317 0 : me->sp = &me;
1318 :
1319 : /*
1320 : At this point, the thread's stack pointer has been saved,
1321 : And it is going to enter a wait loop until it is resumed.
1322 : So it is _really_ suspended
1323 : */
1324 :
1325 0 : me->suspend |= PT_THREAD_SUSPENDED;
1326 :
1327 : /*
1328 : * now, block current thread
1329 : */
1330 : #if defined(PT_NO_SIGTIMEDWAIT)
1331 0 : pthread_cond_signal(&me->suspendResumeCV);
1332 0 : while (me->suspend & PT_THREAD_SUSPENDED)
1333 : {
1334 : #if !defined(FREEBSD) && !defined(NETBSD) && !defined(OPENBSD) \
1335 : && !defined(BSDI) && !defined(UNIXWARE) \
1336 : && !defined(DARWIN) && !defined(RISCOS) \
1337 : && !defined(SYMBIAN) /*XXX*/
1338 : PRIntn rv;
1339 0 : sigwait(&sigwait_set, &rv);
1340 : #endif
1341 : }
1342 0 : me->suspend |= PT_THREAD_RESUMED;
1343 0 : pthread_cond_signal(&me->suspendResumeCV);
1344 : #else /* defined(PT_NO_SIGTIMEDWAIT) */
1345 : while (me->suspend & PT_THREAD_SUSPENDED)
1346 : {
1347 : PRIntn rv = sigtimedwait(&sigwait_set, NULL, &hundredmillisec);
1348 : PR_ASSERT(-1 == rv);
1349 : }
1350 : me->suspend |= PT_THREAD_RESUMED;
1351 : #endif
1352 :
1353 : /*
1354 : * At this point, thread has been resumed, so set a global condition.
1355 : * The ResumeAll needs to know that this has really been resumed.
1356 : * So the signal handler sets a flag which PR_ResumeAll will reset.
1357 : * The PR_ResumeAll must reset this flag ...
1358 : */
1359 :
1360 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
1361 : ("End suspend_signal_handler thred = %p tid = %X\n", me, me->id));
1362 0 : } /* suspend_signal_handler */
1363 :
1364 0 : static void pt_SuspendSet(PRThread *thred)
1365 : {
1366 : PRIntn rv;
1367 :
1368 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
1369 : ("pt_SuspendSet thred %p thread id = %X\n", thred, thred->id));
1370 :
1371 :
1372 : /*
1373 : * Check the thread state and signal the thread to suspend
1374 : */
1375 :
1376 0 : PR_ASSERT((thred->suspend & PT_THREAD_SUSPENDED) == 0);
1377 :
1378 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
1379 : ("doing pthread_kill in pt_SuspendSet thred %p tid = %X\n",
1380 : thred, thred->id));
1381 : #if defined(SYMBIAN)
1382 : /* All signal group functions are not implemented in Symbian OS */
1383 : rv = 0;
1384 : #else
1385 0 : rv = pthread_kill (thred->id, SIGUSR2);
1386 : #endif
1387 0 : PR_ASSERT(0 == rv);
1388 0 : }
1389 :
1390 0 : static void pt_SuspendTest(PRThread *thred)
1391 : {
1392 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
1393 : ("Begin pt_SuspendTest thred %p thread id = %X\n", thred, thred->id));
1394 :
1395 :
1396 : /*
1397 : * Wait for the thread to be really suspended. This happens when the
1398 : * suspend signal handler stores the stack pointer and sets the state
1399 : * to suspended.
1400 : */
1401 :
1402 : #if defined(PT_NO_SIGTIMEDWAIT)
1403 0 : pthread_mutex_lock(&thred->suspendResumeMutex);
1404 0 : while ((thred->suspend & PT_THREAD_SUSPENDED) == 0)
1405 : {
1406 0 : pthread_cond_timedwait(
1407 : &thred->suspendResumeCV, &thred->suspendResumeMutex, &onemillisec);
1408 : }
1409 0 : pthread_mutex_unlock(&thred->suspendResumeMutex);
1410 : #else
1411 : while ((thred->suspend & PT_THREAD_SUSPENDED) == 0)
1412 : {
1413 : PRIntn rv = sigtimedwait(&sigwait_set, NULL, &onemillisec);
1414 : PR_ASSERT(-1 == rv);
1415 : }
1416 : #endif
1417 :
1418 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
1419 : ("End pt_SuspendTest thred %p tid %X\n", thred, thred->id));
1420 0 : } /* pt_SuspendTest */
1421 :
1422 0 : static void pt_ResumeSet(PRThread *thred)
1423 : {
1424 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
1425 : ("pt_ResumeSet thred %p thread id = %X\n", thred, thred->id));
1426 :
1427 : /*
1428 : * Clear the global state and set the thread state so that it will
1429 : * continue past yield loop in the suspend signal handler
1430 : */
1431 :
1432 0 : PR_ASSERT(thred->suspend & PT_THREAD_SUSPENDED);
1433 :
1434 :
1435 0 : thred->suspend &= ~PT_THREAD_SUSPENDED;
1436 :
1437 : #if defined(PT_NO_SIGTIMEDWAIT)
1438 : #if defined(SYMBIAN)
1439 : /* All signal group functions are not implemented in Symbian OS */
1440 : #else
1441 0 : pthread_kill(thred->id, SIGUSR1);
1442 : #endif
1443 : #endif
1444 :
1445 0 : } /* pt_ResumeSet */
1446 :
1447 0 : static void pt_ResumeTest(PRThread *thred)
1448 : {
1449 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
1450 : ("Begin pt_ResumeTest thred %p thread id = %X\n", thred, thred->id));
1451 :
1452 : /*
1453 : * Wait for the threads resume state to change
1454 : * to indicate it is really resumed
1455 : */
1456 : #if defined(PT_NO_SIGTIMEDWAIT)
1457 0 : pthread_mutex_lock(&thred->suspendResumeMutex);
1458 0 : while ((thred->suspend & PT_THREAD_RESUMED) == 0)
1459 : {
1460 0 : pthread_cond_timedwait(
1461 : &thred->suspendResumeCV, &thred->suspendResumeMutex, &onemillisec);
1462 : }
1463 0 : pthread_mutex_unlock(&thred->suspendResumeMutex);
1464 : #else
1465 : while ((thred->suspend & PT_THREAD_RESUMED) == 0) {
1466 : PRIntn rv = sigtimedwait(&sigwait_set, NULL, &onemillisec);
1467 : PR_ASSERT(-1 == rv);
1468 : }
1469 : #endif
1470 :
1471 0 : thred->suspend &= ~PT_THREAD_RESUMED;
1472 :
1473 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, (
1474 : "End pt_ResumeTest thred %p tid %X\n", thred, thred->id));
1475 0 : } /* pt_ResumeTest */
1476 :
1477 : static pthread_once_t pt_gc_support_control = PTHREAD_ONCE_INIT;
1478 :
1479 0 : PR_IMPLEMENT(void) PR_SuspendAll(void)
1480 : {
1481 : #ifdef DEBUG
1482 : PRIntervalTime stime, etime;
1483 : #endif
1484 0 : PRThread* thred = pt_book.first;
1485 0 : PRThread *me = PR_GetCurrentThread();
1486 : int rv;
1487 :
1488 0 : rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support);
1489 0 : PR_ASSERT(0 == rv);
1490 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n"));
1491 : /*
1492 : * Stop all threads which are marked GC able.
1493 : */
1494 0 : PR_Lock(pt_book.ml);
1495 : #ifdef DEBUG
1496 0 : suspendAllOn = PR_TRUE;
1497 0 : stime = PR_IntervalNow();
1498 : #endif
1499 0 : while (thred != NULL)
1500 : {
1501 0 : if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))
1502 0 : pt_SuspendSet(thred);
1503 0 : thred = thred->next;
1504 : }
1505 :
1506 : /* Wait till they are really suspended */
1507 0 : thred = pt_book.first;
1508 0 : while (thred != NULL)
1509 : {
1510 0 : if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))
1511 0 : pt_SuspendTest(thred);
1512 0 : thred = thred->next;
1513 : }
1514 :
1515 0 : suspendAllSuspended = PR_TRUE;
1516 :
1517 : #ifdef DEBUG
1518 0 : etime = PR_IntervalNow();
1519 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,\
1520 : ("End PR_SuspendAll (time %dms)\n",
1521 : PR_IntervalToMilliseconds(etime - stime)));
1522 : #endif
1523 0 : } /* PR_SuspendAll */
1524 :
1525 0 : PR_IMPLEMENT(void) PR_ResumeAll(void)
1526 : {
1527 : #ifdef DEBUG
1528 : PRIntervalTime stime, etime;
1529 : #endif
1530 0 : PRThread* thred = pt_book.first;
1531 0 : PRThread *me = PR_GetCurrentThread();
1532 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n"));
1533 : /*
1534 : * Resume all previously suspended GC able threads.
1535 : */
1536 0 : suspendAllSuspended = PR_FALSE;
1537 : #ifdef DEBUG
1538 0 : stime = PR_IntervalNow();
1539 : #endif
1540 :
1541 0 : while (thred != NULL)
1542 : {
1543 0 : if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))
1544 0 : pt_ResumeSet(thred);
1545 0 : thred = thred->next;
1546 : }
1547 :
1548 0 : thred = pt_book.first;
1549 0 : while (thred != NULL)
1550 : {
1551 0 : if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))
1552 0 : pt_ResumeTest(thred);
1553 0 : thred = thred->next;
1554 : }
1555 :
1556 0 : PR_Unlock(pt_book.ml);
1557 : #ifdef DEBUG
1558 0 : suspendAllOn = PR_FALSE;
1559 0 : etime = PR_IntervalNow();
1560 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
1561 : ("End PR_ResumeAll (time %dms)\n",
1562 : PR_IntervalToMilliseconds(etime - stime)));
1563 : #endif
1564 0 : } /* PR_ResumeAll */
1565 :
1566 : /* Return the stack pointer for the given thread- used by the GC */
1567 0 : PR_IMPLEMENT(void *)PR_GetSP(PRThread *thred)
1568 : {
1569 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
1570 : ("in PR_GetSP thred %p thid = %X, sp = %p\n",
1571 : thred, thred->id, thred->sp));
1572 0 : return thred->sp;
1573 : } /* PR_GetSP */
1574 :
1575 : #else /* !defined(_PR_DCETHREADS) */
1576 :
1577 : static pthread_once_t pt_gc_support_control = pthread_once_init;
1578 :
1579 : /*
1580 : * For DCE threads, there is no pthread_kill or a way of suspending or resuming a
1581 : * particular thread. We will just disable the preemption (virtual timer alarm) and
1582 : * let the executing thread finish the garbage collection. This stops all other threads
1583 : * (GC able or not) and is very inefficient but there is no other choice.
1584 : */
1585 : PR_IMPLEMENT(void) PR_SuspendAll()
1586 : {
1587 : PRIntn rv;
1588 :
1589 : rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support);
1590 : PR_ASSERT(0 == rv); /* returns -1 on failure */
1591 : #ifdef DEBUG
1592 : suspendAllOn = PR_TRUE;
1593 : #endif
1594 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n"));
1595 : /*
1596 : * turn off preemption - i.e add virtual alarm signal to the set of
1597 : * blocking signals
1598 : */
1599 : rv = sigprocmask(
1600 : SIG_BLOCK, &javagc_vtalarm_sigmask, &javagc_intsoff_sigmask);
1601 : PR_ASSERT(0 == rv);
1602 : suspendAllSuspended = PR_TRUE;
1603 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_SuspendAll\n"));
1604 : } /* PR_SuspendAll */
1605 :
1606 : PR_IMPLEMENT(void) PR_ResumeAll()
1607 : {
1608 : PRIntn rv;
1609 :
1610 : suspendAllSuspended = PR_FALSE;
1611 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n"));
1612 : /* turn on preemption - i.e re-enable virtual alarm signal */
1613 :
1614 : rv = sigprocmask(SIG_SETMASK, &javagc_intsoff_sigmask, (sigset_t *)NULL);
1615 : PR_ASSERT(0 == rv);
1616 : #ifdef DEBUG
1617 : suspendAllOn = PR_FALSE;
1618 : #endif
1619 :
1620 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_ResumeAll\n"));
1621 : } /* PR_ResumeAll */
1622 :
1623 : /* Return the stack pointer for the given thread- used by the GC */
1624 : PR_IMPLEMENT(void*)PR_GetSP(PRThread *thred)
1625 : {
1626 : pthread_t tid = thred->id;
1627 : char *thread_tcb, *top_sp;
1628 :
1629 : /*
1630 : * For HPUX DCE threads, pthread_t is a struct with the
1631 : * following three fields (see pthread.h, dce/cma.h):
1632 : * cma_t_address field1;
1633 : * short int field2;
1634 : * short int field3;
1635 : * where cma_t_address is typedef'd to be either void*
1636 : * or char*.
1637 : */
1638 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_GetSP\n"));
1639 : thread_tcb = (char*)tid.field1;
1640 : top_sp = *(char**)(thread_tcb + 128);
1641 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_GetSP %p \n", top_sp));
1642 : return top_sp;
1643 : } /* PR_GetSP */
1644 :
1645 : #endif /* !defined(_PR_DCETHREADS) */
1646 :
1647 : #endif /* defined(_PR_PTHREADS) || defined(_PR_DCETHREADS) */
1648 :
1649 : /* ptthread.c */
|