summaryrefslogtreecommitdiff
path: root/libjava/java/lang/natThread.cc
diff options
context:
space:
mode:
authortromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4>1999-04-07 14:42:40 +0000
committertromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4>1999-04-07 14:42:40 +0000
commit2c60951ba0efef23e2b765964b5dc0f1f49438a9 (patch)
treed96801a16fdf03a5682ef98730fe333a46eef944 /libjava/java/lang/natThread.cc
parent1135eed2207f8f82c589e42ce113a1c2f0310778 (diff)
downloadgcc-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.cc295
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 ();
+}