OSDN Git Service

Regenerate tree using Autoconf 2.64 and Automake 1.11.
[pf3gnuchains/gcc-fork.git] / libjava / include / posix-threads.h
index f495283..806ee55 100644 (file)
@@ -1,7 +1,7 @@
 // -*- c++ -*-
 // posix-threads.h - Defines for using POSIX threads.
 
-/* Copyright (C) 1998, 1999  Cygnus Solutions
+/* Copyright (C) 1998, 1999, 2001, 2003, 2006  Free Software Foundation
 
    This file is part of libgcj.
 
@@ -19,165 +19,159 @@ details.  */
 
 #include <pthread.h>
 #include <sched.h>
-
-#if defined (HAVE_PTHREAD_MUTEXATTR_SETTYPE) || defined (HAVE_PTHREAD_MUTEXATTR_SETKIND_NP)
-#  define HAVE_RECURSIVE_MUTEX 1
-#endif
-
+#include <sysdep/locks.h>
 
 //
 // Typedefs.
 //
 
-typedef pthread_cond_t _Jv_ConditionVariable_t;
-
-#if defined (PTHREAD_MUTEX_HAVE_M_COUNT) || defined (PTHREAD_MUTEX_HAVE___M_COUNT)
-
-// On Linux we use implementation details of mutexes in order to get
-// faster results.
-typedef pthread_mutex_t _Jv_Mutex_t;
-
-#else /* LINUX_THREADS */
-
-#define PTHREAD_MUTEX_IS_STRUCT
-
-typedef struct
-{
-  // Mutex used when locking this structure transiently.
-  pthread_mutex_t mutex;
-#ifndef HAVE_RECURSIVE_MUTEX
-  // Some systems do not have recursive mutexes, so we must simulate
-  // them.  Solaris is one such system.
-
-  // Mutex the thread holds the entire time this mutex is held.  This
-  // is used to make condition variables work properly.
-  pthread_mutex_t mutex2;
-  // Condition variable used when waiting for this lock.
-  pthread_cond_t cond;
-  // Thread holding this mutex.  If COUNT is 0, no thread is holding.
-  pthread_t thread;
-#endif /* HAVE_RECURSIVE_MUTEX */
-
-  // Number of times mutex is held.  If 0, the lock is not held.  We
-  // do this even if we have a native recursive mutex so that we can
-  // keep track of whether the lock is held; this lets us do error
-  // checking.  FIXME it would be nice to optimize this; on some
-  // systems we could do so by relying on implementation details of
-  // recursive mutexes.
-  int count;
-} _Jv_Mutex_t;
-
-#endif
-
-typedef struct
+typedef struct _Jv_Thread_t
 {
   // Flag values are defined in implementation.
   int flags;
 
   // Actual thread id.
   pthread_t thread;
+  
+  // Java Thread object.
+  java::lang::Thread *thread_obj;
+  
+  // Condition variable and corresponding mutex, used to implement the
+  // interruptable wait/notify mechanism.
+  pthread_cond_t wait_cond;
+  pthread_mutex_t wait_mutex;
+
+  // Next thread for Condition Variable wait-list chain.
+  _Jv_Thread_t *next;
+  
 } _Jv_Thread_t;
+
 typedef void _Jv_ThreadStartFunc (java::lang::Thread *);
 
+// Condition Variables used to implement wait/notify/sleep/interrupt.
+typedef struct
+{
+  // Linked list of Threads that are waiting to be notified.
+  _Jv_Thread_t *first;
+
+} _Jv_ConditionVariable_t;
 
-// This convenience function is used to return the POSIX mutex
-// corresponding to our mutex.
-inline pthread_mutex_t *
-_Jv_PthreadGetMutex (_Jv_Mutex_t *mu)
+typedef struct
 {
-#if ! defined (PTHREAD_MUTEX_IS_STRUCT)
-  return mu;
-#elif defined (HAVE_RECURSIVE_MUTEX)
-  return &mu->mutex;
-#else
-  return &mu->mutex2;
-#endif
-}
+  // For compatibility, simplicity, and correctness, we do not use the native
+  // pthreads recursive mutex implementation, but simulate them instead.
 
-#include <stdio.h>
+  // Mutex the thread holds the entire time this mutex is held. 
+  pthread_mutex_t mutex;
+
+  // Thread holding this mutex.
+  pthread_t owner;
+
+  // Number of times mutex is held (lock depth).  If 0, the lock is not held.
+  int count;
+} _Jv_Mutex_t;
 
 // This is a convenience function used only by the pthreads thread
 // implementation.  This is slow, but that's too bad -- we need to do
 // the checks for correctness.  It might be nice to be able to compile
