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