PatchSet 5747 
Date: 2005/01/02 19:03:30
Author: guilhem
Branch: HEAD
Tag: (none) 
Log:
GC Deadlock fixes for Linux 2.4/2.6 (at least).

        * kaffe/kaffevm/systems/unix-pthreads/lock-impl.c
        (setBlockState): Protect the mutex locking against signal.

        * kaffe/kaffevm/systems/unix-pthreads/thread-impl.c,
        kaffe/kaffevm/systems/unix-pthreads/thread-internal.h
        (KaffePThread_AckAndWaitForResume): New function.
        (suspend_handler): Call directly KaffePThread_AckAndWaitForResume
        now.
        (KaffePThread_getSuspendSignal): Export the signal number
        corresponding to the suspend signal.
        (jthread_suspendall): Cleant up the semaphore sweep. Added a few
        assertion checking.
        (jthread_unsuspendall): Added a few assertion checking.
        (tRun): Check whether the thread is killed when it is woken up.
        (jthread_exit): Do not cancel any thread as it may cause deadlocks
        on 2.4. Only interrupt and set the state to THREAD_KILL.

        * libraries/clib/native/Thread.c
        (VMThread.sleep): Check that if timeout is null we should return
        immediately.

Members: 
        ChangeLog:1.3291->1.3292 
        kaffe/kaffevm/systems/unix-jthreads/signal.c:1.29->1.30 
        kaffe/kaffevm/systems/unix-pthreads/lock-impl.c:1.14->1.15 
        kaffe/kaffevm/systems/unix-pthreads/thread-impl.c:1.64->1.65 
        kaffe/kaffevm/systems/unix-pthreads/thread-internal.h:1.28->1.29 
        libraries/clib/native/Thread.c:1.21->1.22 

Index: kaffe/ChangeLog
diff -u kaffe/ChangeLog:1.3291 kaffe/ChangeLog:1.3292
--- kaffe/ChangeLog:1.3291      Sun Jan  2 05:21:39 2005
+++ kaffe/ChangeLog     Sun Jan  2 19:03:30 2005
@@ -1,3 +1,26 @@
+2005-01-02  Guilhem Lavaux  <[EMAIL PROTECTED]>
+
+       * kaffe/kaffevm/systems/unix-pthreads/lock-impl.c
+       (setBlockState): Protect the mutex locking against signal.
+       
+       * kaffe/kaffevm/systems/unix-pthreads/thread-impl.c,
+       kaffe/kaffevm/systems/unix-pthreads/thread-internal.h
+       (KaffePThread_AckAndWaitForResume): New function.
+       (suspend_handler): Call directly KaffePThread_AckAndWaitForResume
+       now.
+       (KaffePThread_getSuspendSignal): Export the signal number
+       corresponding to the suspend signal.
+       (jthread_suspendall): Cleant up the semaphore sweep. Added a few
+       assertion checking.
+       (jthread_unsuspendall): Added a few assertion checking.
+       (tRun): Check whether the thread is killed when it is woken up.
+       (jthread_exit): Do not cancel any thread as it may cause deadlocks
+       on 2.4. Only interrupt and set the state to THREAD_KILL.
+
+       * libraries/clib/native/Thread.c
+       (VMThread.sleep): Check that if timeout is null we should return
+       immediately.
+
 2005-01-02  Dalibor Topic  <[EMAIL PROTECTED]>
 
        * test/regression/TestSerializable2.java:
Index: kaffe/kaffe/kaffevm/systems/unix-jthreads/signal.c
diff -u kaffe/kaffe/kaffevm/systems/unix-jthreads/signal.c:1.29 
kaffe/kaffe/kaffevm/systems/unix-jthreads/signal.c:1.30
--- kaffe/kaffe/kaffevm/systems/unix-jthreads/signal.c:1.29     Sat Jan  1 
09:03:50 2005
+++ kaffe/kaffe/kaffevm/systems/unix-jthreads/signal.c  Sun Jan  2 19:03:33 2005
@@ -453,7 +453,7 @@
        old_sigsegv = registerSyncSignalHandler(SIGSEGV, stackOverflowDetector);
 #endif
 #if defined(SIGBUS)
-       old_sigbus = haregisterSyncSignalHandler(SIGBUS, stackOverflowDetector);
+       old_sigbus = registerSyncSignalHandler(SIGBUS, stackOverflowDetector);
 #endif
        
        if (JTHREAD_SETJMP(outOfLoop) == 0)
