Line data Source code
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 67 : static int pt_RelativePriority(int nice, PRThreadPriority pri)
97 : {
98 67 : return nice + (1 - pri);
99 : }
100 : #endif
101 :
102 : /*
103 : ** Initialize a stack for a native pthread thread
104 : */
105 69 : static void _PR_InitializeStack(PRThreadStack *ts)
106 : {
107 69 : if( ts && (ts->stackTop == 0) ) {
108 69 : ts->allocBase = (char *) &ts;
109 69 : 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 69 : ts->stackTop = ts->allocBase;
119 69 : ts->stackBottom = ts->allocBase - ts->stackSize;
120 : #endif
121 : }
122 69 : }
123 :
124 66 : static void *_pt_root(void *arg)
125 : {
126 : PRIntn rv;
127 66 : PRThread *thred = (PRThread*)arg;
128 66 : PRBool detached = (thred->state & PT_THREAD_DETACHED) ? PR_TRUE : PR_FALSE;
129 66 : 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 66 : tid = gettid();
140 66 : errno = 0;
141 66 : 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 66 : if (errno == 0) {
146 66 : 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 66 : _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 66 : rv = pthread_setspecific(pt_book.key, thred);
175 66 : PR_ASSERT(0 == rv);
176 :
177 : /* make the thread visible to the rest of the runtime */
178 66 : 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 66 : if (!thred->idSet)
188 : {
189 0 : thred->id = id;
190 0 : thred->idSet = PR_TRUE;
191 : }
192 : else
193 : {
194 66 : PR_ASSERT(pthread_equal(thred->id, id));
195 : }
196 :
197 : #ifdef _PR_NICE_PRIORITY_SCHEDULING
198 66 : thred->tid = tid;
199 66 : PR_NotifyAllCondVar(pt_book.cv);
200 : #endif
201 :
202 : /* If this is a GCABLE thread, set its state appropriately */
203 66 : if (thred->suspend & PT_THREAD_SETGCABLE)
204 0 : thred->state |= PT_THREAD_GCABLE;
205 66 : thred->suspend = 0;
206 :
207 66 : thred->prev = pt_book.last;
208 66 : if (pt_book.last)
209 66 : pt_book.last->next = thred;
210 : else
211 0 : pt_book.first = thred;
212 66 : thred->next = NULL;
213 66 : pt_book.last = thred;
214 66 : PR_Unlock(pt_book.ml);
215 :
216 66 : thred->startFunc(thred->arg); /* make visible to the client */
217 :
218 : /* unhook the thread from the runtime */
219 2 : 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 2 : if (detached)
226 : {
227 2 : while (!thred->okToDelete)
228 0 : PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT);
229 : }
230 :
231 2 : if (thred->state & PT_THREAD_SYSTEM)
232 0 : pt_book.system -= 1;
233 2 : else if (--pt_book.user == pt_book.this_many)
234 0 : PR_NotifyAllCondVar(pt_book.cv);
235 2 : if (NULL == thred->prev)
236 0 : pt_book.first = thred->next;
237 : else
238 2 : thred->prev->next = thred->next;
239 2 : if (NULL == thred->next)
240 1 : pt_book.last = thred->prev;
241 : else
242 1 : thred->next->prev = thred->prev;
243 2 : 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 2 : if (PR_FALSE == detached)
254 : {
255 : /* Call TPD destructors on this thread. */
256 1 : _PR_DestroyThreadPrivate(thred);
257 1 : rv = pthread_setspecific(pt_book.key, NULL);
258 1 : PR_ASSERT(0 == rv);
259 : }
260 :
261 2 : return NULL;
262 : } /* _pt_root */
263 :
264 22 : static PRThread* pt_AttachThread(void)
265 : {
266 22 : 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 22 : if (!_pr_initialized) return NULL;
278 :
279 : /* PR_NEWZAP must not call PR_GetCurrentThread() */
280 22 : thred = PR_NEWZAP(PRThread);
281 22 : if (NULL != thred)
282 : {
283 : int rv;
284 :
285 22 : thred->priority = PR_PRIORITY_NORMAL;
286 22 : thred->id = pthread_self();
287 22 : thred->idSet = PR_TRUE;
288 : #ifdef _PR_NICE_PRIORITY_SCHEDULING
289 22 : thred->tid = gettid();
290 : #endif
291 22 : rv = pthread_setspecific(pt_book.key, thred);
292 22 : PR_ASSERT(0 == rv);
293 :
294 22 : thred->state = PT_THREAD_GLOBAL | PT_THREAD_FOREIGN;
295 22 : PR_Lock(pt_book.ml);
296 :
297 : /* then put it into the list */
298 22 : thred->prev = pt_book.last;
299 22 : if (pt_book.last)
300 22 : pt_book.last->next = thred;
301 : else
302 0 : pt_book.first = thred;
303 22 : thred->next = NULL;
304 22 : pt_book.last = thred;
305 22 : PR_Unlock(pt_book.ml);
306 :
307 : }
308 22 : return thred; /* may be NULL */
309 : } /* pt_AttachThread */
310 :
311 66 : 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 66 : if (!_pr_initialized) _PR_ImplicitInitialization();
321 :
322 66 : if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)priority)
323 0 : priority = PR_PRIORITY_FIRST;
324 66 : else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)priority)
325 0 : priority = PR_PRIORITY_LAST;
326 :
327 66 : rv = _PT_PTHREAD_ATTR_INIT(&tattr);
328 66 : PR_ASSERT(0 == rv);
329 :
330 66 : 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 66 : rv = pthread_attr_setdetachstate(&tattr,
365 : ((PR_JOINABLE_THREAD == state) ?
366 : PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED));
367 66 : 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 66 : 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 3 : rv = pthread_attr_setstacksize(&tattr, stackSize);
380 3 : PR_ASSERT(0 == rv);
381 : }
382 :
383 66 : thred = PR_NEWZAP(PRThread);
384 66 : if (NULL == thred)
385 : {
386 0 : PR_SetError(PR_OUT_OF_MEMORY_ERROR, errno);
387 0 : goto done;
388 : }
389 : else
390 : {
391 : pthread_t id;
392 :
393 66 : thred->arg = arg;
394 66 : thred->startFunc = start;
395 66 : thred->priority = priority;
396 66 : if (PR_UNJOINABLE_THREAD == state)
397 2 : thred->state |= PT_THREAD_DETACHED;
398 :
399 66 : if (PR_LOCAL_THREAD == scope)
400 0 : 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 66 : if (PR_GLOBAL_THREAD == scope)
419 66 : thred->state |= PT_THREAD_GLOBAL;
420 0 : else if (PR_GLOBAL_BOUND_THREAD == scope)
421 0 : thred->state |= (PT_THREAD_GLOBAL | PT_THREAD_BOUND);
422 : else /* force it global */
423 0 : thred->state |= PT_THREAD_GLOBAL;
424 66 : if (PR_SYSTEM_THREAD == type)
425 1 : thred->state |= PT_THREAD_SYSTEM;
426 :
427 66 : thred->suspend =(isGCAble) ? PT_THREAD_SETGCABLE : 0;
428 :
429 66 : thred->stack = PR_NEWZAP(PRThreadStack);
430 66 : if (thred->stack == NULL) {
431 0 : PRIntn oserr = errno;
432 0 : PR_Free(thred); /* all that work ... poof! */
433 0 : PR_SetError(PR_OUT_OF_MEMORY_ERROR, oserr);
434 0 : thred = NULL; /* and for what? */
435 0 : goto done;
436 : }
437 66 : thred->stack->stackSize = stackSize;
438 66 : thred->stack->thr = thred;
439 :
440 : #ifdef PT_NO_SIGTIMEDWAIT
441 66 : pthread_mutex_init(&thred->suspendResumeMutex,NULL);
442 66 : pthread_cond_init(&thred->suspendResumeCV,NULL);
443 : #endif
444 :
445 : /* make the thread counted to the rest of the runtime */
446 66 : PR_Lock(pt_book.ml);
447 66 : if (PR_SYSTEM_THREAD == type)
448 1 : pt_book.system += 1;
449 65 : else pt_book.user += 1;
450 66 : 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 66 : rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred);
458 :
459 : #if !defined(_PR_DCETHREADS)
460 66 : 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 0 : pt_schedpriv = EPERM;
475 0 : 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 0 : rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred);
484 : }
485 : #endif
486 :
487 66 : if (0 != rv)
488 : {
489 : #if defined(_PR_DCETHREADS)
490 : PRIntn oserr = errno;
491 : #else
492 0 : PRIntn oserr = rv;
493 : #endif
494 0 : PR_Lock(pt_book.ml);
495 0 : if (thred->state & PT_THREAD_SYSTEM)
496 0 : pt_book.system -= 1;
497 0 : else if (--pt_book.user == pt_book.this_many)
498 0 : PR_NotifyAllCondVar(pt_book.cv);
499 0 : PR_Unlock(pt_book.ml);
500 :
501 0 : PR_Free(thred->stack);
502 0 : PR_Free(thred); /* all that work ... poof! */
503 0 : PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, oserr);
504 0 : thred = NULL; /* and for what? */
505 0 : goto done;
506 : }
507 :
508 66 : 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 66 : if (!thred->idSet)
515 : {
516 66 : thred->id = id;
517 66 : thred->idSet = PR_TRUE;
518 : }
519 : else
520 : {
521 0 : 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 66 : if (PR_UNJOINABLE_THREAD == state)
529 : {
530 2 : thred->okToDelete = PR_TRUE;
531 2 : PR_NotifyAllCondVar(pt_book.cv);
532 : }
533 66 : PR_Unlock(pt_book.ml);
534 : }
535 :
536 : done:
537 66 : rv = _PT_PTHREAD_ATTR_DESTROY(&tattr);
538 66 : PR_ASSERT(0 == rv);
539 :
540 66 : 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 66 : return _PR_CreateThread(
549 : type, start, arg, priority, scope, state, stackSize, PR_FALSE);
550 : } /* PR_CreateThread */
551 :
552 0 : 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 0 : return _PR_CreateThread(
558 : type, start, arg, priority, scope, state, stackSize, PR_TRUE);
559 : } /* PR_CreateThreadGCAble */
560 :
561 0 : PR_IMPLEMENT(void*) GetExecutionEnvironment(PRThread *thred)
562 : {
563 0 : return thred->environment;
564 : } /* GetExecutionEnvironment */
565 :
566 0 : PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread *thred, void *env)
567 : {
568 0 : thred->environment = env;
569 0 : } /* SetExecutionEnvironment */
570 :
571 0 : PR_IMPLEMENT(PRThread*) PR_AttachThread(
572 : PRThreadType type, PRThreadPriority priority, PRThreadStack *stack)
573 : {
574 0 : return PR_GetCurrentThread();
575 : } /* PR_AttachThread */
576 :
577 :
578 : PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thred)
579 : {
580 1 : int rv = -1;
581 1 : void *result = NULL;
582 1 : PR_ASSERT(thred != NULL);
583 :
584 1 : if ((0xafafafaf == thred->state)
585 1 : || (PT_THREAD_DETACHED == (PT_THREAD_DETACHED & thred->state))
586 1 : || (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 0 : PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
595 0 : PR_LogPrint(
596 : "PR_JoinThread: %p not joinable | already smashed\n", thred);
597 : }
598 : else
599 : {
600 1 : pthread_t id = thred->id;
601 1 : rv = pthread_join(id, &result);
602 1 : PR_ASSERT(rv == 0 && result == NULL);
603 1 : 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 1 : _pt_thread_death_internal(thred, PR_FALSE);
614 : }
615 : else
616 : {
617 : PRErrorCode prerror;
618 0 : switch (rv)
619 : {
620 : case EINVAL: /* not a joinable thread */
621 : case ESRCH: /* no thread with given ID */
622 0 : prerror = PR_INVALID_ARGUMENT_ERROR;
623 0 : break;
624 : case EDEADLK: /* a thread joining with itself */
625 0 : prerror = PR_DEADLOCK_ERROR;
626 0 : break;
627 : default:
628 0 : prerror = PR_UNKNOWN_ERROR;
629 0 : break;
630 : }
631 0 : PR_SetError(prerror, rv);
632 : }
633 : }
634 1 : return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
635 : } /* PR_JoinThread */
636 :
637 0 : PR_IMPLEMENT(void) PR_DetachThread(void)
638 : {
639 : void *thred;
640 : int rv;
641 :
642 0 : _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred);
643 0 : if (NULL == thred) return;
644 0 : _pt_thread_death(thred);
645 0 : rv = pthread_setspecific(pt_book.key, NULL);
646 0 : PR_ASSERT(0 == rv);
647 : } /* PR_DetachThread */
648 :
649 : PR_IMPLEMENT(PRThread*) PR_GetCurrentThread(void)
650 : {
651 : void *thred;
652 :
653 5603327 : if (!_pr_initialized) _PR_ImplicitInitialization();
654 :
655 5603327 : _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred);
656 5603645 : if (NULL == thred) thred = pt_AttachThread();
657 5603655 : PR_ASSERT(NULL != thred);
658 5603655 : return (PRThread*)thred;
659 : } /* PR_GetCurrentThread */
660 :
661 : PR_IMPLEMENT(PRThreadScope) PR_GetThreadScope(const PRThread *thred)
662 : {
663 0 : return (thred->state & PT_THREAD_BOUND) ?
664 0 : PR_GLOBAL_BOUND_THREAD : PR_GLOBAL_THREAD;
665 : } /* PR_GetThreadScope() */
666 :
667 : PR_IMPLEMENT(PRThreadType) PR_GetThreadType(const PRThread *thred)
668 : {
669 0 : return (thred->state & PT_THREAD_SYSTEM) ?
670 0 : PR_SYSTEM_THREAD : PR_USER_THREAD;
671 : }
672 :
673 : PR_IMPLEMENT(PRThreadState) PR_GetThreadState(const PRThread *thred)
674 : {
675 0 : return (thred->state & PT_THREAD_DETACHED) ?
676 0 : PR_UNJOINABLE_THREAD : PR_JOINABLE_THREAD;
677 : } /* PR_GetThreadState */
678 :
679 : PR_IMPLEMENT(PRThreadPriority) PR_GetThreadPriority(const PRThread *thred)
680 : {
681 0 : PR_ASSERT(thred != NULL);
682 0 : return thred->priority;
683 : } /* PR_GetThreadPriority */
684 :
685 : PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred, PRThreadPriority newPri)
686 : {
687 : PRIntn rv;
688 :
689 1 : PR_ASSERT(NULL != thred);
690 :
691 1 : if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)newPri)
692 0 : newPri = PR_PRIORITY_FIRST;
693 1 : else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)newPri)
694 0 : 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 scheduling privilege"));
714 : }
715 : }
716 : if (rv != 0)
717 : rv = -1;
718 : }
719 : #elif defined(_PR_NICE_PRIORITY_SCHEDULING)
720 1 : PR_Lock(pt_book.ml);
721 2 : while (thred->tid == 0)
722 0 : PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT);
723 1 : PR_Unlock(pt_book.ml);
724 :
725 1 : errno = 0;
726 1 : rv = getpriority(PRIO_PROCESS, 0);
727 :
728 : /* Do not proceed unless we know the main thread's nice value. */
729 1 : if (errno == 0) {
730 1 : rv = setpriority(PRIO_PROCESS, thred->tid,
731 : pt_RelativePriority(rv, newPri));
732 :
733 1 : 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 0 : 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 1 : thred->priority = newPri;
748 1 : } /* 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 0 : PR_ASSERT(NULL != thred);
773 0 : if (NULL == thred) return PR_FAILURE;
774 :
775 0 : thred->state |= PT_THREAD_ABORTED;
776 :
777 0 : cv = thred->waiting;
778 0 : if ((NULL != cv) && !thred->interrupt_blocked)
779 : {
780 : PRIntn rv;
781 0 : (void)PR_ATOMIC_INCREMENT(&cv->notify_pending);
782 0 : rv = pthread_cond_broadcast(&cv->cv);
783 0 : PR_ASSERT(0 == rv);
784 0 : if (0 > PR_ATOMIC_DECREMENT(&cv->notify_pending))
785 0 : PR_DestroyCondVar(cv);
786 : }
787 0 : return PR_SUCCESS;
788 : } /* PR_Interrupt */
789 :
790 : PR_IMPLEMENT(void) PR_ClearInterrupt(void)
791 : {
792 0 : PRThread *me = PR_GetCurrentThread();
793 0 : me->state &= ~PT_THREAD_ABORTED;
794 0 : } /* PR_ClearInterrupt */
795 :
796 : PR_IMPLEMENT(void) PR_BlockInterrupt(void)
797 : {
798 0 : PRThread *me = PR_GetCurrentThread();
799 0 : _PT_THREAD_BLOCK_INTERRUPT(me);
800 0 : } /* PR_BlockInterrupt */
801 :
802 : PR_IMPLEMENT(void) PR_UnblockInterrupt(void)
803 : {
804 0 : PRThread *me = PR_GetCurrentThread();
805 0 : _PT_THREAD_UNBLOCK_INTERRUPT(me);
806 0 : } /* PR_UnblockInterrupt */
807 :
808 0 : PR_IMPLEMENT(PRStatus) PR_Yield(void)
809 : {
810 : static PRBool warning = PR_TRUE;
811 0 : if (warning) warning = _PR_Obsolete(
812 : "PR_Yield()", "PR_Sleep(PR_INTERVAL_NO_WAIT)");
813 0 : return PR_Sleep(PR_INTERVAL_NO_WAIT);
814 : }
815 :
816 : PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime ticks)
817 : {
818 0 : PRStatus rv = PR_SUCCESS;
819 :
820 0 : if (!_pr_initialized) _PR_ImplicitInitialization();
821 :
822 0 : if (PR_INTERVAL_NO_WAIT == ticks)
823 : {
824 0 : _PT_PTHREAD_YIELD();
825 : }
826 : else
827 : {
828 : PRCondVar *cv;
829 : PRIntervalTime timein;
830 :
831 0 : timein = PR_IntervalNow();
832 0 : cv = PR_NewCondVar(_pr_sleeplock);
833 0 : PR_ASSERT(cv != NULL);
834 0 : PR_Lock(_pr_sleeplock);
835 : do
836 : {
837 0 : PRIntervalTime now = PR_IntervalNow();
838 0 : PRIntervalTime delta = now - timein;
839 0 : if (delta > ticks) break;
840 0 : rv = PR_WaitCondVar(cv, ticks - delta);
841 0 : } while (PR_SUCCESS == rv);
842 0 : PR_Unlock(_pr_sleeplock);
843 0 : PR_DestroyCondVar(cv);
844 : }
845 0 : return rv;
846 : } /* PR_Sleep */
847 :
848 1 : static void _pt_thread_death(void *arg)
849 : {
850 : void *thred;
851 : int rv;
852 :
853 1 : _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred);
854 1 : if (NULL == thred)
855 : {
856 : /*
857 : * Have PR_GetCurrentThread return the expected value to the
858 : * destructors.
859 : */
860 1 : rv = pthread_setspecific(pt_book.key, arg);
861 1 : PR_ASSERT(0 == rv);
862 : }
863 :
864 : /* PR_TRUE for: call destructors */
865 1 : _pt_thread_death_internal(arg, PR_TRUE);
866 :
867 1 : if (NULL == thred)
868 : {
869 1 : rv = pthread_setspecific(pt_book.key, NULL);
870 1 : PR_ASSERT(0 == rv);
871 : }
872 1 : }
873 :
874 2 : static void _pt_thread_death_internal(void *arg, PRBool callDestructors)
875 : {
876 2 : PRThread *thred = (PRThread*)arg;
877 :
878 2 : if (thred->state & (PT_THREAD_FOREIGN|PT_THREAD_PRIMORD))
879 : {
880 0 : PR_Lock(pt_book.ml);
881 0 : if (NULL == thred->prev)
882 0 : pt_book.first = thred->next;
883 : else
884 0 : thred->prev->next = thred->next;
885 0 : if (NULL == thred->next)
886 0 : pt_book.last = thred->prev;
887 : else
888 0 : thred->next->prev = thred->prev;
889 0 : PR_Unlock(pt_book.ml);
890 : }
891 2 : if (callDestructors)
892 1 : _PR_DestroyThreadPrivate(thred);
893 2 : PR_Free(thred->privateData);
894 2 : if (NULL != thred->errorString)
895 0 : PR_Free(thred->errorString);
896 2 : if (NULL != thred->name)
897 1 : PR_Free(thred->name);
898 2 : PR_Free(thred->stack);
899 2 : if (NULL != thred->syspoll_list)
900 0 : 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 2 : memset(thred, 0xaf, sizeof(PRThread));
907 : #endif /* defined(DEBUG) */
908 2 : PR_Free(thred);
909 2 : } /* _pt_thread_death */
910 :
911 3 : void _PR_InitThreads(
912 : PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs)
913 : {
914 : int rv;
915 : PRThread *thred;
916 :
917 3 : 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 3 : PR_ASSERT(NULL == pt_book.ml);
955 3 : pt_book.ml = PR_NewLock();
956 3 : PR_ASSERT(NULL != pt_book.ml);
957 3 : pt_book.cv = PR_NewCondVar(pt_book.ml);
958 3 : PR_ASSERT(NULL != pt_book.cv);
959 3 : thred = PR_NEWZAP(PRThread);
960 3 : PR_ASSERT(NULL != thred);
961 3 : thred->arg = NULL;
962 3 : thred->startFunc = NULL;
963 3 : thred->priority = priority;
964 3 : thred->id = pthread_self();
965 3 : thred->idSet = PR_TRUE;
966 : #ifdef _PR_NICE_PRIORITY_SCHEDULING
967 3 : thred->tid = gettid();
968 : #endif
969 :
970 3 : thred->state = (PT_THREAD_DETACHED | PT_THREAD_PRIMORD);
971 3 : if (PR_SYSTEM_THREAD == type)
972 : {
973 0 : thred->state |= PT_THREAD_SYSTEM;
974 0 : pt_book.system += 1;
975 0 : pt_book.this_many = 0;
976 : }
977 : else
978 : {
979 3 : pt_book.user += 1;
980 3 : pt_book.this_many = 1;
981 : }
982 3 : thred->next = thred->prev = NULL;
983 3 : pt_book.first = pt_book.last = thred;
984 :
985 3 : thred->stack = PR_NEWZAP(PRThreadStack);
986 3 : PR_ASSERT(thred->stack != NULL);
987 3 : thred->stack->stackSize = 0;
988 3 : thred->stack->thr = thred;
989 3 : _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 3 : rv = _PT_PTHREAD_KEY_CREATE(&pt_book.key, _pt_thread_death);
1006 3 : if (0 != rv)
1007 0 : PR_Assert("0 == rv", __FILE__, __LINE__);
1008 3 : pt_book.keyCreated = PR_TRUE;
1009 3 : rv = pthread_setspecific(pt_book.key, thred);
1010 3 : PR_ASSERT(0 == rv);
1011 3 : } /* _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 0 : void _PR_Fini(void)
1066 : {
1067 : void *thred;
1068 : int rv;
1069 :
1070 0 : if (!_pr_initialized) {
1071 : /* Either NSPR was never successfully initialized or
1072 : * PR_Cleanup has been called already. */
1073 0 : if (pt_book.keyCreated)
1074 : {
1075 0 : rv = pthread_key_delete(pt_book.key);
1076 0 : PR_ASSERT(0 == rv);
1077 0 : pt_book.keyCreated = PR_FALSE;
1078 : }
1079 0 : return;
1080 : }
1081 :
1082 0 : _PT_PTHREAD_GETSPECIFIC(pt_book.key, thred);
1083 0 : 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 0 : _pt_thread_death_internal(thred, PR_FALSE);
1090 0 : rv = pthread_setspecific(pt_book.key, NULL);
1091 0 : PR_ASSERT(0 == rv);
1092 : }
1093 0 : rv = pthread_key_delete(pt_book.key);
1094 0 : PR_ASSERT(0 == rv);
1095 0 : 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 0 : PRThread *me = PR_GetCurrentThread();
1103 : int rv;
1104 0 : PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR"));
1105 0 : PR_ASSERT(me->state & PT_THREAD_PRIMORD);
1106 0 : if (me->state & PT_THREAD_PRIMORD)
1107 : {
1108 0 : PR_Lock(pt_book.ml);
1109 0 : while (pt_book.user > pt_book.this_many)
1110 0 : PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT);
1111 0 : if (me->state & PT_THREAD_SYSTEM)
1112 0 : pt_book.system -= 1;
1113 : else
1114 0 : pt_book.user -= 1;
1115 0 : PR_Unlock(pt_book.ml);
1116 :
1117 0 : _PR_MD_EARLY_CLEANUP();
1118 :
1119 0 : _PR_CleanupMW();
1120 0 : _PR_CleanupTime();
1121 0 : _PR_CleanupDtoa();
1122 0 : _PR_CleanupCallOnce();
1123 0 : _PR_ShutdownLinker();
1124 0 : _PR_LogCleanup();
1125 0 : _PR_CleanupNet();
1126 : /* Close all the fd's before calling _PR_CleanupIO */
1127 0 : _PR_CleanupIO();
1128 0 : _PR_CleanupCMon();
1129 :
1130 0 : _pt_thread_death(me);
1131 0 : rv = pthread_setspecific(pt_book.key, NULL);
1132 0 : 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 0 : if (0 == pt_book.system)
1140 : {
1141 0 : PR_DestroyCondVar(pt_book.cv); pt_book.cv = NULL;
1142 0 : PR_DestroyLock(pt_book.ml); pt_book.ml = NULL;
1143 : }
1144 0 : PR_DestroyLock(_pr_sleeplock);
1145 0 : _pr_sleeplock = NULL;
1146 0 : _PR_CleanupLayerCache();
1147 0 : _PR_CleanupEnv();
1148 : #ifdef _PR_ZONE_ALLOCATOR
1149 0 : _PR_DestroyZones();
1150 : #endif
1151 0 : _pr_initialized = PR_FALSE;
1152 0 : return PR_SUCCESS;
1153 : }
1154 0 : return PR_FAILURE;
1155 : } /* PR_Cleanup */
1156 :
1157 : PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status)
1158 : {
1159 0 : _exit(status);
1160 : }
1161 :
1162 0 : 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 0 : 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 0 : PR_IMPLEMENT(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask)
1180 : {
1181 0 : return 0; /* not implemented */
1182 : }
1183 :
1184 0 : PR_IMPLEMENT(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask )
1185 : {
1186 0 : return 0; /* not implemented */
1187 : }
1188 :
1189 : PR_IMPLEMENT(void)
1190 0 : PR_SetThreadDumpProc(PRThread* thread, PRThreadDumpProc dump, void *arg)
1191 : {
1192 0 : thread->dump = dump;
1193 0 : thread->dumpArg = arg;
1194 0 : }
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 0 : 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 0 : sigact_usr2.sa_handler = suspend_signal_handler;
1249 0 : sigact_usr2.sa_flags = SA_RESTART;
1250 0 : sigemptyset (&sigact_usr2.sa_mask);
1251 :
1252 0 : rv = sigaction (SIGUSR2, &sigact_usr2, NULL);
1253 0 : PR_ASSERT(0 == rv);
1254 :
1255 0 : sigemptyset (&sigwait_set);
1256 : #if defined(PT_NO_SIGTIMEDWAIT)
1257 0 : 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 0 : sigact_null.sa_handler = null_signal_handler;
1266 0 : sigact_null.sa_flags = SA_RESTART;
1267 0 : sigemptyset (&sigact_null.sa_mask);
1268 0 : rv = sigaction (SIGUSR1, &sigact_null, NULL);
1269 0 : PR_ASSERT(0 ==rv);
1270 : }
1271 : #endif /* defined(PT_NO_SIGTIMEDWAIT) */
1272 : #endif /* defined(_PR_DCETHREADS) */
1273 : #endif /* SYMBIAN */
1274 0 : }
1275 :
1276 0 : PR_IMPLEMENT(void) PR_SetThreadGCAble(void)
1277 : {
1278 0 : PR_Lock(pt_book.ml);
1279 0 : PR_GetCurrentThread()->state |= PT_THREAD_GCABLE;
1280 0 : PR_Unlock(pt_book.ml);
1281 0 : }
1282 :
1283 0 : PR_IMPLEMENT(void) PR_ClearThreadGCAble(void)
1284 : {
1285 0 : PR_Lock(pt_book.ml);
1286 0 : PR_GetCurrentThread()->state &= (~PT_THREAD_GCABLE);
1287 0 : PR_Unlock(pt_book.ml);
1288 0 : }
1289 :
1290 : #if defined(DEBUG)
1291 : static PRBool suspendAllOn = PR_FALSE;
1292 : #endif
1293 :
1294 : static PRBool suspendAllSuspended = PR_FALSE;
1295 :
1296 0 : PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg)
1297 : {
1298 0 : PRIntn count = 0;
1299 0 : PRStatus rv = PR_SUCCESS;
1300 0 : PRThread* thred = pt_book.first;
1301 :
1302 : #if defined(DEBUG) || defined(FORCE_PR_ASSERT)
1303 : #if !defined(_PR_DCETHREADS)
1304 0 : PRThread *me = PR_GetCurrentThread();
1305 : #endif
1306 : #endif
1307 :
1308 0 : 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 0 : PR_ASSERT(suspendAllOn);
1318 :
1319 0 : 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 original
1325 : * queue.
1326 : *
1327 : * To get around this problem, we save qp->next in qp_next before applying
1328 : * "func" and use that saved value as the next value after applying "func".
1329 : */
1330 0 : PRThread* next = thred->next;
1331 :
1332 0 : if (_PT_IS_GCABLE_THREAD(thred))
1333 : {
1334 : #if !defined(_PR_DCETHREADS)
1335 0 : PR_ASSERT((thred == me) || (thred->suspend & PT_THREAD_SUSPENDED));
1336 : #endif
1337 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
1338 : ("In PR_EnumerateThreads callback thread %p thid = %X\n",
1339 : thred, thred->id));
1340 :
1341 0 : rv = func(thred, count++, arg);
1342 0 : if (rv != PR_SUCCESS)
1343 0 : return rv;
1344 : }
1345 0 : thred = next;
1346 : }
1347 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
1348 : ("End PR_EnumerateThreads count = %d \n", count));
1349 0 : return rv;
1350 : } /* PR_EnumerateThreads */
1351 :
1352 : /*
1353 : * PR_SuspendAll and PR_ResumeAll are called during garbage collection. The strategy
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 does 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 not
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 perhaps
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. Actually
1379 : * SIGUSR1 is also used by exec in Java. So our usage here breaks the exec in Java,
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 0 : static void null_signal_handler(PRIntn sig)
1386 : {
1387 0 : return;
1388 : }
1389 : #endif
1390 :
1391 0 : static void suspend_signal_handler(PRIntn sig)
1392 : {
1393 0 : PRThread *me = PR_GetCurrentThread();
1394 :
1395 0 : PR_ASSERT(me != NULL);
1396 0 : PR_ASSERT(_PT_IS_GCABLE_THREAD(me));
1397 0 : PR_ASSERT((me->suspend & PT_THREAD_SUSPENDED) == 0);
1398 :
1399 0 : 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 0 : 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 0 : me->suspend |= PT_THREAD_SUSPENDED;
1415 :
1416 : /*
1417 : * now, block current thread
1418 : */
1419 : #if defined(PT_NO_SIGTIMEDWAIT)
1420 0 : pthread_cond_signal(&me->suspendResumeCV);
1421 0 : 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 0 : sigwait(&sigwait_set, &rv);
1429 : #endif
1430 : }
1431 0 : me->suspend |= PT_THREAD_RESUMED;
1432 0 : 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 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
1450 : ("End suspend_signal_handler thred = %p tid = %X\n", me, me->id));
1451 0 : } /* suspend_signal_handler */
1452 :
1453 0 : static void pt_SuspendSet(PRThread *thred)
1454 : {
1455 : PRIntn rv;
1456 :
1457 0 : 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 0 : PR_ASSERT((thred->suspend & PT_THREAD_SUSPENDED) == 0);
1466 :
1467 0 : 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 0 : rv = pthread_kill (thred->id, SIGUSR2);
1475 : #endif
1476 0 : PR_ASSERT(0 == rv);
1477 0 : }
1478 :
1479 0 : static void pt_SuspendTest(PRThread *thred)
1480 : {
1481 0 : 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 0 : pthread_mutex_lock(&thred->suspendResumeMutex);
1493 0 : while ((thred->suspend & PT_THREAD_SUSPENDED) == 0)
1494 : {
1495 0 : pthread_cond_timedwait(
1496 : &thred->suspendResumeCV, &thred->suspendResumeMutex, &onemillisec);
1497 : }
1498 0 : 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 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
1508 : ("End pt_SuspendTest thred %p tid %X\n", thred, thred->id));
1509 0 : } /* pt_SuspendTest */
1510 :
1511 0 : static void pt_ResumeSet(PRThread *thred)
1512 : {
1513 0 : 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 0 : PR_ASSERT(thred->suspend & PT_THREAD_SUSPENDED);
1522 :
1523 :
1524 0 : 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 0 : pthread_kill(thred->id, SIGUSR1);
1531 : #endif
1532 : #endif
1533 :
1534 0 : } /* pt_ResumeSet */
1535 :
1536 0 : static void pt_ResumeTest(PRThread *thred)
1537 : {
1538 0 : 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 0 : pthread_mutex_lock(&thred->suspendResumeMutex);
1547 0 : while ((thred->suspend & PT_THREAD_RESUMED) == 0)
1548 : {
1549 0 : pthread_cond_timedwait(
1550 : &thred->suspendResumeCV, &thred->suspendResumeMutex, &onemillisec);
1551 : }
1552 0 : 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 0 : thred->suspend &= ~PT_THREAD_RESUMED;
1561 :
1562 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, (
1563 : "End pt_ResumeTest thred %p tid %X\n", thred, thred->id));
1564 0 : } /* pt_ResumeTest */
1565 :
1566 : static pthread_once_t pt_gc_support_control = PTHREAD_ONCE_INIT;
1567 :
1568 0 : PR_IMPLEMENT(void) PR_SuspendAll(void)
1569 : {
1570 : #ifdef DEBUG
1571 : PRIntervalTime stime, etime;
1572 : #endif
1573 0 : PRThread* thred = pt_book.first;
1574 0 : PRThread *me = PR_GetCurrentThread();
1575 : int rv;
1576 :
1577 0 : rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support);
1578 0 : PR_ASSERT(0 == rv);
1579 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n"));
1580 : /*
1581 : * Stop all threads which are marked GC able.
1582 : */
1583 0 : PR_Lock(pt_book.ml);
1584 : #ifdef DEBUG
1585 0 : suspendAllOn = PR_TRUE;
1586 0 : stime = PR_IntervalNow();
1587 : #endif
1588 0 : while (thred != NULL)
1589 : {
1590 0 : if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))
1591 0 : pt_SuspendSet(thred);
1592 0 : thred = thred->next;
1593 : }
1594 :
1595 : /* Wait till they are really suspended */
1596 0 : thred = pt_book.first;
1597 0 : while (thred != NULL)
1598 : {
1599 0 : if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))
1600 0 : pt_SuspendTest(thred);
1601 0 : thred = thred->next;
1602 : }
1603 :
1604 0 : suspendAllSuspended = PR_TRUE;
1605 :
1606 : #ifdef DEBUG
1607 0 : etime = PR_IntervalNow();
1608 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,\
1609 : ("End PR_SuspendAll (time %dms)\n",
1610 : PR_IntervalToMilliseconds(etime - stime)));
1611 : #endif
1612 0 : } /* PR_SuspendAll */
1613 :
1614 0 : PR_IMPLEMENT(void) PR_ResumeAll(void)
1615 : {
1616 : #ifdef DEBUG
1617 : PRIntervalTime stime, etime;
1618 : #endif
1619 0 : PRThread* thred = pt_book.first;
1620 0 : PRThread *me = PR_GetCurrentThread();
1621 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n"));
1622 : /*
1623 : * Resume all previously suspended GC able threads.
1624 : */
1625 0 : suspendAllSuspended = PR_FALSE;
1626 : #ifdef DEBUG
1627 0 : stime = PR_IntervalNow();
1628 : #endif
1629 :
1630 0 : while (thred != NULL)
1631 : {
1632 0 : if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))
1633 0 : pt_ResumeSet(thred);
1634 0 : thred = thred->next;
1635 : }
1636 :
1637 0 : thred = pt_book.first;
1638 0 : while (thred != NULL)
1639 : {
1640 0 : if ((thred != me) && _PT_IS_GCABLE_THREAD(thred))
1641 0 : pt_ResumeTest(thred);
1642 0 : thred = thred->next;
1643 : }
1644 :
1645 0 : PR_Unlock(pt_book.ml);
1646 : #ifdef DEBUG
1647 0 : suspendAllOn = PR_FALSE;
1648 0 : etime = PR_IntervalNow();
1649 0 : PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
1650 : ("End PR_ResumeAll (time %dms)\n",
1651 : PR_IntervalToMilliseconds(etime - stime)));
1652 : #endif
1653 0 : } /* PR_ResumeAll */
1654 :
1655 : /* Return the stack pointer for the given thread- used by the GC */
1656 0 : PR_IMPLEMENT(void *)PR_GetSP(PRThread *thred)
1657 : {
1658 0 : 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 0 : 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 76 : int result = 0;
1741 :
1742 76 : if (!name) {
1743 0 : PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
1744 0 : return PR_FAILURE;
1745 : }
1746 :
1747 76 : thread = PR_GetCurrentThread();
1748 76 : if (!thread)
1749 0 : return PR_FAILURE;
1750 :
1751 76 : PR_Free(thread->name);
1752 76 : nameLen = strlen(name);
1753 76 : thread->name = (char *)PR_Malloc(nameLen + 1);
1754 76 : if (!thread->name)
1755 0 : return PR_FAILURE;
1756 76 : 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 152 : *(void**)(&dynamic_pthread_setname_np) =
1774 76 : dlsym(RTLD_DEFAULT, "pthread_setname_np");
1775 76 : if (!dynamic_pthread_setname_np)
1776 0 : 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 76 : if (nameLen > SETNAME_LENGTH_CONSTRAINT) {
1790 7 : memcpy(name_dup, name, SETNAME_FRAGMENT1_LENGTH);
1791 7 : name_dup[SETNAME_FRAGMENT1_LENGTH] = '~';
1792 : /* Note that this also copies the null terminator. */
1793 7 : memcpy(name_dup + SETNAME_FRAGMENT1_LENGTH + 1,
1794 7 : name + nameLen - SETNAME_FRAGMENT2_LENGTH,
1795 : SETNAME_FRAGMENT2_LENGTH + 1);
1796 7 : name = name_dup;
1797 : }
1798 :
1799 : #if defined(DARWIN)
1800 : result = dynamic_pthread_setname_np(name);
1801 : #else
1802 76 : result = dynamic_pthread_setname_np(thread->id, name);
1803 : #endif
1804 : #endif /* not BSD */
1805 :
1806 76 : if (result) {
1807 0 : PR_SetError(PR_UNKNOWN_ERROR, result);
1808 0 : return PR_FAILURE;
1809 : }
1810 76 : return PR_SUCCESS;
1811 : }
1812 :
1813 : PR_IMPLEMENT(const char *) PR_GetThreadName(const PRThread *thread)
1814 : {
1815 0 : if (!thread)
1816 0 : return NULL;
1817 0 : return thread->name;
1818 : }
1819 :
1820 : #endif /* defined(_PR_PTHREADS) || defined(_PR_DCETHREADS) */
1821 :
1822 : /* ptthread.c */
|