-// this out.
+// this out.  Returns 0 if the lock is held by the current thread, and
+// 1 otherwise.
 inline int
-_Jv_PthreadCheckMonitor (_Jv_Mutex_t *mu)
+_Jv_MutexCheckMonitor (_Jv_Mutex_t *mu)
 {
-  pthread_mutex_t *pmu = _Jv_PthreadGetMutex (mu);
-  // See if the mutex is locked by this thread.
-  if (pthread_mutex_trylock (pmu))
-    return 1;
-#if defined (PTHREAD_MUTEX_HAVE_M_COUNT)
-  // On Linux we exploit knowledge of the implementation.
-  int r = pmu->m_count == 1;
-#elif defined (PTHREAD_MUTEX_HAVE___M_COUNT)
-  // In glibc 2.1, the first time the mutex is grabbed __m_count is
-  // set to 0 and __m_owner is set to pthread_self().
-  int r = ! pmu->__m_count;
-#else
-  int r = mu->count == 0;
-#endif
-  pthread_mutex_unlock (pmu);
-  return r;
+  return (mu->owner != pthread_self());
 }
 
-//
-// Condition variables.
-//
+// Type identifying a POSIX thread.
+typedef pthread_t _Jv_ThreadDesc_t;
 
-inline void
-_Jv_CondInit (_Jv_ConditionVariable_t *cv)
+inline _Jv_ThreadDesc_t
+_Jv_GetPlatformThreadID(_Jv_Thread_t *t)
 {
-  pthread_cond_init (cv, 0);
+  return t->thread;
 }
 
-#ifndef LINUX_THREADS
-
-// pthread_cond_destroy does nothing on Linux and it is a win to avoid
-// defining this macro.
+//
+// Signal helpers.
+//
 
-#define _Jv_HaveCondDestroy
+void _Jv_BlockSigchld();
+void _Jv_UnBlockSigchld();
 
-inline void
-_Jv_CondDestroy (_Jv_ConditionVariable_t *cv)
-{
-  pthread_cond_destroy (cv);
-}
 
-#endif /* LINUX_THREADS */
+//
+// Condition variables.
+//
 
 int _Jv_CondWait (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu,
                  jlong millis, jint nanos);
+                 
+int _Jv_CondNotify (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu);
 
-inline int
-_Jv_CondNotify (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu)
-{
-  return _Jv_PthreadCheckMonitor (mu) || pthread_cond_signal (cv);
-}
+int _Jv_CondNotifyAll (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu);
 
-inline int
-_Jv_CondNotifyAll (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu)
+inline void
+_Jv_CondInit (_Jv_ConditionVariable_t *cv)
 {
-  return _Jv_PthreadCheckMonitor (mu) || pthread_cond_broadcast (cv);
+  cv->first = 0;
 }
 
-
 //
 // Mutexes.
 //
 
-#ifdef RECURSIVE_MUTEX_IS_DEFAULT
+#ifdef LOCK_DEBUG
+# include <stdio.h>
+#endif
+
 inline void
 _Jv_MutexInit (_Jv_Mutex_t *mu)
 {
-  pthread_mutex_init (_Jv_PthreadGetMutex (mu), NULL);
-#ifdef PTHREAD_MUTEX_IS_STRUCT
+# ifdef LOCK_DEBUG /* Assumes Linuxthreads */
+  pthread_mutexattr_t attr;
+  pthread_mutexattr_init(&attr);
+  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
+  pthread_mutex_init (&mu->mutex, &attr);
+# else
+  pthread_mutex_init (&mu->mutex, 0);
+# endif
+
   mu->count = 0;
-#endif
+  mu->owner = 0;
+}
+
+extern int _Jv_MutexLock (_Jv_Mutex_t *);
+
+inline int
+_Jv_MutexUnlock (_Jv_Mutex_t *mu)
+{
+  if (_Jv_MutexCheckMonitor (mu))
+    {
+#     ifdef LOCK_DEBUG
+       fprintf(stderr, "_Jv_MutexUnlock: Not owner\n");
+       for (;;) {}
+#     endif
+      return 1;
+    }
+    
+  mu->count--;
+
+  if (mu->count == 0)
+    {
+      mu->owner = 0;
+#     ifdef LOCK_DEBUG
+       int result = pthread_mutex_unlock (&mu->mutex);
+       if (0 != result)
+         {
+           fprintf(stderr, "Pthread_mutex_unlock returned %d\n", result);
+           for (;;) {}
+         }
+#     else
+        pthread_mutex_unlock (&mu->mutex);
+#     endif
+    }
+  return 0;
 }
