mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			385 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			385 lines
		
	
	
		
			9.0 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 (pthread_equal(mu->owner, pthread_self()) == 0);
 | 
						|
}
 | 
						|
 | 
						|
// 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__ */
 |