OSDN Git Service

2010-05-15 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / libjava / posix-threads.cc
index 6ea724b..66693ab 100644 (file)
@@ -14,6 +14,7 @@ details.  */
 #include <config.h>
 
 #include "posix.h"
+#include "posix-threads.h"
 
 // If we're using the Boehm GC, then we need to override some of the
 // thread primitives.  This is fairly gross.
@@ -358,15 +359,17 @@ ParkHelper::unpark ()
   if (compare_and_swap 
       (ptr, Thread::THREAD_PARK_RUNNING, Thread::THREAD_PARK_PERMIT))
     return;
-  
+
   /* If this thread is parked, put it into state RUNNING and send it a
      signal.  */
-  if (compare_and_swap 
+  if (compare_and_swap
       (ptr, Thread::THREAD_PARK_PARKED, Thread::THREAD_PARK_RUNNING))
     {
+      int result;
       pthread_mutex_lock (&mutex);
-      pthread_cond_signal (&cond);
+      result = pthread_cond_signal (&cond);
       pthread_mutex_unlock (&mutex);
+      JvAssert (result == 0);
     }
 }
 
@@ -379,6 +382,14 @@ ParkHelper::deactivate ()
   permit = ::java::lang::Thread::THREAD_PARK_DEAD;
 }
 
+void
+ParkHelper::init ()
+{
+  pthread_mutex_init (&mutex, NULL);
+  pthread_cond_init (&cond, NULL);
+  permit = ::java::lang::Thread::THREAD_PARK_RUNNING;
+}
+
 /**
  * Blocks the thread until a matching _Jv_ThreadUnpark() occurs, the
  * thread is interrupted or the optional timeout expires.  If an
@@ -406,32 +417,44 @@ ParkHelper::park (jboolean isAbsolute, jlong time)
     return;
 
   struct timespec ts;
-  jlong millis = 0, nanos = 0;
 
   if (time)
     {
+      unsigned long long seconds;
+      unsigned long usec;
+
       if (isAbsolute)
        {
-         millis = time;
-         nanos = 0;
+         ts.tv_sec = time / 1000;
+         ts.tv_nsec = (time % 1000) * 1000 * 1000;
        }
       else
        {
-         millis = java::lang::System::currentTimeMillis();
-         nanos = time;
-       }
-
-      if (millis > 0 || nanos > 0)
-       {
          // Calculate the abstime corresponding to the timeout.
-         // Everything is in milliseconds.
-         //
-         // We use `unsigned long long' rather than jlong because our
-         // caller may pass up to Long.MAX_VALUE millis.  This would
-         // overflow the range of a timespec.
+         jlong nanos = time;
+         jlong millis = 0;
 
-         unsigned long long m = (unsigned long long)millis;
-         unsigned long long seconds = m / 1000; 
+         // For better accuracy, should use pthread_condattr_setclock
+         // and clock_gettime.
+#ifdef HAVE_GETTIMEOFDAY
+         timeval tv;
+         gettimeofday (&tv, NULL);
+         usec = tv.tv_usec;
+         seconds = tv.tv_sec;
+#else
+         unsigned long long startTime
+           = java::lang::System::currentTimeMillis();
+         seconds = startTime / 1000;
+         /* Assume we're about half-way through this millisecond.  */
+         usec = (startTime % 1000) * 1000 + 500;
+#endif
+         /* These next two statements cannot overflow.  */
+         usec += nanos / 1000;
+         usec += (millis % 1000) * 1000;
+         /* These two statements could overflow only if tv.tv_sec was
+            insanely large.  */
+         seconds += millis / 1000;
+         seconds += usec / 1000000;
 
          ts.tv_sec = seconds;
          if (ts.tv_sec < 0 || (unsigned long long)ts.tv_sec != seconds)
@@ -441,29 +464,30 @@ ParkHelper::park (jboolean isAbsolute, jlong time)
              millis = nanos = 0;
            }
          else
-           {
-             m %= 1000;
-             ts.tv_nsec = m * 1000000 + (unsigned long long)nanos;
-           }
+           /* This next statement also cannot overflow.  */
+           ts.tv_nsec = (usec % 1000000) * 1000 + (nanos % 1000);
        }
     }
-      
+
+  pthread_mutex_lock (&mutex);
   if (compare_and_swap 
       (ptr, Thread::THREAD_PARK_RUNNING, Thread::THREAD_PARK_PARKED))
     {
-      pthread_mutex_lock (&mutex);
-      if (millis == 0 && nanos == 0)
-       pthread_cond_wait (&cond, &mutex);
+      int result = 0;
+
+      if (! time)
+       result = pthread_cond_wait (&cond, &mutex);
       else
-       pthread_cond_timedwait (&cond, &mutex, &ts);
-      pthread_mutex_unlock (&mutex);
-      
+       result = pthread_cond_timedwait (&cond, &mutex, &ts);
+
+      JvAssert (result == 0 || result == ETIMEDOUT);
+
       /* If we were unparked by some other thread, this will already
-        be in state THREAD_PARK_RUNNING.  If we timed out, we have to
-        do it ourself.  */
-      compare_and_swap 
-       (ptr, Thread::THREAD_PARK_PARKED, Thread::THREAD_PARK_RUNNING);
+        be in state THREAD_PARK_RUNNING.  If we timed out or were
+        interrupted, we have to do it ourself.  */
+      permit = Thread::THREAD_PARK_RUNNING;
     }
+  pthread_mutex_unlock (&mutex);
 }
 
 static void
@@ -472,8 +496,8 @@ handle_intr (int)
   // Do nothing.
 }
 
-static void
-block_sigchld()
+void
+_Jv_BlockSigchld()
 {
   sigset_t mask;
   sigemptyset (&mask);
@@ -484,6 +508,17 @@ block_sigchld()
 }
 
 void
+_Jv_UnBlockSigchld()
+{
+  sigset_t mask;
+  sigemptyset (&mask);
+  sigaddset (&mask, SIGCHLD);
+  int c = pthread_sigmask (SIG_UNBLOCK, &mask, NULL);
+  if (c != 0)
+    JvFail (strerror (c));
+}
+
+void
 _Jv_InitThreads (void)
 {
   pthread_key_create (&_Jv_ThreadKey, NULL);
@@ -501,7 +536,7 @@ _Jv_InitThreads (void)
 
   // Block SIGCHLD here to ensure that any non-Java threads inherit the new 
   // signal mask.
-  block_sigchld();
+  _Jv_BlockSigchld();
 
   // Check/set the thread stack size.
   size_t min_ss = 32 * 1024;
@@ -581,7 +616,7 @@ _Jv_ThreadRegister (_Jv_Thread_t *data)
       }
 # endif
   // Block SIGCHLD which is used in natPosixProcess.cc.
-  block_sigchld();
+  _Jv_BlockSigchld();
 }
 
 void
@@ -629,7 +664,7 @@ _Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *data,
 
   // Block SIGCHLD which is used in natPosixProcess.cc.
   // The current mask is inherited by the child thread.
-  block_sigchld();
+  _Jv_BlockSigchld();
 
   param.sched_priority = thread->getPriority();