Bugzilla bug 294955: allow the "primordial" thread (the thread that
authorwtchang%redhat.com
Thu, 26 May 2005 02:27:51 +0000
changeset 3393 82905a457b9e39314cfa81c1d9857a59d020c265
parent 3392 5677df0d2b0ed448a6bc88dfdd6548a8e679c710
child 3394 fc220f7878b22255b570c70bbbf751ae3b2773ed
child 3404 284934f825b0ba0d465da7425d93a2dc2189ee19
child 3405 43e3c25101ed46a4c652d2ebeb0f2840883a7101
push idunknown
push userunknown
push dateunknown
bugs294955
Bugzilla bug 294955: allow the "primordial" thread (the thread that initialized NSPR) to terminate while NSPR is still in use. r=glen.beasley.
pr/src/pthreads/ptthread.c
--- a/pr/src/pthreads/ptthread.c
+++ b/pr/src/pthreads/ptthread.c
@@ -204,17 +204,20 @@ static void *_pt_root(void *arg)
     PR_Lock(pt_book.ml);
 
     /* If this is a GCABLE thread, set its state appropriately */
     if (thred->suspend & PT_THREAD_SETGCABLE)
 	    thred->state |= PT_THREAD_GCABLE;
     thred->suspend = 0;
 
     thred->prev = pt_book.last;
-    pt_book.last->next = thred;
+    if (pt_book.last)
+        pt_book.last->next = thred;
+    else
+        pt_book.first = thred;
     thred->next = NULL;
     pt_book.last = thred;
     PR_Unlock(pt_book.ml);
 
     thred->startFunc(thred->arg);  /* make visible to the client */
 
     /* unhook the thread from the runtime */
     PR_Lock(pt_book.ml);
@@ -228,17 +231,20 @@ static void *_pt_root(void *arg)
         while (!thred->okToDelete)
             PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT);
     }
 
     if (thred->state & PT_THREAD_SYSTEM)
         pt_book.system -= 1;
     else if (--pt_book.user == pt_book.this_many)
         PR_NotifyAllCondVar(pt_book.cv);
-    thred->prev->next = thred->next;
+    if (NULL == thred->prev)
+        pt_book.first = thred->next;
+    else
+        thred->prev->next = thred->next;
     if (NULL == thred->next)
         pt_book.last = thred->prev;
     else
         thred->next->prev = thred->prev;
     PR_Unlock(pt_book.ml);
 
     /*
     * Here we set the pthread's backpointer to the PRThread to NULL.
@@ -283,17 +289,20 @@ static PRThread* pt_AttachThread(void)
         rv = pthread_setspecific(pt_book.key, thred);
         PR_ASSERT(0 == rv);
 
         thred->state = PT_THREAD_GLOBAL | PT_THREAD_FOREIGN;
         PR_Lock(pt_book.ml);
 
         /* then put it into the list */
         thred->prev = pt_book.last;
-	    pt_book.last->next = thred;
+        if (pt_book.last)
+            pt_book.last->next = thred;
+        else
+            pt_book.first = thred;
         thred->next = NULL;
         pt_book.last = thred;
         PR_Unlock(pt_book.ml);
 
     }
     return thred;  /* may be NULL */
 }  /* pt_AttachThread */
 
@@ -785,20 +794,23 @@ PR_IMPLEMENT(PRStatus) PR_Sleep(PRInterv
     }
     return rv;
 }  /* PR_Sleep */
 
 static void _pt_thread_death(void *arg)
 {
     PRThread *thred = (PRThread*)arg;
 
-    if (thred->state & PT_THREAD_FOREIGN)
+    if (thred->state & (PT_THREAD_FOREIGN|PT_THREAD_PRIMORD))
     {
         PR_Lock(pt_book.ml);
-        thred->prev->next = thred->next;
+        if (NULL == thred->prev)
+            pt_book.first = thred->next;
+        else
+            thred->prev->next = thred->next;
         if (NULL == thred->next)
             pt_book.last = thred->prev;
         else
             thred->next->prev = thred->prev;
         PR_Unlock(pt_book.ml);
     }
     _PR_DestroyThreadPrivate(thred);
     PR_Free(thred->privateData);
@@ -910,16 +922,17 @@ void _PR_InitThreads(
     rv = pthread_setspecific(pt_book.key, thred);
     PR_ASSERT(0 == rv);    
     PR_SetThreadPriority(thred, priority);
 }  /* _PR_InitThreads */
 
 PR_IMPLEMENT(PRStatus) PR_Cleanup(void)
 {
     PRThread *me = PR_CurrentThread();
+    int rv;
     PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("PR_Cleanup: shutting down NSPR"));
     PR_ASSERT(me->state & PT_THREAD_PRIMORD);
     if (me->state & PT_THREAD_PRIMORD)
     {
         PR_Lock(pt_book.ml);
         while (pt_book.user > pt_book.this_many)
             PR_WaitCondVar(pt_book.cv, PR_INTERVAL_NO_TIMEOUT);
         PR_Unlock(pt_book.ml);
@@ -928,28 +941,30 @@ PR_IMPLEMENT(PRStatus) PR_Cleanup(void)
         _PR_CleanupDtoa();
         _PR_CleanupCallOnce();
         _PR_ShutdownLinker();
         _PR_LogCleanup();
         _PR_CleanupNet();
         /* Close all the fd's before calling _PR_CleanupIO */
         _PR_CleanupIO();
 
+        _pt_thread_death(me);
+        rv = pthread_setspecific(pt_book.key, NULL);
+        PR_ASSERT(0 == rv);
         /*
          * I am not sure if it's safe to delete the cv and lock here,
          * since there may still be "system" threads around. If this
          * call isn't immediately prior to exiting, then there's a
          * problem.
          */
         if (0 == pt_book.system)
         {
             PR_DestroyCondVar(pt_book.cv); pt_book.cv = NULL;
             PR_DestroyLock(pt_book.ml); pt_book.ml = NULL;
         }
-        _pt_thread_death(me);
         PR_DestroyLock(_pr_sleeplock);
         _pr_sleeplock = NULL;
         _PR_CleanupLayerCache();
         _PR_CleanupEnv();
 #ifdef _PR_ZONE_ALLOCATOR
         _PR_DestroyZones();
 #endif
         _pr_initialized = PR_FALSE;