e301621d19
* configure.in: Rename THREADLIB to THREADLIBS. * Makefile.am (LINK): Add $(THREADLIBS) to libtool command line. This ensures that we link the correct version of the linuxthreads semaphore functions. * Makefile.in: Rebuilt. * configure: Rebuilt. * linux_thread.c (GC_thr_init, GC_suspend_handler): Add SIGABRT to the list of signals which are not blocked during suspend in the NO_SIGNALS case. For libjava: * Makefile.am (libgcj_la_LIBADD): Add $(THREADLIBS). This ensures that the correct versions of various linuxthreads functions get linked. * Makefile.in: Rebuilt. * java/lang/natThread.cc (finalize_native): New static function. Call _Jv_ThreadDestroyData. (initialize_native): Register finalizer for "data". * include/posix-threads.h (_Jv_ThreadInitData): New simpler prototype. (_Jv_ThreadDestroyData): New prototype. * include/win32-threads.h: Ditto. * include/no-threads.h: Ditto. * posix-threads.cc (_Jv_ThreadInitData): Implement new prototype. (_Jv_ThreadDestroyData): New function. Free native thread "data" and move mutex and condition variable destroy code from: (really_start): ...here. (_Jv_ThreadStart): Set PTHREAD_CREATE_DETACHED. * win32-threads.cc (_Jv_ThreadInitData): Implement new prototype. (_Jv_ThreadDestroyData): Implemented. * nogc.cc (_Jv_AllocObject): Use "void *" not "ptr_t". (_Jv_AllocArray): Ditto. From-SVN: r38557
347 lines
8.4 KiB
C++
347 lines
8.4 KiB
C++
// natThread.cc - Native part of Thread class.
|
||
|
||
/* Copyright (C) 1998, 1999, 2000 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. */
|
||
|
||
#include <config.h>
|
||
|
||
#include <stdlib.h>
|
||
|
||
#include <gcj/cni.h>
|
||
#include <jvm.h>
|
||
#include <java-threads.h>
|
||
|
||
#include <java/lang/Thread.h>
|
||
#include <java/lang/ThreadGroup.h>
|
||
#include <java/lang/IllegalArgumentException.h>
|
||
#include <java/lang/UnsupportedOperationException.h>
|
||
#include <java/lang/IllegalThreadStateException.h>
|
||
#include <java/lang/InterruptedException.h>
|
||
#include <java/lang/NullPointerException.h>
|
||
|
||
#include <jni.h>
|
||
|
||
#ifdef ENABLE_JVMPI
|
||
#include <jvmpi.h>
|
||
#endif
|
||
|
||
|
||
|
||
// This structure is used to represent all the data the native side
|
||
// needs. An object of this type is assigned to the `data' member of
|
||
// the Thread class.
|
||
struct natThread
|
||
{
|
||
// These are used to interrupt sleep and join calls. We can share a
|
||
// condition variable here since it only ever gets notified when the thread
|
||
// exits.
|
||
_Jv_Mutex_t join_mutex;
|
||
_Jv_ConditionVariable_t join_cond;
|
||
|
||
// This is private data for the thread system layer.
|
||
_Jv_Thread_t *thread;
|
||
|
||
// Each thread has its own JNI object.
|
||
JNIEnv *jni_env;
|
||
};
|
||
|
||
static void finalize_native (jobject ptr);
|
||
|
||
// This is called from the constructor to initialize the native side
|
||
// of the Thread.
|
||
void
|
||
java::lang::Thread::initialize_native (void)
|
||
{
|
||
natThread *nt = (natThread *) _Jv_AllocBytes (sizeof (natThread));
|
||
|
||
// The native thread data is kept in a Object field, not a rawdata, so that
|
||
// the GC allocator can be used and a finalizer run after the thread becomes
|
||
// unreachable. Note that this relies on the GC's ability to finalize
|
||
// non-Java objects. FIXME?
|
||
data = reinterpret_cast<jobject> (nt);
|
||
|
||
// Register a finalizer to clean up the native thread resources.
|
||
_Jv_RegisterFinalizer (data, finalize_native);
|
||
|
||
_Jv_MutexInit (&nt->join_mutex);
|
||
_Jv_CondInit (&nt->join_cond);
|
||
nt->thread = _Jv_ThreadInitData (this);
|
||
// FIXME: if JNI_ENV is set we will want to free it. It is
|
||
// malloc()d.
|
||
nt->jni_env = NULL;
|
||
}
|
||
|
||
static void
|
||
finalize_native (jobject ptr)
|
||
{
|
||
natThread *nt = (natThread *) ptr;
|
||
_Jv_ThreadDestroyData (nt->thread);
|
||
}
|
||
|
||
jint
|
||
java::lang::Thread::countStackFrames (void)
|
||
{
|
||
// NOTE: This is deprecated in JDK 1.2.
|
||
JvFail ("java::lang::Thread::countStackFrames unimplemented");
|
||
return 0;
|
||
}
|
||
|
||
java::lang::Thread *
|
||
java::lang::Thread::currentThread (void)
|
||
{
|
||
return _Jv_ThreadCurrent ();
|
||
}
|
||
|
||
void
|
||
java::lang::Thread::destroy (void)
|
||
{
|
||
// NOTE: This is marked as unimplemented in the JDK 1.2
|
||
// documentation.
|
||
JvFail ("java::lang::Thread::destroy unimplemented");
|
||
}
|
||
|
||
void
|
||
java::lang::Thread::interrupt (void)
|
||
{
|
||
natThread *nt = (natThread *) data;
|
||
_Jv_ThreadInterrupt (nt->thread);
|
||
}
|
||
|
||
void
|
||
java::lang::Thread::join (jlong millis, jint nanos)
|
||
{
|
||
if (millis < 0 || nanos < 0 || nanos > 999999)
|
||
_Jv_Throw (new IllegalArgumentException);
|
||
|
||
Thread *current = currentThread ();
|
||
|
||
// Here `NT' is the native structure for the thread we are trying to join.
|
||
natThread *nt = (natThread *) data;
|
||
|
||
// Now wait for: (1) an interrupt, (2) the thread to exit, or (3)
|
||
// the timeout to occur.
|
||
_Jv_MutexLock (&nt->join_mutex);
|
||
if (! isAlive ())
|
||
{
|
||
_Jv_MutexUnlock (&nt->join_mutex);
|
||
return;
|
||
}
|
||
_Jv_CondWait (&nt->join_cond, &nt->join_mutex, millis, nanos);
|
||
_Jv_MutexUnlock (&nt->join_mutex);
|
||
|
||
if (current->isInterrupted (true))
|
||
_Jv_Throw (new InterruptedException);
|
||
}
|
||
|
||
void
|
||
java::lang::Thread::resume (void)
|
||
{
|
||
checkAccess ();
|
||
JvFail ("java::lang::Thread::resume unimplemented");
|
||
}
|
||
|
||
void
|
||
java::lang::Thread::setPriority (jint newPriority)
|
||
{
|
||
checkAccess ();
|
||
if (newPriority < MIN_PRIORITY || newPriority > MAX_PRIORITY)
|
||
_Jv_Throw (new IllegalArgumentException);
|
||
|
||
jint gmax = group->getMaxPriority();
|
||
if (newPriority > gmax)
|
||
newPriority = gmax;
|
||
|
||
priority = newPriority;
|
||
natThread *nt = (natThread *) data;
|
||
_Jv_ThreadSetPriority (nt->thread, priority);
|
||
}
|
||
|
||
void
|
||
java::lang::Thread::sleep (jlong millis, jint nanos)
|
||
{
|
||
if (millis < 0 || nanos < 0 || nanos > 999999)
|
||
_Jv_Throw (new IllegalArgumentException);
|
||
|
||
if (millis == 0 && nanos == 0)
|
||
++nanos;
|
||
|
||
Thread *current = currentThread ();
|
||
|
||
// We use a condition variable to implement sleeping so that an
|
||
// interrupt can wake us up.
|
||
natThread *nt = (natThread *) current->data;
|
||
_Jv_MutexLock (&nt->join_mutex);
|
||
_Jv_CondWait (&nt->join_cond, &nt->join_mutex, millis, nanos);
|
||
_Jv_MutexUnlock (&nt->join_mutex);
|
||
|
||
if (current->isInterrupted (true))
|
||
_Jv_Throw (new InterruptedException);
|
||
}
|
||
|
||
void
|
||
java::lang::Thread::finish_ ()
|
||
{
|
||
natThread *nt = (natThread *) data;
|
||
|
||
group->removeThread (this);
|
||
|
||
#ifdef ENABLE_JVMPI
|
||
if (_Jv_JVMPI_Notify_THREAD_END)
|
||
{
|
||
JVMPI_Event event;
|
||
|
||
event.event_type = JVMPI_EVENT_THREAD_END;
|
||
event.env_id = _Jv_GetCurrentJNIEnv ();
|
||
|
||
_Jv_DisableGC ();
|
||
(*_Jv_JVMPI_Notify_THREAD_END) (&event);
|
||
_Jv_EnableGC ();
|
||
}
|
||
#endif
|
||
|
||
group = NULL;
|
||
|
||
// Signal any threads that are waiting to join() us.
|
||
_Jv_MutexLock (&nt->join_mutex);
|
||
alive_flag = false;
|
||
_Jv_CondNotifyAll (&nt->join_cond, &nt->join_mutex);
|
||
_Jv_MutexUnlock (&nt->join_mutex);
|
||
}
|
||
|
||
void
|
||
java::lang::Thread::run_ (jobject obj)
|
||
{
|
||
java::lang::Thread *thread = (java::lang::Thread *) obj;
|
||
try
|
||
{
|
||
#ifdef ENABLE_JVMPI
|
||
if (_Jv_JVMPI_Notify_THREAD_START)
|
||
{
|
||
JVMPI_Event event;
|
||
|
||
jstring thread_name = thread->getName ();
|
||
jstring group_name = NULL, parent_name = NULL;
|
||
java::lang::ThreadGroup *group = thread->getThreadGroup ();
|
||
|
||
if (group)
|
||
{
|
||
group_name = group->getName ();
|
||
group = group->getParent ();
|
||
|
||
if (group)
|
||
parent_name = group->getName ();
|
||
}
|
||
|
||
int thread_len = thread_name ? JvGetStringUTFLength (thread_name) : 0;
|
||
int group_len = group_name ? JvGetStringUTFLength (group_name) : 0;
|
||
int parent_len = parent_name ? JvGetStringUTFLength (parent_name) : 0;
|
||
|
||
char thread_chars[thread_len + 1];
|
||
char group_chars[group_len + 1];
|
||
char parent_chars[parent_len + 1];
|
||
|
||
if (thread_name)
|
||
JvGetStringUTFRegion (thread_name, 0,
|
||
thread_name->length(), thread_chars);
|
||
if (group_name)
|
||
JvGetStringUTFRegion (group_name, 0,
|
||
group_name->length(), group_chars);
|
||
if (parent_name)
|
||
JvGetStringUTFRegion (parent_name, 0,
|
||
parent_name->length(), parent_chars);
|
||
|
||
thread_chars[thread_len] = '\0';
|
||
group_chars[group_len] = '\0';
|
||
parent_chars[parent_len] = '\0';
|
||
|
||
event.event_type = JVMPI_EVENT_THREAD_START;
|
||
event.env_id = NULL;
|
||
event.u.thread_start.thread_name = thread_chars;
|
||
event.u.thread_start.group_name = group_chars;
|
||
event.u.thread_start.parent_name = parent_chars;
|
||
event.u.thread_start.thread_id = (jobjectID) thread;
|
||
event.u.thread_start.thread_env_id = _Jv_GetCurrentJNIEnv ();
|
||
|
||
_Jv_DisableGC ();
|
||
(*_Jv_JVMPI_Notify_THREAD_START) (&event);
|
||
_Jv_EnableGC ();
|
||
}
|
||
#endif
|
||
|
||
thread->run ();
|
||
}
|
||
catch (java::lang::Throwable *t)
|
||
{
|
||
// Uncaught exceptions are forwarded to the ThreadGroup. If
|
||
// this results in an uncaught exception, that is ignored.
|
||
try
|
||
{
|
||
thread->group->uncaughtException (thread, t);
|
||
}
|
||
catch (java::lang::Throwable *f)
|
||
{
|
||
// Nothing.
|
||
}
|
||
}
|
||
|
||
thread->finish_ ();
|
||
}
|
||
|
||
void
|
||
java::lang::Thread::start (void)
|
||
{
|
||
JvSynchronize sync (this);
|
||
|
||
// Its illegal to re-start() a thread, even if its dead.
|
||
if (!startable_flag)
|
||
_Jv_Throw (new IllegalThreadStateException);
|
||
|
||
alive_flag = true;
|
||
startable_flag = false;
|
||
natThread *nt = (natThread *) data;
|
||
_Jv_ThreadStart (this, nt->thread, (_Jv_ThreadStartFunc *) &run_);
|
||
}
|
||
|
||
void
|
||
java::lang::Thread::stop (java::lang::Throwable *)
|
||
{
|
||
_Jv_Throw (new UnsupportedOperationException
|
||
(JvNewStringLatin1 ("java::lang::Thread::stop unimplemented")));
|
||
}
|
||
|
||
void
|
||
java::lang::Thread::suspend (void)
|
||
{
|
||
checkAccess ();
|
||
_Jv_Throw (new UnsupportedOperationException
|
||
(JvNewStringLatin1 ("java::lang::Thread::suspend unimplemented")));
|
||
}
|
||
|
||
void
|
||
java::lang::Thread::yield (void)
|
||
{
|
||
_Jv_ThreadYield ();
|
||
}
|
||
|
||
JNIEnv *
|
||
_Jv_GetCurrentJNIEnv ()
|
||
{
|
||
java::lang::Thread *t = _Jv_ThreadCurrent ();
|
||
if (t == NULL)
|
||
return NULL;
|
||
return ((natThread *) t->data)->jni_env;
|
||
}
|
||
|
||
void
|
||
_Jv_SetCurrentJNIEnv (JNIEnv *env)
|
||
{
|
||
java::lang::Thread *t = _Jv_ThreadCurrent ();
|
||
JvAssert (t != NULL);
|
||
((natThread *) t->data)->jni_env = env;
|
||
}
|