mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			385 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			385 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
| // -*- 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__ */
 |