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

Side by Side Diff: nspr/pr/src/pthreads/ptthread.c

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

Powered by Google App Engine
This is Rietveld 408576698