summaryrefslogtreecommitdiff
path: root/libjava/include/posix-threads.h
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/include/posix-threads.h')
-rw-r--r--libjava/include/posix-threads.h384
1 files changed, 384 insertions, 0 deletions
diff --git a/libjava/include/posix-threads.h b/libjava/include/posix-threads.h
new file mode 100644
index 000000000..59e65f744
--- /dev/null
+++ b/libjava/include/posix-threads.h
@@ -0,0 +1,384 @@
+// -*- c++ -*-
+// posix-threads.h - Defines for using POSIX threads.
+
+/* Copyright (C) 1998, 1999, 2001, 2003, 2006 Free Software Foundation
+
+ This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
+details. */
+
+#ifndef __JV_POSIX_THREADS__
+#define __JV_POSIX_THREADS__
+
+// NOTE: This file may only reference those pthread functions which
+// are known not to be overridden by the Boehm GC. If in doubt, scan
+// boehm-gc/gc.h. This is yucky but lets us avoid including gc.h
+// everywhere (which would be truly yucky).
+
+#include <pthread.h>
+#include <sched.h>
+#include <sysdep/locks.h>
+
+//
+// Typedefs.
+//
+
+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;
+
+typedef struct
+{
+ // For compatibility, simplicity, and correctness, we do not use the native
+ // pthreads recursive mutex implementation, but simulate them instead.
+
+ // 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. Returns 0 if the lock is held by the current thread, and
+// 1 otherwise.
+inline int
+_Jv_MutexCheckMonitor (_Jv_Mutex_t *mu)
+{
+ return (mu->owner != pthread_self());
+}
+
+// Type identifying a POSIX thread.
+typedef pthread_t _Jv_ThreadDesc_t;
+
+inline _Jv_ThreadDesc_t
+_Jv_GetPlatformThreadID(_Jv_Thread_t *t)
+{
+ return t->thread;
+}
+
+//
+// Signal helpers.
+//
+
+void _Jv_BlockSigchld();
+void _Jv_UnBlockSigchld();
+
+
+//
+// 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);
+
+int _Jv_CondNotifyAll (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu);
+
+inline void
+_Jv_CondInit (_Jv_ConditionVariable_t *cv)
+{
+ cv->first = 0;
+}
+
+//
+// Mutexes.
+//
+
+#ifdef LOCK_DEBUG
+# include <stdio.h>
+#endif
+
+inline void
+_Jv_MutexInit (_Jv_Mutex_t *mu)
+{
+# 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;
+ 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;
+}
+
+#ifndef LINUX_THREADS
+
+// pthread_mutex_destroy does nothing on Linux and it is a win to avoid
+// defining this macro.
+
+#define _Jv_HaveMutexDestroy
+
+inline void
+_Jv_MutexDestroy (_Jv_Mutex_t *mu)
+{
+ pthread_mutex_destroy (&mu->mutex);
+}
+
+#endif /* LINUX_THREADS */
+
+//
+// Thread creation and manipulation.
+//
+
+void _Jv_InitThreads (void);
+
+_Jv_Thread_t *_Jv_ThreadInitData (java::lang::Thread *thread);
+void _Jv_ThreadDestroyData (_Jv_Thread_t *data);
+
+inline java::lang::Thread *
+_Jv_ThreadCurrent (void)
+{
+ extern pthread_key_t _Jv_ThreadKey;
+ return (java::lang::Thread *) pthread_getspecific (_Jv_ThreadKey);
+}
+
+#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)
+{
+ return _Jv_self;
+}
+
+#define JV_SELF_DEFINED
+
+#endif /* __ia64__ */
+
+#ifdef __alpha__
+
+typedef void *_Jv_ThreadId_t;
+
+inline _Jv_ThreadId_t
+_Jv_ThreadSelf (void)
+{
+ return __builtin_thread_pointer ();
+}
+
+#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);
+}
+
+#define JV_SELF_DEFINED
+
+#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)
+{
+ return pthread_self();
+}
+
+#endif /* !JV_SELF_DEFINED */
+
+#endif /* JV_HASH_SYNCHRONIZATION */
+
+inline _Jv_Thread_t *
+_Jv_ThreadCurrentData (void)
+{
+ extern pthread_key_t _Jv_ThreadDataKey;
+ return (_Jv_Thread_t *) pthread_getspecific (_Jv_ThreadDataKey);
+}
+
+inline void
+_Jv_ThreadYield (void)
+{
+#ifdef HAVE_SCHED_YIELD
+ sched_yield ();
+#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,
+ _Jv_ThreadStartFunc *meth);
+
+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::destroy ()
+{
+ pthread_mutex_destroy (&mutex);
+ pthread_cond_destroy (&cond);
+}
+
+#endif /* __JV_POSIX_THREADS__ */