diff options
author | tromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-04-07 14:42:40 +0000 |
---|---|---|
committer | tromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4> | 1999-04-07 14:42:40 +0000 |
commit | 2c60951ba0efef23e2b765964b5dc0f1f49438a9 (patch) | |
tree | d96801a16fdf03a5682ef98730fe333a46eef944 /libjava/java/lang/natThread.cc | |
parent | 1135eed2207f8f82c589e42ce113a1c2f0310778 (diff) | |
download | gcc-2c60951ba0efef23e2b765964b5dc0f1f49438a9.tar.gz |
Initial revision
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@26263 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava/java/lang/natThread.cc')
-rw-r--r-- | libjava/java/lang/natThread.cc | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/libjava/java/lang/natThread.cc b/libjava/java/lang/natThread.cc new file mode 100644 index 00000000000..117191133a8 --- /dev/null +++ b/libjava/java/lang/natThread.cc @@ -0,0 +1,295 @@ +// natThread.cc - Native part of Thread class. + +/* Copyright (C) 1998, 1999 Cygnus Solutions + + 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 <cni.h> +#include <jvm.h> +#include <java/lang/Thread.h> +#include <java/lang/ThreadGroup.h> +#include <java/lang/IllegalArgumentException.h> +#include <java/lang/IllegalThreadStateException.h> +#include <java/lang/InterruptedException.h> +#include <java/lang/NullPointerException.h> + + + +// 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 this thread can either be sleeping + // or waiting for a thread exit, but not both. + _Jv_Mutex_t interrupt_mutex; + _Jv_ConditionVariable_t interrupt_cond; + + // This is private data for the thread system layer. + _Jv_Thread_t *thread; + + // All threads waiting to join this thread are linked together and + // waiting on their respective `interrupt' condition variables. + // When this thread exits, it notifies each such thread by + // signalling the condition. In this case the `interrupt_flag' is + // not set; this is how the waiting thread knows whether the join + // has failed or whether it should throw an exception. + struct natThread *joiner; + + // Chain for waiters. + struct natThread *next; +}; + +// This is called from the constructor to initialize the native side +// of the Thread. +void +java::lang::Thread::initialize_native (void) +{ + // FIXME: this must interact with the GC in some logical way. At + // the very least we must register a finalizer to clean up. This + // isn't easy to do. If the Thread object resurrects itself in its + // own finalizer then we will need to reinitialize this structure at + // any "interesting" point. + natThread *nt = (natThread *) _Jv_AllocBytes (sizeof (natThread)); + data = (jobject) nt; + _Jv_MutexInit (&nt->interrupt_mutex); + _Jv_CondInit (&nt->interrupt_cond); + _Jv_ThreadInitData (&nt->thread, this); + nt->joiner = 0; + nt->next = 0; +} + +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 (); +} + +// FIXME: this is apparently the only way a thread can be removed from +// a ThreadGroup. That seems wrong. +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::dumpStack (void) +{ + // We don't implement this because it is very hard. Once we have a + // VM, this could potentially ask the VM to do the dump in cases + // where it makes sense. + JvFail ("java::lang::Thread::dumpStack unimplemented"); +} + +void +java::lang::Thread::interrupt (void) +{ + interrupt_flag = true; + + // Wake up this thread, whether it is sleeping or waiting for + // another thread to exit. + natThread *nt = (natThread *) data; + _Jv_MutexLock (&nt->interrupt_mutex); + _Jv_CondNotify (&nt->interrupt_cond, &nt->interrupt_mutex); + _Jv_MutexUnlock (&nt->interrupt_mutex); + + _Jv_ThreadInterrupt (nt->thread); +} + +void +java::lang::Thread::join (jlong millis, jint nanos) +{ + // FIXME: what if we are trying to join ourselves with no timeout? + + if (millis < 0 || nanos < 0 || nanos > 999999) + _Jv_Throw (new IllegalArgumentException); + + Thread *current = currentThread (); + if (current->isInterrupted ()) + _Jv_Throw (new InterruptedException); + + // Update the list of all threads waiting for this thread to exit. + // We grab a mutex when doing this in order to ensure that the + // required state changes are atomic. + _Jv_MonitorEnter (this); + if (! isAlive ()) + { + _Jv_MonitorExit (this); + return; + } + + // Here `CURR_NT' is the native structure for the currently + // executing thread, while `NT' is the native structure for the + // thread we are trying to join. + natThread *curr_nt = (natThread *) current->data; + natThread *nt = (natThread *) data; + + JvAssert (curr_nt->next == NULL); + // Put thread CURR_NT onto NT's list. When NT exits, it will + // traverse its list and notify all joiners. + curr_nt->next = nt->joiner; + nt->joiner = curr_nt; + _Jv_MonitorExit (this); + + + // Now wait for: (1) an interrupt, (2) the thread to exit, or (3) + // the timeout to occur. + _Jv_MutexLock (&curr_nt->interrupt_mutex); + _Jv_CondWait (&curr_nt->interrupt_cond, + &curr_nt->interrupt_mutex, + millis, nanos); + _Jv_MutexUnlock (&curr_nt->interrupt_mutex); + + // Now the join has completed, one way or another. Update the + // joiners list to account for this. + _Jv_MonitorEnter (this); + JvAssert (nt->joiner != NULL); + natThread *prev = 0; + natThread *t; + for (t = nt->joiner; t != NULL; t = t->next) + { + if (t == curr_nt) + { + if (prev) + prev->next = t->next; + else + nt->joiner = t->next; + t->next = 0; + break; + } + } + JvAssert (t != NULL); + _Jv_MonitorExit (this); + + if (current->isInterrupted ()) + _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); + + Thread *current = currentThread (); + if (current->isInterrupted ()) + _Jv_Throw (new InterruptedException); + + // We use a condition variable to implement sleeping so that an + // interrupt can wake us up. + natThread *nt = (natThread *) current->data; + _Jv_MutexLock (&nt->interrupt_mutex); + _Jv_CondWait (&nt->interrupt_cond, &nt->interrupt_mutex, + millis, nanos); + _Jv_MutexUnlock (&nt->interrupt_mutex); + + if (current->isInterrupted ()) + _Jv_Throw (new InterruptedException); +} + +void +java::lang::Thread::finish_ (void) +{ + // Notify all threads waiting to join this thread. + _Jv_MonitorEnter (this); + alive_flag = false; + + // Note that we don't bother cleaning up the joiner list here. That + // is taken care of when each thread wakes up again. + natThread *nt = (natThread *) data; + for (natThread *t = nt->joiner; t != NULL; t = t->next) + { + _Jv_MutexLock (&t->interrupt_mutex); + _Jv_CondNotify (&t->interrupt_cond, &t->interrupt_mutex); + _Jv_MutexUnlock (&t->interrupt_mutex); + } + + _Jv_MonitorExit (this); +} + +void +java::lang::Thread::run__ (jobject obj) +{ + java::lang::Thread *thread = (java::lang::Thread *) obj; + thread->run_ (); +} + +void +java::lang::Thread::start (void) +{ + JvSynchronize sync (this); + + if (alive_flag) + _Jv_Throw (new IllegalThreadStateException); + + alive_flag = true; + natThread *nt = (natThread *) data; + _Jv_ThreadStart (this, nt->thread, (_Jv_ThreadStartFunc *) &run__); +} + +void +java::lang::Thread::stop (java::lang::Throwable *e) +{ + JvSynchronize sync (this); + checkAccess (); + if (! e) + _Jv_Throw (new NullPointerException); + natThread *nt = (natThread *) data; + _Jv_ThreadCancel (nt->thread, e); +} + +void +java::lang::Thread::suspend (void) +{ + checkAccess (); + JvFail ("java::lang::Thread::suspend unimplemented"); +} + +void +java::lang::Thread::yield (void) +{ + _Jv_ThreadYield (); +} |