-#else
-void _Jv_MutexInit (_Jv_Mutex_t *mu);
-#endif
 
 #ifndef LINUX_THREADS
 
@@ -186,68 +180,158 @@ void _Jv_MutexInit (_Jv_Mutex_t *mu);
 
 #define _Jv_HaveMutexDestroy
 
-#ifdef HAVE_RECURSIVE_MUTEX
-
-inline void
+inline void 
 _Jv_MutexDestroy (_Jv_Mutex_t *mu)
 {
-  pthread_mutex_destroy (_Jv_PthreadGetMutex (mu));
+  pthread_mutex_destroy (&mu->mutex);
 }
 
-#else /* HAVE_RECURSIVE_MUTEX */
+#endif /* LINUX_THREADS */
 
-extern void _Jv_MutexDestroy (_Jv_Mutex_t *mu);
+//
+// Thread creation and manipulation.
+//
 
-#endif /* HAVE_RECURSIVE_MUTEX */
-#endif /* LINUX_THREADS */
+void _Jv_InitThreads (void);
 
-#ifdef HAVE_RECURSIVE_MUTEX
+_Jv_Thread_t *_Jv_ThreadInitData (java::lang::Thread *thread);
+void _Jv_ThreadDestroyData (_Jv_Thread_t *data);
 
-inline int
-_Jv_MutexLock (_Jv_Mutex_t *mu)
+inline java::lang::Thread *
+_Jv_ThreadCurrent (void)
 {
-  int r = pthread_mutex_lock (_Jv_PthreadGetMutex (mu));
-#ifdef PTHREAD_MUTEX_IS_STRUCT
-  if (! r)
-    ++mu->count;
-#endif
-  return r;
+  extern pthread_key_t _Jv_ThreadKey;
+  return (java::lang::Thread *) pthread_getspecific (_Jv_ThreadKey);
 }
 
-inline int
-_Jv_MutexUnlock (_Jv_Mutex_t *mu)
+#ifdef JV_HASH_SYNCHRONIZATION
+// Should be specialized to just load the "current thread" register
+// on platforms that support it.   Speed is of the essence.  The value
+// of the descriptor is not, so long as there is a one-to-one correspondence
+// to threads.
+
+
+#ifdef __ia64__
+
+typedef size_t _Jv_ThreadId_t;
+
+register size_t _Jv_self __asm__("r13");
+       // For linux_threads this is really a pointer to its thread data
+       // structure.  We treat it as opaque.  That should also work
+       // on other operating systems that follow the ABI standard.
+
+// This should become the prototype for machines that maintain a thread
+// pointer in a register.
+inline _Jv_ThreadId_t
+_Jv_ThreadSelf (void)
 {
-  int r = pthread_mutex_unlock (_Jv_PthreadGetMutex (mu));
-#ifdef PTHREAD_MUTEX_IS_STRUCT
-  if (! r)
-    --mu->count;
-#endif
-  return r;
+  return _Jv_self;
 }
 
-#else /* HAVE_RECURSIVE_MUTEX */
+#define JV_SELF_DEFINED
 
-extern int _Jv_MutexLock (_Jv_Mutex_t *mu);
-extern int _Jv_MutexUnlock (_Jv_Mutex_t *mu);
+#endif /* __ia64__ */
 
-#endif /* HAVE_RECURSIVE_MUTEX */
+#ifdef __alpha__
 
+typedef void *_Jv_ThreadId_t;
 
-//
-// Thread creation and manipulation.
-//
+inline _Jv_ThreadId_t
+_Jv_ThreadSelf (void)
+{
+  return __builtin_thread_pointer ();
+}
 
