Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(324)

Side by Side Diff: mozilla/nsprpub/pr/src/pthreads/ptthread.c

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

Powered by Google App Engine
This is Rietveld 408576698