comparison nspr/pr/src/pthreads/ptthread.c @ 0:1e5118fa0cb1

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