libgcj/78: pthread thread cancellation problem

green@cygnus.com green@cygnus.com
Sun Oct 31 20:50:00 GMT 1999


>Number:         78
>Category:       libgcj
>Synopsis:       pthread thread cancellation problem
>Confidential:   no
>Severity:       critical
>Priority:       medium
>Responsible:    tromey
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Oct 31 20:50:00 PST 1999
>Closed-Date:
>Last-Modified:
>Originator:     Anthony Green
>Release:        All
>Organization:
>Environment:
IA-32 Linux	
>Description:
One problem with pc range table exception handling is that it can't
walk the stack backwards over code that wasn't built with the
exception handling flag.

Linux pthread libraries aren't typically compiled with exception
support - which is a real shame.  I don't really understand why glibc
isn't built with this.  In any case, libgcj implements Thread.stop by
cancelling the thread.  A waiting thread that is cancelled ends up
calling back into libjava/posix-threads.cc's throw_cleanup routing,
which calls _Jv_Throw.  The throw fails of course, because the stack
walker can't make it past the pthread library code.  libgcc.a will
simply abort in this case.

The solutions as I see them are:

- compile libpthread with -fexceptions, or

- find some way to generate frame unwind info from compiled code, or

- find some other way around the library code.


I've appended a patch for discussion.  It implements "some other way
around the library code".  I'm not very happy with it though.

The basic idea is to longjmp around the pthread library code, back
into code we can throw from.  The problem here is the overhead.  The
linux threads implementation specifies different `cancellation
including many system calls.

This patch only makes waiting safe.

>How-To-Repeat:

>Fix:
1999-10-31  Anthony Green  <green@cygnus.com>

        * include/posix-threads.h (_Jv_Thread_t): Add jump buffer field.
        * posix-threads.cc (throw_cleanup): Longjmp out of thread cleanup
        code before throwing.
        (_Jv_CondWait): Use setjmp to recover from cancelled thread.

Index: libjava/posix-threads.cc
===================================================================
RCS file: /cvs/java/libgcj/libjava/posix-threads.cc,v
retrieving revision 1.10
diff -u -r1.10 posix-threads.cc
--- posix-threads.cc    1999/09/10 22:03:05     1.10
+++ posix-threads.cc    1999/11/01 02:20:33
@@ -90,8 +90,14 @@
   jlong m, m2, startTime;
   bool done_sleeping = false;

+  _Jv_Thread_t *td = _Jv_ThreadCurrentData ();
+
   if (millis == 0 && nanos == 0)
-    r = pthread_cond_wait (cv, pmu);
+    {
+      if (setjmp (td->recover) == 1)
+       _Jv_Throw ((java::lang::Throwable *) td->exception);
+      pthread_cond_wait (cv, pmu);
+    }
   else
     {
       startTime = java::lang::System::currentTimeMillis();
@@ -102,7 +108,9 @@
          ts.tv_sec = m / 1000;
          ts.tv_nsec = ((m % 1000) * 1000000) + nanos;

-         r = pthread_cond_timedwait (cv, pmu, &ts);
+         if (setjmp (td->recover) == 1)
+           _Jv_Throw ((java::lang::Throwable *) td->exception);
+         pthread_cond_timedwait (cv, pmu, &ts);

          if (r == EINTR)
            {
@@ -217,7 +225,9 @@
        }
       else
        {
-         // Try to acquire the lock.
+         _Jv_Thread_t *td = _Jv_ThreadCurrentData ();
+         if (setjmp (td->recover) == 1)
+           _Jv_Throw ((java::lang::Throwable *) td->exception);
          pthread_cond_wait (&mu->cond, &mu->mutex);
        }
     }
@@ -314,7 +324,7 @@
 throw_cleanup (void *data)
 {
   _Jv_Thread_t *td = (_Jv_Thread_t *) data;
-  _Jv_Throw ((java::lang::Throwable *) td->exception);
+  longjmp (td->recover, 0);
 }

 void
Index: libjava/include/posix-threads.h
===================================================================
RCS file: /cvs/java/libgcj/libjava/include/posix-threads.h,v
retrieving revision 1.8
diff -u -r1.8 posix-threads.h
--- posix-threads.h     1999/09/21 23:01:23     1.8
+++ posix-threads.h     1999/11/01 02:20:33
@@ -19,6 +19,7 @@

 #include <pthread.h>
 #include <sched.h>
+#include <setjmp.h>

 #if defined (HAVE_PTHREAD_MUTEXATTR_SETTYPE) || defined (HAVE_PTHREAD_MUTEXATT\
R_SETKIND_NP)
 #  define HAVE_RECURSIVE_MUTEX 1
@@ -79,9 +80,17 @@

   // Exception we want to throw when cancelled.
   void *exception;
+
+  // Jump buffer for use during thread cancellation.
+  //
+  // PC range style exceptions can't be thrown over library code that
+  // doesn't have range table info.  Typical pthread installations
+  // aren't compiled with this information.  A jump buffer is used to
+  // skip back out of the pthread library and into an area we know we
+  // can throw exceptions from.
+  jmp_buf recover;
 } _Jv_Thread_t;
 typedef void _Jv_ThreadStartFunc (java::lang::Thread *);
-

 // This convenience function is used to return the POSIX mutex
 // corresponding to our mutex.


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the Java-prs mailing list