Index: Makefile.in =================================================================== --- Makefile.in (revision 172224) +++ Makefile.in (working copy) @@ -58,6 +58,7 @@ @USING_DARWIN_CRT_TRUE@am__append_15 = darwin.cc @USING_POSIX_THREADS_TRUE@am__append_16 = posix-threads.cc @USING_WIN32_THREADS_TRUE@am__append_17 = win32-threads.cc +@USING_RTEMS_THREADS_TRUE@am__append_rtems = rtems-threads.cc @USING_NO_THREADS_TRUE@am__append_18 = no-threads.cc @BUILD_SUBLIBS_TRUE@am__append_19 = libgcj-noncore.la @BUILD_SUBLIBS_TRUE@am__append_20 = libgcj-noncore.la @@ -389,12 +390,14 @@ @USING_DARWIN_CRT_TRUE@am__objects_10 = darwin.lo @USING_POSIX_THREADS_TRUE@am__objects_11 = posix-threads.lo @USING_WIN32_THREADS_TRUE@am__objects_12 = win32-threads.lo +@USING_RTEMS_THREADS_TRUE@am__objects_rtems = rtems-threads.lo @USING_NO_THREADS_TRUE@am__objects_13 = no-threads.lo am_libgcj_la_OBJECTS = prims.lo jni.lo exception.lo stacktrace.lo \ link.lo defineclass.lo verify.lo $(am__objects_2) \ $(am__objects_5) $(am__objects_6) $(am__objects_7) \ $(am__objects_8) $(am__objects_9) $(am__objects_10) \ - $(am__objects_11) $(am__objects_12) $(am__objects_13) + $(am__objects_11) $(am__objects_12) $(am__objects_13) \ + $(am_objects_rtems) libgcj_la_OBJECTS = $(am_libgcj_la_OBJECTS) libgcj_bc_la_LIBADD = am_libgcj_bc_la_OBJECTS = libgcj_bc.lo @@ -1056,7 +1059,8 @@ defineclass.cc verify.cc $(libgcj_interpret_source_files) \ $(nat_source_files) $(am__append_11) $(am__append_12) \ $(am__append_13) $(am__append_14) $(am__append_15) \ - $(am__append_16) $(am__append_17) $(am__append_18) + $(am__append_16) $(am__append_17) $(am__append_18) \ + $(am_append_rtems) @USING_DARWIN_CRT_FALSE@LIBJAVA_LDFLAGS_LIBMATH = -lm @USING_DARWIN_CRT_TRUE@LIBJAVA_LDFLAGS_LIBMATH = nat_files = $(nat_source_files:.cc=.lo) Index: rtems-threads.cc =================================================================== --- rtems-threads.cc (revision 0) +++ rtems-threads.cc (revision 0) @@ -0,0 +1,735 @@ +// rtems-threads.cc - interface between libjava and POSIX threads. +//by lj8175 20110629 +/* Copyright (C) 1998, 1999, 2000, 2001, 2004, 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. */ + +// TO DO: +// * Document signal handling limitations + +#include + +#include "posix.h" +#include "rtems-threads.h" + +// If we're using the Boehm GC, then we need to override some of the +// thread primitives. This is fairly gross. +#ifdef HAVE_BOEHM_GC +#include +#endif /* HAVE_BOEHM_GC */ + +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include // To test for _POSIX_THREAD_PRIORITY_SCHEDULING +#endif + +#include +#include +#include +#include +#include +#include +#include + +// This is used to implement thread startup. +struct starter +{ + _Jv_ThreadStartFunc *method; + _Jv_Thread_t *data; +}; + +// This is the key used to map from the POSIX thread value back to the +// Java object representing the thread. The key is global to all +// threads, so it is ok to make it a global here. +pthread_key_t _Jv_ThreadKey; + +// This is the key used to map from the POSIX thread value back to the +// _Jv_Thread_t* representing the thread. +pthread_key_t _Jv_ThreadDataKey; + +// We keep a count of all non-daemon threads which are running. When +// this reaches zero, _Jv_ThreadWait returns. +static pthread_mutex_t daemon_mutex; +static pthread_cond_t daemon_cond; +static int non_daemon_count; + +// The signal to use when interrupting a thread. +#if defined(LINUX_THREADS) || defined(FREEBSD_THREADS) + // LinuxThreads (prior to glibc 2.1) usurps both SIGUSR1 and SIGUSR2. + // GC on FreeBSD uses both SIGUSR1 and SIGUSR2. +# define INTR SIGHUP +#else /* LINUX_THREADS */ +# define INTR SIGUSR2 +#endif /* LINUX_THREADS */ + +// +// These are the flags that can appear in _Jv_Thread_t. +// + +// Thread started. +#define FLAG_START 0x01 +// Thread is daemon. +#define FLAG_DAEMON 0x02 + + + +int +_Jv_MutexLock (_Jv_Mutex_t *mu) +{ + pthread_t self = pthread_self (); + if (mu->owner == self) + { + mu->count++; + } + else + { + JvSetThreadState holder (_Jv_ThreadCurrent(), JV_BLOCKED); + +# ifdef LOCK_DEBUG + int result = pthread_mutex_lock (&mu->mutex); + if (0 != result) + { + fprintf(stderr, "Pthread_mutex_lock returned %d\n", result); + for (;;) {} + } +# else + pthread_mutex_lock (&mu->mutex); +# endif + mu->count = 1; + mu->owner = self; + } + return 0; +} + +// Wait for the condition variable "CV" to be notified. +// Return values: +// 0: the condition was notified, or the timeout expired. +// _JV_NOT_OWNER: the thread does not own the mutex "MU". +// _JV_INTERRUPTED: the thread was interrupted. Its interrupted flag is set. +int +_Jv_CondWait (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu, + jlong millis, jint nanos) +{ + pthread_t self = pthread_self(); + if (mu->owner != self) + return _JV_NOT_OWNER; + + struct timespec ts; + + JvThreadState new_state = JV_WAITING; + if (millis > 0 || nanos > 0) + { + // Calculate the abstime corresponding to the timeout. + unsigned long long seconds; + unsigned long usec; + + // 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) + { + // We treat a timeout that won't fit into a struct timespec + // as a wait forever. + millis = nanos = 0; + } + else + /* This next statement also cannot overflow. */ + ts.tv_nsec = (usec % 1000000) * 1000 + (nanos % 1000); + } + + _Jv_Thread_t *current = _Jv_ThreadCurrentData (); + java::lang::Thread *current_obj = _Jv_ThreadCurrent (); + + pthread_mutex_lock (¤t->wait_mutex); + + // Now that we hold the wait mutex, check if this thread has been + // interrupted already. + if (current_obj->interrupt_flag) + { + pthread_mutex_unlock (¤t->wait_mutex); + return _JV_INTERRUPTED; + } + + // Set the thread's state. + JvSetThreadState holder (current_obj, new_state); + + // Add this thread to the cv's wait set. + current->next = NULL; + + if (cv->first == NULL) + cv->first = current; + else + for (_Jv_Thread_t *t = cv->first;; t = t->next) + { + if (t->next == NULL) + { + t->next = current; + break; + } + } + + // Record the current lock depth, so it can be restored when we re-aquire it. + int count = mu->count; + + // Release the monitor mutex. + mu->count = 0; + mu->owner = 0; + pthread_mutex_unlock (&mu->mutex); + + int r = 0; + bool done_sleeping = false; + + while (! done_sleeping) + { + if (millis == 0 && nanos == 0) + r = pthread_cond_wait (¤t->wait_cond, ¤t->wait_mutex); + else + r = pthread_cond_timedwait (¤t->wait_cond, ¤t->wait_mutex, + &ts); + + // In older glibc's (prior to 2.1.3), the cond_wait functions may + // spuriously wake up on a signal. Catch that here. + if (r != EINTR) + done_sleeping = true; + } + + // Check for an interrupt *before* releasing the wait mutex. + jboolean interrupted = current_obj->interrupt_flag; + + pthread_mutex_unlock (¤t->wait_mutex); + + // Reaquire the monitor mutex, and restore the lock count. + pthread_mutex_lock (&mu->mutex); + mu->owner = self; + mu->count = count; + + // If we were interrupted, or if a timeout occurred, remove ourself from + // the cv wait list now. (If we were notified normally, notify() will have + // already taken care of this) + if (r == ETIMEDOUT || interrupted) + { + _Jv_Thread_t *prev = NULL; + for (_Jv_Thread_t *t = cv->first; t != NULL; t = t->next) + { + if (t == current) + { + if (prev != NULL) + prev->next = t->next; + else + cv->first = t->next; + t->next = NULL; + break; + } + prev = t; + } + if (interrupted) + return _JV_INTERRUPTED; + } + + return 0; +} + +int +_Jv_CondNotify (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu) +{ + if (_Jv_MutexCheckMonitor (mu)) + return _JV_NOT_OWNER; + + _Jv_Thread_t *target; + _Jv_Thread_t *prev = NULL; + + for (target = cv->first; target != NULL; target = target->next) + { + pthread_mutex_lock (&target->wait_mutex); + + if (target->thread_obj->interrupt_flag) + { + // Don't notify a thread that has already been interrupted. + pthread_mutex_unlock (&target->wait_mutex); + prev = target; + continue; + } + + pthread_cond_signal (&target->wait_cond); + pthread_mutex_unlock (&target->wait_mutex); + + // Two concurrent notify() calls must not be delivered to the same + // thread, so remove the target thread from the cv wait list now. + if (prev == NULL) + cv->first = target->next; + else + prev->next = target->next; + + target->next = NULL; + + break; + } + + return 0; +} + +int +_Jv_CondNotifyAll (_Jv_ConditionVariable_t *cv, _Jv_Mutex_t *mu) +{ + if (_Jv_MutexCheckMonitor (mu)) + return _JV_NOT_OWNER; + + _Jv_Thread_t *target; + _Jv_Thread_t *prev = NULL; + + for (target = cv->first; target != NULL; target = target->next) + { + pthread_mutex_lock (&target->wait_mutex); + pthread_cond_signal (&target->wait_cond); + pthread_mutex_unlock (&target->wait_mutex); + + if (prev != NULL) + prev->next = NULL; + prev = target; + } + if (prev != NULL) + prev->next = NULL; + + cv->first = NULL; + + return 0; +} + +void +_Jv_ThreadInterrupt (_Jv_Thread_t *data) +{ + pthread_mutex_lock (&data->wait_mutex); + + // Set the thread's interrupted flag *after* aquiring its wait_mutex. This + // ensures that there are no races with the interrupt flag being set after + // the waiting thread checks it and before pthread_cond_wait is entered. + data->thread_obj->interrupt_flag = true; + + // Interrupt blocking system calls using a signal. + pthread_kill (data->thread, INTR); + + pthread_cond_signal (&data->wait_cond); + + pthread_mutex_unlock (&data->wait_mutex); +} + +/** + * Releases the block on a thread created by _Jv_ThreadPark(). This + * method can also be used to terminate a blockage caused by a prior + * call to park. This operation is unsafe, as the thread must be + * guaranteed to be live. + * + * @param thread the thread to unblock. + */ +void +ParkHelper::unpark () +{ + using namespace ::java::lang; + volatile obj_addr_t *ptr = &permit; + + /* If this thread is in state RUNNING, give it a permit and return + immediately. */ + 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 + (ptr, Thread::THREAD_PARK_PARKED, Thread::THREAD_PARK_RUNNING)) + { + int result; + pthread_mutex_lock (&mutex); + result = pthread_cond_signal (&cond); + pthread_mutex_unlock (&mutex); + JvAssert (result == 0); + } +} + +/** + * Sets our state to dead. + */ +void +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 + * unpark call has already occurred, this also counts. A timeout + * value of zero is defined as no timeout. When isAbsolute is true, + * the timeout is in milliseconds relative to the epoch. Otherwise, + * the value is the number of nanoseconds which must occur before + * timeout. This call may also return spuriously (i.e. for no + * apparent reason). + * + * @param isAbsolute true if the timeout is specified in milliseconds from + * the epoch. + * @param time either the number of nanoseconds to wait, or a time in + * milliseconds from the epoch to wait for. + */ +void +ParkHelper::park (jboolean isAbsolute, jlong time) +{ + using namespace ::java::lang; + volatile obj_addr_t *ptr = &permit; + + /* If we have a permit, return immediately. */ + if (compare_and_swap + (ptr, Thread::THREAD_PARK_PERMIT, Thread::THREAD_PARK_RUNNING)) + return; + + struct timespec ts; + + if (time) + { + unsigned long long seconds; + unsigned long usec; + + if (isAbsolute) + { + ts.tv_sec = time / 1000; + ts.tv_nsec = (time % 1000) * 1000 * 1000; + } + else + { + // Calculate the abstime corresponding to the timeout. + jlong nanos = time; + jlong millis = 0; + + // 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) + { + // We treat a timeout that won't fit into a struct timespec + // as a wait forever. + millis = nanos = 0; + } + else + /* 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)) + { + int result = 0; + + if (! time) + result = pthread_cond_wait (&cond, &mutex); + else + 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 or were + interrupted, we have to do it ourself. */ + permit = Thread::THREAD_PARK_RUNNING; + } + pthread_mutex_unlock (&mutex); +} + +static void +handle_intr (int) +{ + // Do nothing. +} + +void +_Jv_BlockSigchld() +{ + sigset_t mask; + sigemptyset (&mask); + sigaddset (&mask, SIGCHLD); + int c = pthread_sigmask (SIG_BLOCK, &mask, NULL); + if (c != 0) + JvFail (strerror (c)); +} + +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); + pthread_key_create (&_Jv_ThreadDataKey, NULL); + pthread_mutex_init (&daemon_mutex, NULL); + pthread_cond_init (&daemon_cond, 0); + non_daemon_count = 0; + + // Arrange for the interrupt signal to interrupt system calls. + struct sigaction act; + act.sa_handler = handle_intr; + sigemptyset (&act.sa_mask); + act.sa_flags = 0; + sigaction (INTR, &act, NULL); + + // Block SIGCHLD here to ensure that any non-Java threads inherit the new + // signal mask. + _Jv_BlockSigchld(); + + // Check/set the thread stack size. + size_t min_ss = 32 * 1024; + + if (sizeof (void *) == 8) + // Bigger default on 64-bit systems. + min_ss *= 2; + +#ifdef PTHREAD_STACK_MIN + if (min_ss < PTHREAD_STACK_MIN) + min_ss = PTHREAD_STACK_MIN; +#endif + + if (gcj::stack_size > 0 && gcj::stack_size < min_ss) + gcj::stack_size = min_ss; +} + +_Jv_Thread_t * +_Jv_ThreadInitData (java::lang::Thread *obj) +{ + _Jv_Thread_t *data = (_Jv_Thread_t *) _Jv_Malloc (sizeof (_Jv_Thread_t)); + data->flags = 0; + data->thread_obj = obj; + + pthread_mutex_init (&data->wait_mutex, NULL); + pthread_cond_init (&data->wait_cond, NULL); + + return data; +} + +void +_Jv_ThreadDestroyData (_Jv_Thread_t *data) +{ + pthread_mutex_destroy (&data->wait_mutex); + pthread_cond_destroy (&data->wait_cond); + _Jv_Free ((void *)data); +} + +void +_Jv_ThreadSetPriority (_Jv_Thread_t *data, jint prio) +{ +#ifdef _POSIX_THREAD_PRIORITY_SCHEDULING + if (data->flags & FLAG_START) + { + struct sched_param param; + + param.sched_priority = prio; + pthread_setschedparam (data->thread, SCHED_OTHER, ¶m); + } +#endif +} + +void +_Jv_ThreadRegister (_Jv_Thread_t *data) +{ + pthread_setspecific (_Jv_ThreadKey, data->thread_obj); + pthread_setspecific (_Jv_ThreadDataKey, data); + + // glibc 2.1.3 doesn't set the value of `thread' until after start_routine + // is called. Since it may need to be accessed from the new thread, work + // around the potential race here by explicitly setting it again. + data->thread = pthread_self (); + +# ifdef SLOW_PTHREAD_SELF + // Clear all self cache slots that might be needed by this thread. + int dummy; + int low_index = SC_INDEX(&dummy) + SC_CLEAR_MIN; + int high_index = SC_INDEX(&dummy) + SC_CLEAR_MAX; + for (int i = low_index; i <= high_index; ++i) + { + int current_index = i; + if (current_index < 0) + current_index += SELF_CACHE_SIZE; + if (current_index >= SELF_CACHE_SIZE) + current_index -= SELF_CACHE_SIZE; + _Jv_self_cache[current_index].high_sp_bits = BAD_HIGH_SP_VALUE; + } +# endif + // Block SIGCHLD which is used in natPosixProcess.cc. + _Jv_BlockSigchld(); +} + +void +_Jv_ThreadUnRegister () +{ + pthread_setspecific (_Jv_ThreadKey, NULL); + pthread_setspecific (_Jv_ThreadDataKey, NULL); +} + +// This function is called when a thread is started. We don't arrange +// to call the `run' method directly, because this function must +// return a value. +static void * +really_start (void *x) +{ + struct starter *info = (struct starter *) x; + + _Jv_ThreadRegister (info->data); + + info->method (info->data->thread_obj); + + if (! (info->data->flags & FLAG_DAEMON)) + { + pthread_mutex_lock (&daemon_mutex); + --non_daemon_count; + if (! non_daemon_count) + pthread_cond_signal (&daemon_cond); + pthread_mutex_unlock (&daemon_mutex); + } + + return NULL; +} + +void +_Jv_ThreadStart (java::lang::Thread *thread, _Jv_Thread_t *data, + _Jv_ThreadStartFunc *meth) +{ + struct sched_param param; + pthread_attr_t attr; + struct starter *info; + + if (data->flags & FLAG_START) + return; + data->flags |= FLAG_START; + + // Block SIGCHLD which is used in natPosixProcess.cc. + // The current mask is inherited by the child thread. + _Jv_BlockSigchld(); + + param.sched_priority = thread->getPriority(); + + pthread_attr_init (&attr); + pthread_attr_setschedparam (&attr, ¶m); + pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); + + pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); + pthread_attr_setschedpolicy(&attr, SCHED_RR); + + // Set stack size if -Xss option was given. + if (gcj::stack_size > 0) + { + int e = pthread_attr_setstacksize (&attr, gcj::stack_size); + if (e != 0) + JvFail (strerror (e)); + } + + info = (struct starter *) _Jv_AllocBytes (sizeof (struct starter)); + info->method = meth; + info->data = data; + + if (! thread->isDaemon()) + { + pthread_mutex_lock (&daemon_mutex); + ++non_daemon_count; + pthread_mutex_unlock (&daemon_mutex); + } + else + data->flags |= FLAG_DAEMON; + int r = pthread_create (&data->thread, &attr, really_start, (void *) info); + + pthread_attr_destroy (&attr); + + if (r) + { + const char* msg = "Cannot create additional threads"; + throw new java::lang::OutOfMemoryError (JvNewStringUTF (msg)); + } +} + +void +_Jv_ThreadWait (void) +{ + pthread_mutex_lock (&daemon_mutex); + if (non_daemon_count) + pthread_cond_wait (&daemon_cond, &daemon_mutex); + pthread_mutex_unlock (&daemon_mutex); +} + +#if defined(SLOW_PTHREAD_SELF) + +#include "sysdep/locks.h" + +// Support for pthread_self() lookup cache. +volatile self_cache_entry _Jv_self_cache[SELF_CACHE_SIZE]; + +_Jv_ThreadId_t +_Jv_ThreadSelf_out_of_line(volatile self_cache_entry *sce, size_t high_sp_bits) +{ + pthread_t self = pthread_self(); + sce -> high_sp_bits = high_sp_bits; + write_barrier(); + sce -> self = self; + return self; +} + +#endif /* SLOW_PTHREAD_SELF */ Index: classpath/native/fdlibm/mprec.c =================================================================== --- classpath/native/fdlibm/mprec.c (revision 172224) +++ classpath/native/fdlibm/mprec.c (working copy) @@ -1004,7 +1004,7 @@ {1e-16, 1e-32}; #endif - +#if !defined(__rtems__) double _DEFUN (_mprec_log10, (dig), int dig) @@ -1019,3 +1019,4 @@ } return v; } +#endif Index: include/rtems-threads.h =================================================================== --- include/rtems-threads.h (revision 0) +++ include/rtems-threads.h (revision 0) @@ -0,0 +1,384 @@ +// -*- c++ -*- +// rtems-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 +#include +#include + +// +// 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 +#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__ */ Index: configure =================================================================== --- configure (revision 172224) +++ configure (working copy) @@ -688,6 +688,8 @@ USING_NO_THREADS_TRUE USING_WIN32_THREADS_FALSE USING_WIN32_THREADS_TRUE +USING_RTEMS_THREADS_FALSE +USING_RTEMS_THREADS_TRUE USING_POSIX_THREADS_FALSE USING_POSIX_THREADS_TRUE THREADCXXFLAGS @@ -20704,6 +20706,16 @@ ;; win32) ;; + rtems) +$as_echo "#define HAVE_SYS_SOCKET_H 1" >>confdefs.h +$as_echo "#define HAVE_NETINET_IN_H 1" >>confdefs.h +$as_echo "#define HAVE_ARPA_INET_H 1" >>confdefs.h +$as_echo "#define HAVE_NETDB_H 1" >>confdefs.h +$as_echo "#define HAVE_SYS_IOCTL_H 1" >>confdefs.h +$as_echo "#define HAVE_NET_IF_H 1" >>confdefs.h +$as_echo "#define HAVE_IFADDRS_H 1" >>confdefs.h +$as_echo "#define HAVE_GETTIMEOFDAY 1" >>confdefs.h + ;; decosf1 | irix | mach | os2 | dce | vxworks) as_fn_error "thread package $THREADS not yet supported" "$LINENO" 5 ;; @@ -20809,7 +20821,9 @@ # contexts ourselves. THREADSTARTFILESPEC='crtmt%O%s' ;; - + rtems) + THREADH=rtems-threads.h + ;; none) THREADH=no-threads.h ;; @@ -20839,6 +20853,14 @@ USING_WIN32_THREADS_FALSE= fi + if test "$THREADS" = rtems; then + USING_RTEMS_THREADS_TRUE= + USING_RTEMS_THREADS_FALSE='#' +else + USING_RTEMS_THREADS_TRUE='#' + USING_RTEMS_THREADS_FALSE= +fi + if test "$THREADS" = none; then USING_NO_THREADS_TRUE= USING_NO_THREADS_FALSE='#' @@ -25144,6 +25166,10 @@ as_fn_error "conditional \"USING_WIN32_THREADS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi +if test -z "${USING_RTEMS_THREADS_TRUE}" && test -z "${USING_RTEMS_THREADS_FALSE}"; then + as_fn_error "conditional \"USING_RTEMS_THREADS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi if test -z "${USING_NO_THREADS_TRUE}" && test -z "${USING_NO_THREADS_FALSE}"; then as_fn_error "conditional \"USING_NO_THREADS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 Index: java/lang/natClass.cc =================================================================== --- java/lang/natClass.cc (revision 172224) +++ java/lang/natClass.cc (working copy) @@ -1679,6 +1679,10 @@ return NULL; } +#if defined(__rtems__) +# undef HAVE_TLS +#endif + #ifdef HAVE_TLS // NOTE: MCACHE_SIZE should be a power of 2 minus one. Index: java/net/natVMInetAddressPosix.cc =================================================================== --- java/net/natVMInetAddressPosix.cc (revision 172224) +++ java/net/natVMInetAddressPosix.cc (working copy) @@ -39,8 +39,10 @@ #endif #ifndef HAVE_GETHOSTNAME_DECL +#if !defined(__rtems__) extern "C" int gethostname (char *name, int namelen); #endif +#endif jstring java::net::VMInetAddress::getLocalHostname () Index: Makefile.am =================================================================== --- Makefile.am (revision 172224) +++ Makefile.am (working copy) @@ -478,6 +478,10 @@ libgcj_la_SOURCES += win32-threads.cc endif +if USING_RTEMS_THREADS +libgcj_la_SOURCES += rtems-threads.cc +endif + if USING_NO_THREADS libgcj_la_SOURCES += no-threads.cc endif