-void _Jv_InitThreads (void);
+#define JV_SELF_DEFINED
+
+#endif /* __alpha__ */
+
+#if defined(SLOW_PTHREAD_SELF)
+
+#include "sysdep/locks.h"
+
+typedef pthread_t _Jv_ThreadId_t;
+
+// E.g. on X86 Linux, pthread_self() is too slow for our purpose.
+// Instead we maintain a cache based on the current sp value.
+// This is similar to what's done for thread local allocation in the
+// GC, only far simpler.
+// This code should probably go away when Linux/X86 starts using a
+// segment register to hold the thread id.
+# define LOG_THREAD_SPACING 12
+                       // If two thread pointer values are closer than
+                       // 1 << LOG_THREAD_SPACING, we assume they belong
+                       // to the same thread.
+# define SELF_CACHE_SIZE 1024
+# define SC_INDEX(sp) (((unsigned long)(sp) >> 19) & (SELF_CACHE_SIZE-1))
+                       // Mapping from sp value to cache index.
+                       // Note that this is not in any real sense a hash
+                       // function, since we need to be able to clear
+                       // all possibly matching slots on thread startup.
+                       // Thus all entries that might correspond to
+                       // a given thread are intentionally contiguous.
+                       // Works well with anything that allocates at least
+                       // 512KB stacks.
+# define SC_CLEAR_MIN (-16)    // When starting a new thread, we clear
+# define SC_CLEAR_MAX 0                // all self cache entries between
+                               // SC_INDEX(sp)+SC_CLEAR_MIN and
+                               // SC_INDEX(sp)+SC_CLEAR_MAX to ensure
+                               // we never see stale values.  The
+                               // current values assume a downward
+                               // growing stack of size <= 7.5 MB.
+# define BAD_HIGH_SP_VALUE ((size_t)(-1))
+
+extern volatile
+struct self_cache_entry {
+  size_t high_sp_bits; // sp value >> LOG_THREAD_SPACING
+  pthread_t self;      // Corresponding thread
+} _Jv_self_cache[];
+
+void _Jv_Self_Cache_Init();
+
+_Jv_ThreadId_t
+_Jv_ThreadSelf_out_of_line(volatile self_cache_entry *sce,
+                          size_t high_sp_bits);
+  
+inline _Jv_ThreadId_t
+_Jv_ThreadSelf (void)
+{
+  int dummy;
+  size_t sp = (size_t)(&dummy);
+  unsigned h = SC_INDEX(sp);
+  volatile self_cache_entry *sce = _Jv_self_cache + h;
+  pthread_t candidate_self = sce -> self;  // Read must precede following one.
+  read_barrier();
+  if (sce -> high_sp_bits == sp >> LOG_THREAD_SPACING)
+    {
+      // The sce -> self value we read must be valid.  An intervening
+      // cache replacement by another thread would have first replaced
+      // high_sp_bits by something else, and it can't possibly change
+      // back without our intervention.
+      return candidate_self;
+    }
+  else
+    return _Jv_ThreadSelf_out_of_line(sce, sp >> LOG_THREAD_SPACING);
+}
 
-void _Jv_ThreadInitData (_Jv_Thread_t **data, java::lang::Thread *thread);
+#define JV_SELF_DEFINED
 
-inline java::lang::Thread *
-_Jv_ThreadCurrent (void)
+#endif /* SLOW_PTHREAD_SELF */
+
+#ifndef JV_SELF_DEFINED /* If all else fails, call pthread_self directly */
+
+typedef pthread_t _Jv_ThreadId_t;
+
+inline _Jv_ThreadId_t
+_Jv_ThreadSelf (void)
 {
-  extern pthread_key_t _Jv_ThreadKey;
-  return (java::lang::Thread *) pthread_getspecific (_Jv_ThreadKey);
+  return pthread_self();
 }
 
+#endif /* !JV_SELF_DEFINED */
+
+#endif /* JV_HASH_SYNCHRONIZATION */
+
 inline _Jv_Thread_t *
 _Jv_ThreadCurrentData (void)
 {
@@ -263,6 +347,9 @@ _Jv_ThreadYield (void)
 #endif /* HAVE_SCHED_YIELD */
 }
 
+void _Jv_ThreadRegister (_Jv_Thread_t *data);
+void _Jv_ThreadUnRegister ();
+
 void _Jv_ThreadSetPriority (_Jv_Thread_t *data, jint prio);
 
 void _Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *data,
@@ -272,4 +359,33 @@ void _Jv_ThreadWait (void);
 
 void _Jv_ThreadInterrupt (_Jv_Thread_t *data);
 
+// park() / unpark() support
+
+struct ParkHelper
+{
+  volatile obj_addr_t permit;
+  pthread_mutex_t mutex;
+  pthread_cond_t cond;
+  
+  void init ();
+  void deactivate ();
+  void destroy ();
+  void park (jboolean isAbsolute, jlong time);
+  void unpark ();
+};
+
+inline void
+ParkHelper::init ()
+{
+  pthread_mutex_init (&mutex, NULL);
+  pthread_cond_init (&cond, NULL);
+}
+
+inline void
+ParkHelper::destroy ()
+{
+  pthread_mutex_destroy (&mutex);
+  pthread_cond_destroy (&cond);
+}
+
 #endif /* __JV_POSIX_THREADS__ */