Index: kaffe/kaffe/kaffevm/systems/unix-pthreads/lock-impl.c
diff -u kaffe/kaffe/kaffevm/systems/unix-pthreads/lock-impl.c:1.14 
kaffe/kaffe/kaffevm/systems/unix-pthreads/lock-impl.c:1.15
--- kaffe/kaffe/kaffevm/systems/unix-pthreads/lock-impl.c:1.14  Mon Dec 20 
02:29:52 2004
+++ kaffe/kaffe/kaffevm/systems/unix-pthreads/lock-impl.c       Sun Jan  2 
19:03:33 2005
@@ -19,18 +19,37 @@
 #ifdef KAFFE_BOEHM_GC
 #include "boehm-gc/boehm/include/gc.h"
 #endif
+#include <signal.h>
 
 static inline void
-setBlockState(jthread_t cur, unsigned int newState, void *sp)
+setBlockState(jthread_t cur, unsigned int newState, void *sp, sigset_t 
*old_mask)
 {
+  int suspendSig;
+  sigset_t suspendMask, pendingMask;
+
+  suspendSig = KaffePThread_getSuspendSignal();
+  sigemptyset(&suspendMask);
+  sigaddset(&suspendMask, suspendSig);
+  pthread_sigmask(SIG_BLOCK, &suspendMask, old_mask);
+
   pthread_mutex_lock(&cur->suspendLock);
   cur->blockState |= newState;
   cur->stackCur  = sp;
   pthread_mutex_unlock(&cur->suspendLock);
+
+  /* This thread is protected against suspendall. So if a signal has been
+   * received it is just before the mutex_lock and after pthread_sigmask.
+   * We must acknowledge and go in WaitForResume.
+   */
+  sigpending(&pendingMask); 
+  if (sigismember(&pendingMask, suspendSig))
+  {
+    KaffePThread_AckAndWaitForResume(cur, newState);
+  }
 }
 
 static inline void
