home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / pthreads / ptthread.c < prev   
Encoding:
C/C++ Source or Header  |  1998-04-08  |  38.7 KB  |  1,310 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /*
  20. ** File:            ptthread.c
  21. ** Descritpion:        Implemenation for threds using pthreds
  22. ** Exports:            ptthread.h
  23. */
  24.  
  25. #if defined(_PR_PTHREADS) || defined(_PR_DCETHREADS)
  26.  
  27. #include "prlog.h"
  28. #include "primpl.h"
  29. #include "prpdce.h"
  30.  
  31. #include <pthread.h>
  32. #include <string.h>
  33. #include <signal.h>
  34.  
  35. /*
  36.  * Record whether or not we have the privilege to set the scheduling
  37.  * policy and priority of threads.  0 means that privilege is available.
  38.  * EPERM means that privilege is not available.
  39.  */
  40.  
  41. PRIntn pt_schedpriv;
  42.  
  43. struct _PT_Bookeeping pt_book = {0};
  44.  
  45. static void init_pthread_gc_support(void);
  46.  
  47. static PRIntn pt_PriorityMap(PRThreadPriority pri)
  48. {
  49.     return pt_book.minPrio +
  50.         pri * (pt_book.maxPrio - pt_book.minPrio) / PR_PRIORITY_LAST;
  51. }
  52.  
  53. /*
  54. ** Initialize a stack for a native pthread thread
  55. */
  56. static void _PR_InitializeStack(PRThreadStack *ts)
  57. {
  58.     if( ts && (ts->stackTop == 0) ) {
  59.         ts->allocBase = (char *) &ts;
  60.         ts->allocSize = ts->stackSize;
  61.  
  62.         /*
  63.         ** Setup stackTop and stackBottom values.
  64.         */
  65. #ifdef HAVE_STACK_GROWING_UP
  66.         ts->stackBottom = ts->allocBase + ts->stackSize;
  67.         ts->stackTop = ts->allocBase;
  68. #else
  69.         ts->stackTop    = ts->allocBase;
  70.         ts->stackBottom = ts->allocBase - ts->stackSize;
  71. #endif
  72.     }
  73. }
  74.  
  75. static void *_pt_root(void *arg)
  76. {
  77.     PRIntn rv;
  78.     PRThread *thred = (PRThread*)arg;
  79.     PRBool detached = (thred->state & PT_THREAD_DETACHED) ? PR_TRUE : PR_FALSE;
  80.  
  81.     /*
  82.      * Both the parent thread and this new thread set thred->id.
  83.      * The new thread must ensure that thred->id is set before
  84.      * it executes its startFunc.  The parent thread must ensure
  85.      * that thred->id is set before PR_CreateThread() returns.
  86.      * Both threads set thred->id without holding a lock.  Since
  87.      * they are writing the same value, this unprotected double
  88.      * write should be safe.
  89.      */
  90.     thred->id = pthread_self();
  91.  
  92.     /*
  93.     ** DCE Threads can't detach during creation, so do it late.
  94.     ** I would like to do it only here, but that doesn't seem
  95.     ** to work.
  96.     */
  97. #if defined(_PR_DCETHREADS)
  98.     if (detached)
  99.     {
  100.         /* pthread_detach() modifies its argument, so we must pass a copy */
  101.         pthread_t self = thred->id;
  102.         rv = pthread_detach(&self);
  103.         PR_ASSERT(0 == rv);
  104.     }
  105. #endif /* defined(_PR_DCETHREADS) */
  106.  
  107.     /* Set up the thread stack information */
  108.     _PR_InitializeStack(thred->stack);
  109.  
  110.     /*
  111.      * Set within the current thread the pointer to our object.
  112.      * This object will be deleted when the thread termintates,
  113.      * whether in a join or detached (see _PR_InitThreads()).
  114.      */
  115.     rv = pthread_setspecific(pt_book.key, thred);
  116.     PR_ASSERT(0 == rv);
  117.  
  118.     /* make the thread visible to the rest of the runtime */
  119.     PR_Lock(pt_book.ml);
  120.  
  121.     /* If this is a GCABLE thread, set its state appropriately */
  122.     if (thred->suspend & PT_THREAD_SETGCABLE)
  123.         thred->state |= PT_THREAD_GCABLE;
  124.     thred->suspend = 0;
  125.  
  126.     thred->prev = pt_book.last;
  127.     pt_book.last->next = thred;
  128.     thred->next = NULL;
  129.     pt_book.last = thred;
  130.     PR_Unlock(pt_book.ml);
  131.  
  132.     thred->startFunc(thred->arg);  /* make visible to the client */
  133.  
  134.     /* unhook the thread from the runtime */
  135.     PR_Lock(pt_book.ml);
  136.     if (thred->state & PT_THREAD_SYSTEM)
  137.         pt_book.system -= 1;
  138.     else if (--pt_book.user == pt_book.this_many)
  139.         PR_NotifyAllCondVar(pt_book.cv);
  140.     thred->prev->next = thred->next;
  141.     if (NULL == thred->next)
  142.         pt_book.last = thred->prev;
  143.     else
  144.         thred->next->prev = thred->prev;
  145.  
  146.     /*
  147.      * At this moment, PR_CreateThread() may not have set thred->id yet.
  148.      * It is safe for a detached thread to free thred only after
  149.      * PR_CreateThread() has set thred->id.
  150.      */
  151.     if (detached)
  152.     {
  153.         while (!thred->okToDelete)
  154.             PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT);
  155.     }
  156.     PR_Unlock(pt_book.ml);
  157.  
  158.     /* last chance to delete this puppy if the thread is detached */
  159.     if (detached)
  160.     {
  161.         PR_DELETE(thred->stack);
  162. #if defined(DEBUG)
  163.         memset(thred, 0xaf, sizeof(PRThread));
  164. #endif
  165.         PR_DELETE(thred);
  166.     }
  167.  
  168.     rv = pthread_setspecific(pt_book.key, NULL);
  169.     PR_ASSERT(0 == rv);
  170.     return NULL;
  171. }  /* _pt_root */
  172.  
  173. static PRThread* _PR_CreateThread(
  174.     PRThreadType type, void (*start)(void *arg),
  175.     void *arg, PRThreadPriority priority, PRThreadScope scope,
  176.     PRThreadState state, PRUint32 stackSize, PRBool isGCAble)
  177. {
  178.     int rv;
  179.     PRThread *thred;
  180.     pthread_attr_t tattr;
  181.  
  182.     if (!_pr_initialized) _PR_ImplicitInitialization();
  183.  
  184.     if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)priority)
  185.         priority = PR_PRIORITY_FIRST;
  186.     else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)priority)
  187.         priority = PR_PRIORITY_LAST;
  188.  
  189.     rv = PTHREAD_ATTR_INIT(&tattr);
  190.     PR_ASSERT(0 == rv);
  191.  
  192.     if (EPERM != pt_schedpriv)
  193.     {
  194. #if !defined(_PR_DCETHREADS) && !defined(FREEBSD)
  195.         struct sched_param schedule;
  196. #endif
  197.  
  198. #if !defined(FREEBSD)
  199.         rv = pthread_attr_setinheritsched(&tattr, PTHREAD_EXPLICIT_SCHED);
  200.         PR_ASSERT(0 == rv);
  201. #endif
  202.  
  203.         /* Use the default scheduling policy */
  204.  
  205. #if defined(_PR_DCETHREADS)
  206.         rv = pthread_attr_setprio(&tattr, pt_PriorityMap(priority));
  207.         PR_ASSERT(0 == rv);
  208. #elif !defined(FREEBSD)
  209.         rv = pthread_attr_getschedparam(&tattr, &schedule);
  210.         PR_ASSERT(0 == rv);
  211.         schedule.sched_priority = pt_PriorityMap(priority);
  212.         rv = pthread_attr_setschedparam(&tattr, &schedule);
  213.         PR_ASSERT(0 == rv);
  214. #endif /* !defined(_PR_DCETHREADS) */
  215.     }
  216.  
  217.     /*
  218.      * DCE threads can't set detach state before creating the thread.
  219.      * AIX can't set detach late. Why can't we all just get along?
  220.      */
  221. #if !defined(_PR_DCETHREADS)
  222.     rv = pthread_attr_setdetachstate(&tattr,
  223.         ((PR_JOINABLE_THREAD == state) ?
  224.             PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED));
  225.     PR_ASSERT(0 == rv);
  226. #endif /* !defined(_PR_DCETHREADS) */
  227.  
  228.     /*
  229.      * HPUX only supports PTHREAD_SCOPE_SYSTEM.
  230.      * IRIX only supports PTHREAD_SCOPE_PROCESS.
  231.      * OSF1 only supports PTHREAD_SCOPE_PROCESS.
  232.      * AIX only supports PTHREAD_SCOPE_SYSTEM.
  233.      */
  234. #if defined(SOLARIS)
  235.     rv = pthread_attr_setscope(&tattr,
  236.     ((PR_GLOBAL_THREAD == scope) ?
  237.             PTHREAD_SCOPE_SYSTEM : PTHREAD_SCOPE_PROCESS));
  238.     PR_ASSERT(0 == rv);
  239. #endif
  240.  
  241. #if defined(IRIX)
  242.     if ((16 * 1024) > stackSize) stackSize = (16 * 1024);  /* IRIX minimum */
  243.     else
  244. #endif
  245.     if (0 == stackSize) stackSize = (64 * 1024);  /* default == 64K */
  246.     /*
  247.      * Linux doesn't have pthread_attr_setstacksize.
  248.      */
  249. #ifndef LINUX
  250.     rv = pthread_attr_setstacksize(&tattr, stackSize);
  251.     PR_ASSERT(0 == rv);
  252. #endif
  253.  
  254.     thred = PR_NEWZAP(PRThread);
  255.     if (thred != NULL)
  256.     {
  257.         pthread_t id;
  258.  
  259.         thred->arg = arg;
  260.         thred->startFunc = start;
  261.         thred->priority = priority;
  262.         if (PR_UNJOINABLE_THREAD == state)
  263.             thred->state |= PT_THREAD_DETACHED;
  264.         if (PR_GLOBAL_THREAD == scope)
  265.             thred->state |= PT_THREAD_GLOBAL;
  266.         if (PR_SYSTEM_THREAD == type)
  267.             thred->state |= PT_THREAD_SYSTEM;
  268.  
  269.         thred->suspend =(isGCAble) ? PT_THREAD_SETGCABLE : 0;
  270.  
  271.         thred->stack = PR_NEWZAP(PRThreadStack);
  272.         if (thred->stack == NULL) {
  273.             PR_DELETE(thred);  /* all that work ... poof! */
  274.             thred = NULL;  /* and for what? */
  275.             goto done;
  276.         }
  277.         thred->stack->stackSize = stackSize;
  278.         thred->stack->thr = thred;
  279.  
  280. #ifdef PT_NO_SIGTIMEDWAIT
  281.       pthread_mutex_init(&thred->suspendResumeMutex,NULL);
  282.       pthread_cond_init(&thred->suspendResumeCV,NULL);
  283. #endif
  284.  
  285.         /* make the thread counted to the rest of the runtime */
  286.         PR_Lock(pt_book.ml);
  287.         if (thred->state & PT_THREAD_SYSTEM)
  288.             pt_book.system += 1;
  289.         else pt_book.user += 1;
  290.         PR_Unlock(pt_book.ml);
  291.  
  292.         /*
  293.          * We pass a pointer to a local copy (instead of thred->id)
  294.          * to pthread_create() because who knows what wacky things
  295.          * pthread_create() may be doing to its argument.
  296.          */
  297.         if (PTHREAD_CREATE(&id, tattr, _pt_root, thred) != 0)
  298.         {
  299.             PR_Lock(pt_book.ml);
  300.             if (thred->state & PT_THREAD_SYSTEM)
  301.                 pt_book.system -= 1;
  302.             else if (--pt_book.user == pt_book.this_many)
  303.                 PR_NotifyAllCondVar(pt_book.cv);
  304.             PR_Unlock(pt_book.ml);
  305.  
  306.             PR_DELETE(thred->stack);
  307.             PR_DELETE(thred);  /* all that work ... poof! */
  308.             thred = NULL;  /* and for what? */
  309.             goto done;
  310.         }
  311.  
  312.         /*
  313.          * Both the parent thread and this new thread set thred->id.
  314.          * The parent thread must ensure that thred->id is set before
  315.          * PR_CreateThread() returns.  (See comments in _pt_root().)
  316.          */
  317.         thred->id = id;
  318.  
  319.         /*
  320.          * If the new thread is detached, tell it that PR_CreateThread()
  321.          * has set thred->id so it's ok to delete thred.
  322.          */
  323.         if (PR_UNJOINABLE_THREAD == state)
  324.         {
  325.             PR_Lock(pt_book.ml);
  326.             thred->okToDelete = PR_TRUE;
  327.             PR_NotifyAllCondVar(pt_book.cv);
  328.             PR_Unlock(pt_book.ml);
  329.         }
  330.     }
  331.  
  332. done:
  333.     rv = PTHREAD_ATTR_DESTROY(&tattr);
  334.     PR_ASSERT(0 == rv);
  335.  
  336.     return thred;
  337. }  /* _PR_CreateThread */
  338.  
  339. PR_IMPLEMENT(PRThread*) PR_CreateThread(
  340.     PRThreadType type, void (*start)(void *arg), void *arg,
  341.     PRThreadPriority priority, PRThreadScope scope,
  342.     PRThreadState state, PRUint32 stackSize)
  343. {
  344.     return _PR_CreateThread(
  345.         type, start, arg, priority, scope, state, stackSize, PR_FALSE);
  346. } /* PR_CreateThread */
  347.  
  348. PR_IMPLEMENT(PRThread*) PR_CreateThreadGCAble(
  349.     PRThreadType type, void (*start)(void *arg), void *arg, 
  350.     PRThreadPriority priority, PRThreadScope scope,
  351.     PRThreadState state, PRUint32 stackSize)
  352. {
  353.     return _PR_CreateThread(
  354.         type, start, arg, priority, scope, state, stackSize, PR_TRUE);
  355. }  /* PR_CreateThreadGCAble */
  356.  
  357. PR_IMPLEMENT(void*) GetExecutionEnvironment(PRThread *thred)
  358. {
  359.     return thred->environment;
  360. }  /* GetExecutionEnvironment */
  361.  
  362. PR_IMPLEMENT(void) SetExecutionEnvironment(PRThread *thred, void *env)
  363. {
  364.     thred->environment = env;
  365. }  /* SetExecutionEnvironment */
  366.  
  367. PR_IMPLEMENT(PRThread*) PR_AttachThread(
  368.     PRThreadType type, PRThreadPriority priority, PRThreadStack *stack)
  369. {
  370.     PRThread *thred = NULL;
  371.     void *privateData = NULL;
  372.  
  373.     /*
  374.      * NSPR must have been initialized when PR_AttachThread is called.
  375.      * We cannot have PR_AttachThread call implicit initialization
  376.      * because if multiple threads call PR_AttachThread simultaneously,
  377.      * NSPR may be initialized more than once.
  378.      */
  379.     if (!_pr_initialized) {
  380.         /* Since NSPR is not initialized, we cannot call PR_SetError. */
  381.         return NULL;
  382.     }
  383.  
  384.     PTHREAD_GETSPECIFIC(pt_book.key, privateData);
  385.     if (NULL != privateData)
  386.     {
  387.         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
  388.         return NULL;
  389.     }
  390.     thred = PR_NEWZAP(PRThread);
  391.     if (NULL == thred) PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  392.     else
  393.     {
  394.         int rv;
  395.  
  396.         if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)priority)
  397.             priority = PR_PRIORITY_FIRST;
  398.         else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)priority)
  399.             priority = PR_PRIORITY_LAST;
  400.  
  401.         thred->priority = priority;
  402.         thred->id = pthread_self();
  403.         rv = pthread_setspecific(pt_book.key, thred);
  404.         PR_ASSERT(0 == rv);
  405.  
  406.         PR_Lock(pt_book.ml);
  407.         if (PR_SYSTEM_THREAD == type)
  408.         {
  409.             pt_book.system += 1;
  410.             thred->state |= PT_THREAD_SYSTEM;
  411.         }
  412.         else pt_book.user += 1;
  413.  
  414.         /* then put it into the list */
  415.         thred->prev = pt_book.last;
  416.         pt_book.last->next = thred;
  417.         thred->next = NULL;
  418.         pt_book.last = thred;
  419.         PR_Unlock(pt_book.ml);
  420.  
  421.     }
  422.     return thred;  /* may be NULL */
  423. }  /* PR_AttachThread */
  424.  
  425. PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thred)
  426. {
  427.     int rv = -1;
  428.     void *result = NULL;
  429.     PR_ASSERT(thred != NULL);
  430.  
  431.     if ((0xafafafaf == thred->state)
  432.     || (PT_THREAD_DETACHED & thred->state))
  433.     {
  434.         /*
  435.          * This might be a bad address, but if it isn't, the state should
  436.          * either be an unjoinable thread or it's already had the object
  437.          * deleted. However, the client that called join on a detached
  438.          * thread deserves all the rath I can muster....
  439.          */
  440.         PR_SetError(PR_ILLEGAL_ACCESS_ERROR, 0);
  441.         PR_LogPrint(
  442.             "PR_JoinThread: 0x%X not joinable | already smashed\n", thred);
  443.  
  444.         PR_ASSERT((0xafafafaf == thred->state)
  445.         || (PT_THREAD_DETACHED & thred->state));
  446.     }
  447.     else
  448.     {
  449.         pthread_t id = thred->id;
  450.         rv = pthread_join(id, &result);
  451.         if (0 != rv)
  452.             PR_SetError(PR_UNKNOWN_ERROR, errno);
  453.         PR_DELETE(thred->stack);
  454.         memset(thred, 0xaf, sizeof(PRThread));
  455.         PR_ASSERT(result == NULL);
  456.         PR_DELETE(thred);
  457.     }
  458.     return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
  459. }  /* PR_JoinThread */
  460.  
  461. PR_IMPLEMENT(void) PR_DetachThread()
  462. {
  463.     void *tmp;
  464.     PTHREAD_GETSPECIFIC(pt_book.key, tmp);
  465.     PR_ASSERT(NULL != tmp);
  466.  
  467.     if (NULL != tmp)
  468.     {
  469.         int rv;
  470.         PRThread *thred = (PRThread*)tmp;
  471.  
  472.         PR_Lock(pt_book.ml);
  473.         if (thred->state & PT_THREAD_SYSTEM)
  474.             pt_book.system -= 1;
  475.         else if (--pt_book.user == pt_book.this_many)
  476.             PR_NotifyAllCondVar(pt_book.cv);
  477.         thred->prev->next = thred->next;
  478.         if (NULL == thred->next)
  479.             pt_book.last = thred->prev;
  480.         else
  481.             thred->next->prev = thred->prev;
  482.         PR_Unlock(pt_book.ml);
  483.  
  484.         rv = pthread_setspecific(pt_book.key, NULL);
  485.         PR_ASSERT(0 == rv);
  486.         PR_DELETE(thred->stack);
  487.         memset(thred, 0xaf, sizeof(PRThread));
  488.         PR_DELETE(thred);
  489.     }    
  490. }  /* PR_DetachThread */
  491.  
  492. PR_IMPLEMENT(PRThread*) PR_GetCurrentThread()
  493. {
  494.     void *thred;
  495.  
  496.     if (!_pr_initialized) _PR_ImplicitInitialization();
  497.  
  498.     PTHREAD_GETSPECIFIC(pt_book.key, thred);
  499.     PR_ASSERT(NULL != thred);
  500.     return (PRThread*)thred;
  501. }  /* PR_GetCurrentThread */
  502.  
  503. PR_IMPLEMENT(PRThreadScope) PR_GetThreadScope(const PRThread *thred)
  504. {
  505.     return (thred->state & PT_THREAD_GLOBAL) ?
  506.         PR_GLOBAL_THREAD : PR_LOCAL_THREAD;
  507. }  /* PR_GetThreadScope() */
  508.  
  509. PR_IMPLEMENT(PRThreadType) PR_GetThreadType(const PRThread *thred)
  510. {
  511.     return (thred->state & PT_THREAD_SYSTEM) ?
  512.         PR_SYSTEM_THREAD : PR_USER_THREAD;
  513. }
  514.  
  515. PR_IMPLEMENT(PRThreadState) PR_GetThreadState(const PRThread *thred)
  516. {
  517.     return (thred->state & PT_THREAD_DETACHED) ?
  518.         PR_UNJOINABLE_THREAD : PR_JOINABLE_THREAD;
  519. }  /* PR_GetThreadState */
  520.  
  521. PR_IMPLEMENT(PRThreadPriority) PR_GetThreadPriority(const PRThread *thred)
  522. {
  523.     PR_ASSERT(thred != NULL);
  524.     return thred->priority;
  525. }  /* PR_GetThreadPriority */
  526.  
  527. PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred, PRThreadPriority newPri)
  528. {
  529.     PRIntn rv;
  530.  
  531.     PR_ASSERT(NULL != thred);
  532.  
  533.     if ((PRIntn)PR_PRIORITY_FIRST > (PRIntn)newPri)
  534.         newPri = PR_PRIORITY_FIRST;
  535.     else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)newPri)
  536.         newPri = PR_PRIORITY_LAST;
  537.  
  538. #if defined(_PR_DCETHREADS)
  539.     rv = pthread_setprio(thred->id, pt_PriorityMap(newPri));
  540.     /* pthread_setprio returns the old priority */
  541.     PR_ASSERT(-1 != rv);
  542. #elif !defined(FREEBSD)
  543.     if (EPERM != pt_schedpriv)
  544.     {
  545.         int policy;
  546.         struct sched_param schedule;
  547.  
  548.         rv = pthread_getschedparam(thred->id, &policy, &schedule);
  549.         PR_ASSERT(0 == rv);
  550.         schedule.sched_priority = pt_PriorityMap(newPri);
  551.         rv = pthread_setschedparam(thred->id, policy, &schedule);
  552.         PR_ASSERT(0 == rv);
  553.     }
  554. #endif
  555.  
  556.     thred->priority = newPri;
  557. }  /* PR_SetThreadPriority */
  558.  
  559. PR_IMPLEMENT(PRStatus) PR_NewThreadPrivateIndex(
  560.     PRUintn *newIndex, PRThreadPrivateDTOR destructor)
  561. {
  562.     int rv;
  563.  
  564.     if (!_pr_initialized) _PR_ImplicitInitialization();
  565.  
  566.     rv = PTHREAD_KEY_CREATE((pthread_key_t*)newIndex, destructor);
  567.  
  568.     if (0 == rv)
  569.     {
  570.         PR_Lock(pt_book.ml);
  571.         if (*newIndex >= pt_book.highwater)
  572.             pt_book.highwater = *newIndex + 1;
  573.         PR_Unlock(pt_book.ml);
  574.         return PR_SUCCESS;
  575.     }
  576.     PR_SetError(PR_UNKNOWN_ERROR, rv);
  577.     return PR_FAILURE;
  578. }  /* PR_NewThreadPrivateIndex */
  579.  
  580. PR_IMPLEMENT(PRStatus) PR_SetThreadPrivate(PRUintn index, void *priv)
  581. {
  582.     PRIntn rv;
  583.     if ((pthread_key_t)index >= pt_book.highwater)
  584.     {
  585.         PR_SetError(PR_TPD_RANGE_ERROR, 0);
  586.         return PR_FAILURE;
  587.     }
  588.     rv = pthread_setspecific((pthread_key_t)index, priv);
  589.     PR_ASSERT(0 == rv);
  590.     if (0 == rv) return PR_SUCCESS;
  591.  
  592.     PR_SetError(PR_UNKNOWN_ERROR, rv);
  593.     return PR_FAILURE;
  594. }  /* PR_SetThreadPrivate */
  595.  
  596. PR_IMPLEMENT(void*) PR_GetThreadPrivate(PRUintn index)
  597. {
  598.     void *result = NULL;
  599.     if ((pthread_key_t)index < pt_book.highwater)
  600.         PTHREAD_GETSPECIFIC((pthread_key_t)index, result);
  601.     return result;
  602. }  /* PR_GetThreadPrivate */
  603.  
  604. PR_IMPLEMENT(PRStatus) PR_Interrupt(PRThread *thred)
  605. {
  606.     /*
  607.     ** If the target thread indicates that it's waiting,
  608.     ** find the condition and broadcast to it. Broadcast
  609.     ** since we don't know which thread (if there are more
  610.     ** than one). This sounds risky, but clients must
  611.     ** test their invariants when resumed from a wait and
  612.     ** I don't expect very many threads to be waiting on
  613.     ** a single condition and I don't expect interrupt to
  614.     ** be used very often.
  615.     */
  616.     PRCondVar *victim;
  617.     PR_ASSERT(thred != NULL);
  618.     thred->state |= PT_THREAD_ABORTED;
  619.     victim = thred->waiting;
  620.     if (NULL != victim)
  621.     {
  622.         PRIntn haveLock = pthread_equal(victim->lock->owner, pthread_self());
  623.         if (!haveLock) PR_Lock(victim->lock);
  624.         PR_NotifyAllCondVar(victim);
  625.         if (!haveLock) PR_Unlock(victim->lock);
  626.     }
  627.     return PR_SUCCESS;
  628. }  /* PR_Interrupt */
  629.  
  630. PR_IMPLEMENT(void) PR_ClearInterrupt()
  631. {
  632.     PRThread *me = PR_CurrentThread();
  633.     me->state &= ~PT_THREAD_ABORTED;
  634. }  /* PR_ClearInterrupt */
  635.  
  636. PR_IMPLEMENT(PRStatus) PR_Yield()
  637. {
  638.     static PRBool warning = PR_TRUE;
  639.     if (warning) warning = _PR_Obsolete(
  640.         "PR_Yield()", "PR_Sleep(PR_INTERVAL_NO_WAIT)");
  641.     return PR_Sleep(PR_INTERVAL_NO_WAIT);
  642. }
  643.  
  644. PR_IMPLEMENT(PRStatus) PR_Sleep(PRIntervalTime ticks)
  645. {
  646.     PRStatus rv;
  647.  
  648.     if (!_pr_initialized) _PR_ImplicitInitialization();
  649.  
  650.     if (PR_INTERVAL_NO_WAIT == ticks)
  651.     {
  652.         PTHREAD_YIELD();
  653.         rv = PR_SUCCESS;
  654.     }
  655.     else
  656.     {
  657.         PRCondVar *cv = PR_NewCondVar(pt_book.ml);
  658.         PR_ASSERT(cv != NULL);
  659.         PR_Lock(pt_book.ml);
  660.         rv = PR_WaitCondVar(cv, ticks);
  661.         PR_Unlock(pt_book.ml);
  662.         PR_DestroyCondVar(cv);
  663.     }
  664.     return rv;
  665. }  /* PR_Sleep */
  666.  
  667. void _PR_InitThreads(
  668.     PRThreadType type, PRThreadPriority priority, PRUintn maxPTDs)
  669. {
  670.     int rv;
  671.     PRThread *thred;
  672.  
  673.     /*
  674.     ** These might be function evaluations
  675.     */
  676.     pt_book.minPrio = PT_PRIO_MIN;
  677.     pt_book.maxPrio = PT_PRIO_MAX;
  678.     
  679.     PR_ASSERT(NULL == pt_book.ml);
  680.     pt_book.ml = PR_NewLock();
  681.     PR_ASSERT(NULL != pt_book.ml);
  682.     pt_book.cv = PR_NewCondVar(pt_book.ml);
  683.     PR_ASSERT(NULL != pt_book.cv);
  684.     thred = PR_NEWZAP(PRThread);
  685.     PR_ASSERT(NULL != thred);
  686.     thred->arg = NULL;
  687.     thred->startFunc = NULL;
  688.     thred->priority = priority;
  689.     thred->id = pthread_self();
  690.  
  691.     thred->state |= (PT_THREAD_DETACHED | PT_THREAD_PRIMORD);
  692.     if (PR_SYSTEM_THREAD == type)
  693.     {
  694.         thred->state |= PT_THREAD_SYSTEM;
  695.         pt_book.system += 1;
  696.         pt_book.this_many = 0;
  697.     }
  698.     else
  699.     {
  700.         pt_book.user += 1;
  701.         pt_book.this_many = 1;
  702.     }
  703.     thred->next = thred->prev = NULL;
  704.     pt_book.first = pt_book.last = thred;
  705.  
  706.     thred->stack = PR_NEWZAP(PRThreadStack);
  707.     PR_ASSERT(thred->stack != NULL);
  708.     thred->stack->stackSize = 0;
  709.     thred->stack->thr = thred;
  710.     _PR_InitializeStack(thred->stack);
  711.  
  712.     /*
  713.      * Create a key for our use to store a backpointer in the pthread
  714.      * to our PRThread object. This object gets deleted when the thread
  715.      * returns from its root in the case of a detached thread. Other
  716.      * threads delete the objects in Join.
  717.      *
  718.      * NB: The destructor logic seems to have a bug so it isn't used.
  719.      */
  720.     rv = PTHREAD_KEY_CREATE(&pt_book.key, NULL);
  721.     PR_ASSERT(0 == rv);
  722.     rv = pthread_setspecific(pt_book.key, thred);
  723.     PR_ASSERT(0 == rv);
  724.     
  725.     pt_schedpriv = PT_PRIVCHECK();
  726.     PR_SetThreadPriority(thred, priority);
  727.  
  728.     /*
  729.      * Linux pthreads use SIGUSR1 and SIGUSR2 internally, which
  730.      * conflict with the use of these two signals in our GC support.
  731.      * So we don't know how to support GC on Linux pthreads.
  732.      */
  733. #if !defined(LINUX2_0) && !defined(FREEBSD)
  734.     init_pthread_gc_support();
  735. #endif
  736.  
  737. }  /* _PR_InitThreads */
  738.  
  739. PR_IMPLEMENT(PRStatus) PR_Cleanup()
  740. {
  741.     PRThread *me = PR_CurrentThread();
  742.     PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR"));
  743.     PR_ASSERT(me->state & PT_THREAD_PRIMORD);
  744.     if (me->state & PT_THREAD_PRIMORD)
  745.     {
  746.         PR_Lock(pt_book.ml);
  747.         while (pt_book.user > pt_book.this_many)
  748.             PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT);
  749.         PR_Unlock(pt_book.ml);
  750.  
  751.         /*
  752.          * I am not sure if it's safe to delete the cv and lock here,
  753.          * since there may still be "system" threads around. If this
  754.          * call isn't immediately prior to exiting, then there's a
  755.          * problem.
  756.          */
  757.         if (0 == pt_book.system)
  758.         {
  759.             PR_DestroyCondVar(pt_book.cv); pt_book.cv = NULL;
  760.             PR_DestroyLock(pt_book.ml); pt_book.ml = NULL;
  761.         }
  762.         PR_DELETE(me->stack);
  763.         PR_DELETE(me);
  764.         return PR_SUCCESS;
  765.     }
  766.     return PR_FAILURE;
  767. }  /* PR_Cleanup */
  768.  
  769. PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status)
  770. {
  771.     _exit(status);
  772. }
  773.  
  774. /*
  775.  * $$$
  776.  * The following two thread-to-processor affinity functions are not
  777.  * yet implemented for pthreads.  By the way, these functions should return
  778.  * PRStatus rather than PRInt32 to indicate the success/failure status.
  779.  * $$$
  780.  */
  781.  
  782. PR_IMPLEMENT(PRInt32) PR_GetThreadAffinityMask(PRThread *thread, PRUint32 *mask)
  783. {
  784.     return 0;  /* not implemented */
  785. }
  786.  
  787. PR_IMPLEMENT(PRInt32) PR_SetThreadAffinityMask(PRThread *thread, PRUint32 mask )
  788. {
  789.     return 0;  /* not implemented */
  790. }
  791.  
  792. PR_IMPLEMENT(void)
  793. PR_SetThreadDumpProc(PRThread* thread, PRThreadDumpProc dump, void *arg)
  794. {
  795.     thread->dump = dump;
  796.     thread->dumpArg = arg;
  797. }
  798.  
  799. /* 
  800.  * Garbage collection support follows.
  801.  */
  802.  
  803. #if defined(_PR_DCETHREADS)
  804.  
  805. /*
  806.  * statics for Garbage Collection support.  We don't need to protect these
  807.  * signal masks since the garbage collector itself is protected by a lock
  808.  * and multiple threads will not be garbage collecting at the same time.
  809.  */
  810. static sigset_t javagc_vtalarm_sigmask;
  811. static sigset_t javagc_intsoff_sigmask;
  812.  
  813. #else /* defined(_PR_DCETHREADS) */
  814.  
  815. /* a bogus signal mask for forcing a timed wait */
  816. /* Not so bogus in AIX as we really do a sigwait */
  817. static sigset_t sigwait_set;
  818.  
  819. static struct timespec onemillisec = {0, 1000000L};
  820. static struct timespec hundredmillisec = {0, 100000000L};
  821.  
  822. #endif /* defined(_PR_DCETHREADS) */
  823.  
  824. static void suspend_signal_handler(PRIntn sig);
  825.  
  826. #ifdef PT_NO_SIGTIMEDWAIT
  827. static void null_signal_handler(PRIntn sig);
  828. #endif
  829.  
  830. static void init_pthread_gc_support()
  831. {
  832.     PRIntn rv;
  833.  
  834. #if defined(_PR_DCETHREADS)
  835.     rv = sigemptyset(&javagc_vtalarm_sigmask);
  836.     PR_ASSERT(0 == rv);
  837.     rv = sigaddset(&javagc_vtalarm_sigmask, SIGVTALRM);
  838.     PR_ASSERT(0 == rv);
  839. #else  /* defined(_PR_DCETHREADS) */
  840.     {
  841.         struct sigaction sigact_usr2 = {0};
  842.  
  843.         sigact_usr2.sa_handler = suspend_signal_handler;
  844.         sigact_usr2.sa_flags = SA_RESTART;
  845.         sigemptyset (&sigact_usr2.sa_mask);
  846.  
  847.         rv = sigaction (SIGUSR2, &sigact_usr2, NULL);
  848.         PR_ASSERT(0 == rv);
  849.  
  850.         sigemptyset (&sigwait_set);
  851. #if defined(PT_NO_SIGTIMEDWAIT)
  852.         sigaddset (&sigwait_set, SIGUSR1);
  853. #else
  854.         sigaddset (&sigwait_set, SIGUSR2);
  855. #endif  /* defined(PT_NO_SIGTIMEDWAIT) */
  856.     }
  857. #if defined(PT_NO_SIGTIMEDWAIT)
  858.     {
  859.         struct sigaction sigact_null = {0};
  860.         sigact_null.sa_handler = null_signal_handler;
  861.         sigact_null.sa_flags = SA_RESTART;
  862.         sigemptyset (&sigact_null.sa_mask);
  863.         rv = sigaction (SIGUSR1, &sigact_null, NULL);
  864.         PR_ASSERT(0 ==rv); 
  865.     }
  866. #endif  /* defined(PT_NO_SIGTIMEDWAIT) */
  867. #endif /* defined(_PR_DCETHREADS) */
  868. }
  869.  
  870. PR_IMPLEMENT(void) PR_SetThreadGCAble()
  871. {
  872.     PR_Lock(pt_book.ml);
  873.     PR_CurrentThread()->state |= PT_THREAD_GCABLE;
  874.     PR_Unlock(pt_book.ml);
  875. }
  876.  
  877. PR_IMPLEMENT(void) PR_ClearThreadGCAble()
  878. {
  879.     PR_Lock(pt_book.ml);
  880.     PR_CurrentThread()->state &= (~PT_THREAD_GCABLE);
  881.     PR_Unlock(pt_book.ml);
  882. }
  883.  
  884. #if defined(DEBUG)
  885. static PRBool suspendAllOn = PR_FALSE;
  886. #endif
  887.  
  888. static PRBool suspendAllSuspended = PR_FALSE;
  889.  
  890. /* Are all GCAble threads (except gc'ing thread) suspended? */
  891. PR_IMPLEMENT(PRBool) PR_SuspendAllSuspended()
  892. {
  893.     return suspendAllSuspended;
  894. } /* PR_SuspendAllSuspended */
  895.  
  896. PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg)
  897. {
  898.     PRIntn count = 0;
  899.     PRStatus rv = PR_SUCCESS;
  900.     PRThread* thred = pt_book.first;
  901.     PRThread *me = PR_CurrentThread();
  902.  
  903.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_EnumerateThreads\n"));
  904.     /*
  905.      * $$$
  906.      * Need to suspend all threads other than me before doing this.
  907.      * This is really a gross and disgusting thing to do. The only
  908.      * good thing is that since all other threads are suspended, holding
  909.      * the lock during a callback seems like child's play.
  910.      * $$$
  911.      */
  912.     PR_ASSERT(suspendAllOn);
  913.  
  914.     while (thred != NULL)
  915.     {
  916.         /* Steve Morse, 4-23-97: Note that we can't walk a queue by taking
  917.          * qp->next after applying the function "func".  In particular, "func"
  918.          * might remove the thread from the queue and put it into another one in
  919.          * which case qp->next no longer points to the next entry in the original
  920.          * queue.
  921.          *
  922.          * To get around this problem, we save qp->next in qp_next before applying
  923.          * "func" and use that saved value as the next value after applying "func".
  924.          */
  925.         PRThread* next = thred->next;
  926.  
  927.         if (thred->state & PT_THREAD_GCABLE)
  928.         {
  929. #if !defined(_PR_DCETHREADS)
  930.             PR_ASSERT((thred == me) || (thred->suspend & PT_THREAD_SUSPENDED));
  931. #endif
  932.             PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
  933.                    ("In PR_EnumerateThreads callback thread %X thid = %X\n", 
  934.                     thred, thred->id));
  935.  
  936.             rv = func(thred, count++, arg);
  937.             if (rv != PR_SUCCESS)
  938.                 return rv;
  939.         }
  940.         thred = next;
  941.     }
  942.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
  943.        ("End PR_EnumerateThreads count = %d \n", count));
  944.     return rv;
  945. }  /* PR_EnumerateThreads */
  946.  
  947. /*
  948.  * PR_SuspendAll and PR_ResumeAll are called during garbage collection.  The strategy 
  949.  * we use is to send a SIGUSR2 signal to every gc able thread that we intend to suspend.
  950.  * The signal handler will record the stack pointer and will block until resumed by
  951.  * the resume call.  Since the signal handler is the last routine called for the
  952.  * suspended thread, the stack pointer will also serve as a place where all the
  953.  * registers have been saved on the stack for the previously executing routines.
  954.  *
  955.  * Through global variables, we also make sure that PR_Suspend and PR_Resume does not
  956.  * proceed until the thread is suspended or resumed.
  957.  */
  958.  
  959. #if !defined(_PR_DCETHREADS)
  960.  
  961. /*
  962.  * In the signal handler, we can not use condition variable notify or wait.
  963.  * This does not work consistently across all pthread platforms.  We also can not 
  964.  * use locking since that does not seem to work reliably across platforms.
  965.  * Only thing we can do is yielding while testing for a global condition
  966.  * to change.  This does work on pthread supported platforms.  We may have
  967.  * to play with priortities if there are any problems detected.
  968.  */
  969.  
  970.  /* 
  971.   * In AIX, you cannot use ANY pthread calls in the signal handler except perhaps
  972.   * pthread_yield. But that is horribly inefficient. Hence we use only sigwait, no
  973.   * sigtimedwait is available. We need to use another user signal, SIGUSR1. Actually
  974.   * SIGUSR1 is also used by exec in Java. So our usage here breaks the exec in Java,
  975.   * for AIX. You cannot use pthread_cond_wait or pthread_delay_np in the signal
  976.   * handler as all synchronization mechanisms just break down. 
  977.   */
  978.  
  979. #if defined(PT_NO_SIGTIMEDWAIT)
  980. static void null_signal_handler(PRIntn sig)
  981. {
  982.     return;
  983. }
  984. #endif
  985.  
  986. static void suspend_signal_handler(PRIntn sig)
  987. {
  988.     PRThread *me = PR_CurrentThread();
  989.  
  990.     PR_ASSERT(me != NULL);
  991.     PR_ASSERT(me->state & PT_THREAD_GCABLE);
  992.     PR_ASSERT((me->suspend & PT_THREAD_SUSPENDED) == 0);
  993.  
  994.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
  995.         ("Begin suspend_signal_handler thred %X thread id = %X\n", 
  996.         me, me->id));
  997.  
  998.     /*
  999.      * save stack pointer
  1000.      */
  1001.     me->sp = &me;
  1002.  
  1003.     /* 
  1004.        At this point, the thread's stack pointer has been saved,
  1005.        And it is going to enter a wait loop until it is resumed.
  1006.        So it is _really_ suspended 
  1007.     */
  1008.  
  1009.     me->suspend |= PT_THREAD_SUSPENDED;
  1010.  
  1011.     /*
  1012.      * now, block current thread
  1013.      */
  1014. #if defined(PT_NO_SIGTIMEDWAIT)
  1015.     pthread_cond_signal(&me->suspendResumeCV);
  1016.     while (me->suspend & PT_THREAD_SUSPENDED)
  1017.     {
  1018. #if !defined(FREEBSD)  /*XXX*/
  1019.         PRIntn rv;
  1020.         sigwait(&sigwait_set, &rv);
  1021. #endif
  1022.     }
  1023.     me->suspend |= PT_THREAD_RESUMED;
  1024.     pthread_cond_signal(&me->suspendResumeCV);
  1025. #else /* defined(PT_NO_SIGTIMEDWAIT) */
  1026.     while (me->suspend & PT_THREAD_SUSPENDED)
  1027.     {
  1028.         PRIntn rv = sigtimedwait(&sigwait_set, NULL, &hundredmillisec);
  1029.         PR_ASSERT(-1 == rv);
  1030.     }
  1031.     me->suspend |= PT_THREAD_RESUMED;
  1032. #endif
  1033.  
  1034.     /*
  1035.      * At this point, thread has been resumed, so set a global condition.
  1036.      * The ResumeAll needs to know that this has really been resumed. 
  1037.      * So the signal handler sets a flag which PR_ResumeAll will reset. 
  1038.      * The PR_ResumeAll must reset this flag ...
  1039.      */
  1040.  
  1041.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
  1042.         ("End suspend_signal_handler thred = %X tid = %X\n", me, me->id));
  1043. }  /* suspend_signal_handler */
  1044.  
  1045. static void PR_SuspendSet(PRThread *thred)
  1046. {
  1047.     PRIntn rv;
  1048.  
  1049.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
  1050.        ("PR_SuspendSet thred %X thread id = %X\n", thred, thred->id));
  1051.  
  1052.  
  1053.     /*
  1054.      * Check the thread state and signal the thread to suspend
  1055.      */
  1056.  
  1057.     PR_ASSERT((thred->suspend & PT_THREAD_SUSPENDED) == 0);
  1058.  
  1059.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
  1060.        ("doing pthread_kill in PR_SuspendSet thred %X tid = %X\n",
  1061.        thred, thred->id));
  1062.     rv = pthread_kill (thred->id, SIGUSR2);
  1063.     PR_ASSERT(0 == rv);
  1064. }
  1065.  
  1066. static void PR_SuspendTest(PRThread *thred)
  1067. {
  1068.     PRIntn rv;
  1069.  
  1070.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
  1071.        ("Begin PR_SuspendTest thred %X thread id = %X\n", thred, thred->id));
  1072.  
  1073.  
  1074.     /*
  1075.      * Wait for the thread to be really suspended. This happens when the
  1076.      * suspend signal handler stores the stack pointer and sets the state
  1077.      * to suspended. 
  1078.      */
  1079.  
  1080. #if defined(PT_NO_SIGTIMEDWAIT)
  1081.     pthread_mutex_lock(&thred->suspendResumeMutex);
  1082.     while ((thred->suspend & PT_THREAD_SUSPENDED) == 0)
  1083.     {
  1084.         pthread_cond_timedwait(
  1085.             &thred->suspendResumeCV, &thred->suspendResumeMutex, &onemillisec);
  1086.     }
  1087.     pthread_mutex_unlock(&thred->suspendResumeMutex);
  1088. #else
  1089.     while ((thred->suspend & PT_THREAD_SUSPENDED) == 0)
  1090.     {
  1091.         rv = sigtimedwait(&sigwait_set, NULL, &onemillisec);
  1092.         PR_ASSERT(-1 == rv);
  1093.     }
  1094. #endif
  1095.  
  1096.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
  1097.         ("End PR_SuspendTest thred %X tid %X\n", thred, thred->id));
  1098. }  /* PR_SuspendTest */
  1099.  
  1100. PR_IMPLEMENT(void) PR_ResumeSet(PRThread *thred)
  1101. {
  1102.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
  1103.        ("PR_ResumeSet thred %X thread id = %X\n", thred, thred->id));
  1104.  
  1105.     /*
  1106.      * Clear the global state and set the thread state so that it will
  1107.      * continue past yield loop in the suspend signal handler
  1108.      */
  1109.  
  1110.     PR_ASSERT(thred->suspend & PT_THREAD_SUSPENDED);
  1111.  
  1112.  
  1113.     thred->suspend &= ~PT_THREAD_SUSPENDED;
  1114.  
  1115. #if defined(PT_NO_SIGTIMEDWAIT)
  1116.     pthread_kill(thred->id, SIGUSR1);
  1117. #endif
  1118.  
  1119. }  /* PR_ResumeSet */
  1120.  
  1121. PR_IMPLEMENT(void) PR_ResumeTest(PRThread *thred)
  1122. {
  1123.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
  1124.        ("Begin PR_ResumeTest thred %X thread id = %X\n", thred, thred->id));
  1125.  
  1126.     /*
  1127.      * Wait for the threads resume state to change
  1128.      * to indicate it is really resumed 
  1129.      */
  1130. #if defined(PT_NO_SIGTIMEDWAIT)
  1131.     pthread_mutex_lock(&thred->suspendResumeMutex);
  1132.     while ((thred->suspend & PT_THREAD_RESUMED) == 0)
  1133.     {
  1134.         pthread_cond_timedwait(
  1135.             &thred->suspendResumeCV, &thred->suspendResumeMutex, &onemillisec);
  1136.     }
  1137.     pthread_mutex_unlock(&thred->suspendResumeMutex);
  1138. #else
  1139.     while ((thred->suspend & PT_THREAD_RESUMED) == 0) {
  1140.         PRIntn rv = sigtimedwait(&sigwait_set, NULL, &onemillisec);
  1141.         PR_ASSERT(-1 == rv);
  1142.     }
  1143. #endif
  1144.  
  1145.     thred->suspend &= ~PT_THREAD_RESUMED;
  1146.  
  1147.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, (
  1148.         "End PR_ResumeTest thred %X tid %X\n", thred, thred->id));
  1149. }  /* PR_ResumeTest */
  1150.  
  1151. PR_IMPLEMENT(void) PR_SuspendAll()
  1152. {
  1153. #ifdef DEBUG
  1154.     PRIntervalTime stime, etime;
  1155. #endif
  1156.     PRThread* thred = pt_book.first;
  1157.     PRThread *me = PR_CurrentThread();
  1158.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n"));
  1159.     /*
  1160.      * Stop all threads which are marked GC able.
  1161.      */
  1162.     PR_Lock(pt_book.ml);
  1163. #ifdef DEBUG
  1164.     suspendAllOn = PR_TRUE;
  1165.     stime = PR_IntervalNow();
  1166. #endif
  1167.     while (thred != NULL)
  1168.     {
  1169.         if ((thred != me) && (thred->state & PT_THREAD_GCABLE))
  1170.             PR_SuspendSet(thred);
  1171.         thred = thred->next;
  1172.     }
  1173.  
  1174.     /* Wait till they are really suspended */
  1175.     thred = pt_book.first;
  1176.     while (thred != NULL)
  1177.     {
  1178.         if ((thred != me) && (thred->state & PT_THREAD_GCABLE))
  1179.             PR_SuspendTest(thred);
  1180.         thred = thred->next;
  1181.     }
  1182.  
  1183.     suspendAllSuspended = PR_TRUE;
  1184.  
  1185. #ifdef DEBUG
  1186.     etime = PR_IntervalNow();
  1187.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,\
  1188.         ("End PR_SuspendAll (time %dms)\n",
  1189.         PR_IntervalToMilliseconds(etime - stime)));
  1190. #endif
  1191. }  /* PR_SuspendAll */
  1192.  
  1193. PR_IMPLEMENT(void) PR_ResumeAll()
  1194. {
  1195. #ifdef DEBUG
  1196.     PRIntervalTime stime, etime;
  1197. #endif
  1198.     PRThread* thred = pt_book.first;
  1199.     PRThread *me = PR_CurrentThread();
  1200.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n"));
  1201.     /*
  1202.      * Resume all previously suspended GC able threads.
  1203.      */
  1204.     suspendAllSuspended = PR_FALSE;
  1205. #ifdef DEBUG
  1206.     stime = PR_IntervalNow();
  1207. #endif
  1208.  
  1209.     while (thred != NULL)
  1210.     {
  1211.         if ((thred != me) && (thred->state & PT_THREAD_GCABLE))
  1212.             PR_ResumeSet(thred);
  1213.         thred = thred->next;
  1214.     }
  1215.  
  1216.     thred = pt_book.first;
  1217.     while (thred != NULL)
  1218.     {
  1219.         if ((thred != me) && (thred->state & PT_THREAD_GCABLE))
  1220.             PR_ResumeTest(thred);
  1221.         thred = thred->next;
  1222.     }
  1223.  
  1224.     PR_Unlock(pt_book.ml);
  1225. #ifdef DEBUG
  1226.     suspendAllOn = PR_FALSE;
  1227.     etime = PR_IntervalNow();
  1228.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
  1229.         ("End PR_ResumeAll (time %dms)\n",
  1230.         PR_IntervalToMilliseconds(etime - stime)));
  1231. #endif
  1232. }  /* PR_ResumeAll */
  1233.  
  1234. /* Return the stack pointer for the given thread- used by the GC */
  1235. PR_IMPLEMENT(void *)PR_GetSP(PRThread *thred)
  1236. {
  1237.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, 
  1238.         ("in PR_GetSP thred %X thid = %X, sp = %X \n", 
  1239.         thred, thred->id, thred->sp));
  1240.     return thred->sp;
  1241. }  /* PR_GetSP */
  1242.  
  1243. #else /* !defined(_PR_DCETHREADS) */
  1244.  
  1245. /*
  1246.  * For DCE threads, there is no pthread_kill or a way of suspending or resuming a
  1247.  * particular thread.  We will just disable the preemption (virtual timer alarm) and
  1248.  * let the executing thread finish the garbage collection.  This stops all other threads
  1249.  * (GC able or not) and is very inefficient but there is no other choice.
  1250.  */
  1251. PR_IMPLEMENT(void) PR_SuspendAll()
  1252. {
  1253.     PRIntn rv;
  1254.  
  1255.     suspendAllOn = PR_TRUE;
  1256.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n"));
  1257.     /* 
  1258.      * turn off preemption - i.e add virtual alarm signal to the set of 
  1259.      * blocking signals 
  1260.      */
  1261.     rv = sigprocmask(
  1262.         SIG_BLOCK, &javagc_vtalarm_sigmask, &javagc_intsoff_sigmask);
  1263.     PR_ASSERT(0 == rv);
  1264.     suspendAllSuspended = PR_TRUE;
  1265.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_SuspendAll\n"));
  1266. }  /* PR_SuspendAll */
  1267.  
  1268. PR_IMPLEMENT(void) PR_ResumeAll()
  1269. {
  1270.     PRIntn rv;
  1271.     
  1272.     suspendAllSuspended = PR_FALSE;
  1273.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n"));
  1274.     /* turn on preemption - i.e re-enable virtual alarm signal */
  1275.  
  1276.     rv = sigprocmask(SIG_SETMASK, &javagc_intsoff_sigmask, (sigset_t *)NULL);
  1277.     PR_ASSERT(0 == rv);
  1278.     suspendAllOn = PR_FALSE;
  1279.  
  1280.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_ResumeAll\n"));
  1281. }  /* PR_ResumeAll */
  1282.  
  1283. /* Return the stack pointer for the given thread- used by the GC */
  1284. PR_IMPLEMENT(void*)PR_GetSP(PRThread *thred)
  1285. {
  1286.     pthread_t tid = thred->id;
  1287.     char *thread_tcb, *top_sp;
  1288.  
  1289.     /*
  1290.      * For HPUX DCE threads, pthread_t is a struct with the
  1291.      * following three fields (see pthread.h, dce/cma.h):
  1292.      *     cma_t_address       field1;
  1293.      *     short int           field2;
  1294.      *     short int           field3;
  1295.      * where cma_t_address is typedef'd to be either void*
  1296.      * or char*.
  1297.      */
  1298.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_GetSP\n"));
  1299.     thread_tcb = (char*)tid.field1;
  1300.     top_sp = *(char**)(thread_tcb + 128);
  1301.     PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_GetSP %X \n", top_sp));
  1302.     return top_sp;
  1303. }  /* PR_GetSP */
  1304.  
  1305. #endif /* !defined(_PR_DCETHREADS) */
  1306.  
  1307. #endif  /* defined(_PR_PTHREADS) || defined(_PR_DCETHREADS) */
  1308.  
  1309. /* ptthread.c */
  1310.