-clearBlockState(jthread_t cur, unsigned int newState)
+clearBlockState(jthread_t cur, unsigned int newState, sigset_t *old_mask)
 {
   pthread_mutex_lock(&cur->suspendLock);
   cur->blockState &= ~newState;
@@ -38,7 +57,7 @@
     {
       DBG(JTHREADDETAIL, dprintf("Changing blockstate of %p to %d while in 
suspend, block again\n",  cur, newState));
 
-      KaffePThread_WaitForResume(true);
+      KaffePThread_WaitForResume(true, 0);
     }
   else
     {
@@ -51,16 +70,22 @@
    */
   if (cur->status == THREAD_KILL)
     pthread_exit(NULL);
+
+  pthread_sigmask(SIG_SETMASK, old_mask, NULL);
+  /* Here the state is not SS_PENDING_SUSPEND so releasing the signal will
+   * not trigger a deadlock.
+   */
 }
 
 void
 jmutex_lock( jmutex* lk )
 {
   jthread_t cur = jthread_current ();
+  sigset_t oldmask;
 
-  setBlockState(cur, BS_MUTEX, (void*)&cur);
+  setBlockState(cur, BS_MUTEX, (void*)&cur, &oldmask);
   pthread_mutex_lock( lk );
-  clearBlockState(cur, BS_MUTEX);
+  clearBlockState(cur, BS_MUTEX, &oldmask);
 }
 
 
@@ -68,10 +93,11 @@
 ThreadCondWait(jthread_t cur, jcondvar *cv, jmutex *mux)
 {
   int status;
+  sigset_t oldmask;
 
-  setBlockState(cur, BS_CV, (void*)&cur);
+  setBlockState(cur, BS_CV, (void*)&cur, &oldmask);
   status = pthread_cond_wait( cv, mux );
-  clearBlockState(cur, BS_CV);
+  clearBlockState(cur, BS_CV, &oldmask);
 
   return status;
 }
@@ -87,6 +113,7 @@
   int             status;
   struct timespec abst;
   struct timeval  now;
+  sigset_t oldmask;
 
   /*
    * If a thread trying to get a heavy lock is interrupted, we may get here
@@ -120,9 +147,9 @@
              abst.tv_nsec -= 1000000000;
            }
 
-         setBlockState(cur, BS_CV_TO, (void*)&cur);
+         setBlockState(cur, BS_CV_TO, (void*)&cur, &oldmask);
          status = pthread_cond_timedwait( cv, mux, &abst);
-         clearBlockState(cur, BS_CV_TO);
+         clearBlockState(cur, BS_CV_TO, &oldmask);
        }
     }
 
Index: kaffe/kaffe/kaffevm/systems/unix-pthreads/thread-impl.c
diff -u kaffe/kaffe/kaffevm/systems/unix-pthreads/thread-impl.c:1.64 
kaffe/kaffe/kaffevm/systems/unix-pthreads/thread-impl.c:1.65
--- kaffe/kaffe/kaffevm/systems/unix-pthreads/thread-impl.c:1.64        Wed Dec 
29 16:27:43 2004
+++ kaffe/kaffe/kaffevm/systems/unix-pthreads/thread-impl.c     Sun Jan  2 
19:03:33 2005
@@ -784,6 +784,8 @@
        /* Wait until we get re-used (by TcreateThread). No need to update the
         * blockState, since we aren't active anymore */
        repsem_wait( &cur->sem);
+       if (cur->status == THREAD_KILL)
+         break;
 
        /*
         * we have already been moved back to the activeThreads list by
@@ -1024,7 +1026,7 @@
           */
          for ( t=cache; t != NULL; t = t->next ){
                t->status = THREAD_KILL;
-               pthread_cancel( t->tid);
+               repsem_post(&t->sem);
          }
 
          for ( t=activeThreads; t != NULL; t = t->next ){
@@ -1033,8 +1035,6 @@
                  t->status = THREAD_KILL;
                  /* Send an interrupt event to the remote thread. */
                  jthread_interrupt(t);
-                 /* Cancel it to be sure it is dead. */
-                 pthread_cancel( t->tid);
                }
          }
 
@@ -1156,7 +1156,7 @@
  * mask and to release the suspendLock mutex only after this. In that case we
  * keep in sync with jthread_suspendall()
  */
-void KaffePThread_WaitForResume(int releaseMutex)
+void KaffePThread_WaitForResume(int releaseMutex, unsigned int state)
 {
   volatile jthread_t cur = jthread_current();
   int s;
@@ -1164,8 +1164,16 @@
 
   if (releaseMutex)
     {
-      pthread_sigmask(SIG_SETMASK, &suspendSet, &oldset);
+      pthread_sigmask(SIG_BLOCK, &suspendSet, &oldset);
       pthread_mutex_unlock(&cur->suspendLock);
+      /*
+       * In that particular case we have to release the mutex on the thread 
list
+       * because it may cause deadlocks in the GC thread. It does not hurt as 
we
+       * do not access the thread list but we will have to reacquire it before
+       * returning.
+       */
+      if (cur->blockState & BS_THREAD)
+             pthread_mutex_unlock(&activeThreadsLock);
     }
 
   /* freeze until we get a subsequent sigResume */
@@ -1173,15 +1181,22 @@
     sigwait( &suspendSet, &s);
   
   DBG( JTHREADDETAIL, dprintf("sigwait return: %p\n", cur));
-    
-  cur->stackCur     = NULL;
+
+  /* If the thread needs to be put back in a block state
+   * we must not reset the stack pointer.
+   */
+  if (state == 0)
+    cur->stackCur     = NULL;
   cur->suspendState = 0;
+  cur->blockState |= state;
   
   /* notify the critSect owner we are leaving the handler */
   repsem_post( &critSem);
 
   if (releaseMutex)
     {
+      if (cur->blockState & BS_THREAD)
+       pthread_mutex_lock(&activeThreadsLock);
       pthread_sigmask(SIG_SETMASK, &oldset, NULL);
     }
 }
@@ -1206,26 +1221,33 @@
   if ( !cur || !cur->active )
        return;
 
-  if ( cur->suspendState == SS_PENDING_SUSPEND ){
-       JTHREAD_JMPBUF env;
-
-       /*
-        * Note: We're not gonna do a longjmp to this place, we just want
-        * to do something that will save all of the registers onto the stack.
-        */
-       JTHREAD_SETJMP(env);
-
-       /* assuming we are executing on the thread stack, we record our current 
pos */
-       cur->stackCur     = (void*)&env;
-       cur->suspendState = SS_SUSPENDED;
-
-       /* notify the critSect owner that we are now suspending in the handler 
*/
-       repsem_post( &critSem);
+  KaffePThread_AckAndWaitForResume(cur, 0);
+}
 
-       KaffePThread_WaitForResume(false);
+void KaffePThread_AckAndWaitForResume(volatile jthread_t cur, unsigned int 
state)
+{
+  if ( cur->suspendState == SS_PENDING_SUSPEND ){
+    JTHREAD_JMPBUF env;
+    
+    /*
+     * Note: We're not gonna do a longjmp to this place, we just want
+     * to do something that will save all of the registers onto the stack.
+     */
+    JTHREAD_SETJMP(env);
+    
+    /* assuming we are executing on the thread stack, we record our current 
pos */
+    cur->stackCur     = (void*)&env;
+    cur->suspendState = SS_SUSPENDED;
+    cur->blockState  &= ~state;
+    
+    /* notify the critSect owner that we are now suspending in the handler */
+    repsem_post( &critSem);
+    
+    KaffePThread_WaitForResume(false, state);
   }
 }
 
+
 /**
  * The resume signal handler, which we mainly need to get the implicit 
sigreturn
  * call (i.e. to unblock a preceeding sigwait).
@@ -1312,18 +1334,8 @@
         */
        while (numPending > 0)
          {
-           repsem_getvalue(&critSem, &val);
            repsem_wait( &critSem);
-           for ( numPending=0,t=activeThreads; t; t = t->next ){
-             if (t->suspendState == SS_PENDING_SUSPEND)
-               numPending++;
-           }
-         }
-       /* Now flush the semaphore. */
-       repsem_getvalue(&critSem, &val);
-       for (;val != 0; val--)
-         {
-           repsem_wait(&critSem);
+           numPending--;
          }
 
 #else
@@ -1362,11 +1374,14 @@
        return;
 
   if ( --critSection == 0 ){
+         int val;
        /* No need to sync, there's nobody else running. However it seems
         * we cannot use mutexes as they cause a deadlock when the world
         * is suspended.
         */
-         protectThreadList(cur);
+       protectThreadList(cur);
+       repsem_getvalue(&critSem, &val);
+       assert(val == 0);
 
 #if !defined(KAFFE_BOEHM_GC)
        for ( t=activeThreads; t; t = t->next ){
@@ -1408,6 +1423,8 @@
        GC_start_world();
 
 #endif
+       repsem_getvalue(&critSem, &val);
+       assert(val == 0);
          unprotectThreadList(cur);
 
   }
@@ -1592,4 +1609,9 @@
 void jthread_atexit(void (* func)(void))
 {
   runOnExit = func;
+}
+
+int KaffePThread_getSuspendSignal()
+{
+  return sigSuspend;
 }
Index: kaffe/kaffe/kaffevm/systems/unix-pthreads/thread-internal.h
diff -u kaffe/kaffe/kaffevm/systems/unix-pthreads/thread-internal.h:1.28 
kaffe/kaffe/kaffevm/systems/unix-pthreads/thread-internal.h:1.29
--- kaffe/kaffe/kaffevm/systems/unix-pthreads/thread-internal.h:1.28    Sat Dec 
25 19:09:17 2004
+++ kaffe/kaffe/kaffevm/systems/unix-pthreads/thread-internal.h Sun Jan  2 
19:03:34 2005
@@ -414,7 +414,9 @@
 
 int jthread_interrupted(jthread_t jt);
 
-void KaffePThread_WaitForResume(int releaseMutex);
+void KaffePThread_WaitForResume(int releaseMutex, unsigned int state);
+void KaffePThread_AckAndWaitForResume(jthread_t cur, unsigned int newState);
+int KaffePThread_getSuspendSignal();
 
 void detectStackBoundaries(jthread_t jtid, int mainThreadStackSize);
 
Index: kaffe/libraries/clib/native/Thread.c
diff -u kaffe/libraries/clib/native/Thread.c:1.21 
kaffe/libraries/clib/native/Thread.c:1.22
--- kaffe/libraries/clib/native/Thread.c:1.21   Sun Dec 19 06:25:12 2004
+++ kaffe/libraries/clib/native/Thread.c        Sun Jan  2 19:03:34 2005
@@ -82,6 +82,10 @@
 {
   jthread_t    cur = KTHREAD(current)();
 
+  /* Temporary hack waiting for the Classpath merge. */
+  if (timeout == 0)
+    return;
+
   if(KTHREAD(interrupted)(cur))
     {
       throwException(InterruptedException);

_______________________________________________
kaffe mailing list
[email protected]
http://kaffe.org/cgi-bin/mailman/listinfo/kaffe

Reply via email to