123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535 |
- // natThread.cc - Native part of Thread class.
- /* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005, 2006, 2007 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 <gnu/gcj/RawDataManaged.h>
- #include <java/lang/Thread.h>
- #include <java/lang/Thread$State.h>
- #include <java/lang/Thread$UncaughtExceptionHandler.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>
- #include <jni.h>
- #ifdef INTERPRETER
- #include <jvmti.h>
- #include "jvmti-int.h"
- #endif
- #ifdef ENABLE_JVMPI
- #include <jvmpi.h>
- #endif
- 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));
-
- state = JV_NEW;
- nt->alive_flag = THREAD_DEAD;
- data = (gnu::gcj::RawDataManaged *) 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->park_helper.init();
- 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);
- #ifdef _Jv_HaveCondDestroy
- _Jv_CondDestroy (&nt->join_cond);
- #endif
- #ifdef _Jv_HaveMutexDestroy
- _Jv_MutexDestroy (&nt->join_mutex);
- #endif
- _Jv_FreeJNIEnv((JNIEnv*)nt->jni_env);
-
- nt->park_helper.destroy();
- }
- jint
- java::lang::Thread::countStackFrames (void)
- {
- // NOTE: This is deprecated in JDK 1.2.
- // Old applets still call this method. Rather than throwing
- // UnsupportedOperationException we simply fail silently.
- return 0;
- }
- java::lang::Thread *
- java::lang::Thread::currentThread (void)
- {
- return _Jv_ThreadCurrent ();
- }
- jboolean
- java::lang::Thread::holdsLock (jobject obj)
- {
- if (!obj)
- throw new NullPointerException;
- return !_Jv_ObjectCheckMonitor (obj);
- }
- jboolean
- java::lang::Thread::isAlive (void)
- {
- natThread *nt = (natThread *) data;
- return nt->alive_flag != (obj_addr_t)THREAD_DEAD;
- }
- void
- java::lang::Thread::interrupt (void)
- {
- checkAccess ();
- natThread *nt = (natThread *) data;
- // If a thread is in state ALIVE, we atomically set it to state
- // SIGNALED and send it a signal. Once we've sent it the signal, we
- // set its state back to ALIVE.
- if (compare_and_swap
- (&nt->alive_flag, Thread::THREAD_ALIVE, Thread::THREAD_SIGNALED))
- {
- _Jv_ThreadInterrupt (nt->thread);
- compare_and_swap
- (&nt->alive_flag, THREAD_SIGNALED, Thread::THREAD_ALIVE);
- // Even though we've interrupted this thread, it might still be
- // parked.
- nt->park_helper.unpark ();
- }
- }
- void
- java::lang::Thread::join (jlong millis, jint nanos)
- {
- if (millis < 0 || nanos < 0 || nanos > 999999)
- 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))
- throw new InterruptedException;
- }
- void
- java::lang::Thread::resume (void)
- {
- checkAccess ();
- // Old applets still call this method. Rather than throwing
- // UnsupportedOperationException we simply fail silently.
- }
- void
- java::lang::Thread::setPriority (jint newPriority)
- {
- checkAccess ();
- if (newPriority < MIN_PRIORITY || newPriority > MAX_PRIORITY)
- 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)
- 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))
- throw new InterruptedException;
- }
- void
- java::lang::Thread::finish_ ()
- {
- __sync_synchronize();
- natThread *nt = (natThread *) data;
-
- nt->park_helper.deactivate ();
- group->removeThread (this);
- #ifdef INTERPRETER
- if (JVMTI_REQUESTED_EVENT (ThreadEnd))
- _Jv_JVMTI_PostEvent (JVMTI_EVENT_THREAD_END, this, nt->jni_env);
- #endif
- #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
- // If a method cache was created, free it.
- _Jv_FreeMethodCache();
- // Clear out thread locals.
- locals = NULL;
- // Signal any threads that are waiting to join() us.
- _Jv_MutexLock (&nt->join_mutex);
- {
- JvSynchronize sync (this);
- nt->alive_flag = THREAD_DEAD;
- state = JV_TERMINATED;
- }
- _Jv_CondNotifyAll (&nt->join_cond, &nt->join_mutex);
- _Jv_MutexUnlock (&nt->join_mutex);
- }
- // Run once at thread startup, either when thread is attached or when
- // _Jv_ThreadRun is called.
- static void
- _Jv_NotifyThreadStart (java::lang::Thread* thread)
- {
- #ifdef INTERPRETER
- if (JVMTI_REQUESTED_EVENT (ThreadStart))
- {
- natThread *nt = reinterpret_cast<natThread *> (thread->data);
- _Jv_JVMTI_PostEvent (JVMTI_EVENT_THREAD_START, thread, nt->jni_env);
- }
- #endif
- #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
- }
- void
- _Jv_ThreadRun (java::lang::Thread* thread)
- {
- try
- {
- _Jv_NotifyThreadStart (thread);
- 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->getUncaughtExceptionHandler()->uncaughtException (thread, t);
- }
- catch (java::lang::Throwable *f)
- {
- // Nothing.
- }
- }
- thread->finish_ ();
- }
- _Jv_Thread_t*
- _Jv_ThreadGetData (java::lang::Thread* thread)
- {
- natThread* nt = (natThread*) thread->data;
- return nt->thread;
- }
- void
- java::lang::Thread::start (void)
- {
- JvSynchronize sync (this);
- // Its illegal to re-start() a thread, even if its dead.
- if (!startable_flag)
- throw new IllegalThreadStateException;
- natThread *nt = (natThread *) data;
- nt->alive_flag = THREAD_ALIVE;
- startable_flag = false;
- state = JV_RUNNABLE;
- _Jv_ThreadStart (this, nt->thread, (_Jv_ThreadStartFunc *) &_Jv_ThreadRun);
- }
- void
- java::lang::Thread::stop (java::lang::Throwable *)
- {
- checkAccess ();
- // Old applets still call this method. Rather than throwing
- // UnsupportedOperationException we simply fail silently.
- }
- void
- java::lang::Thread::suspend (void)
- {
- checkAccess ();
- // Old applets still call this method. Rather than throwing
- // UnsupportedOperationException we simply fail silently.
- }
- static int nextThreadNumber = 0;
- jstring
- java::lang::Thread::gen_name (void)
- {
- jint i;
- jclass sync = &java::lang::Thread::class$;
- {
- JvSynchronize dummy(sync);
- i = ++nextThreadNumber;
- }
- // Use an array large enough for "-2147483648"; i.e. 11 chars, + "Thread-".
- jchar buffer[7+11];
- jchar *bufend = (jchar *) ((char *) buffer + sizeof(buffer));
- i = _Jv_FormatInt (bufend, i);
- jchar *ptr = bufend - i;
- // Prepend "Thread-".
- *--ptr = '-';
- *--ptr = 'd';
- *--ptr = 'a';
- *--ptr = 'e';
- *--ptr = 'r';
- *--ptr = 'h';
- *--ptr = 'T';
- return JvNewString (ptr, bufend - ptr);
- }
- void
- java::lang::Thread::yield (void)
- {
- _Jv_ThreadYield ();
- }
- ::java::lang::Thread$State *
- java::lang::Thread::getState()
- {
- _Jv_InitClass(&::java::lang::Thread$State::class$);
- switch (state)
- {
- case JV_BLOCKED:
- return ::java::lang::Thread$State::BLOCKED;
- case JV_NEW:
- return ::java::lang::Thread$State::NEW;
- case JV_RUNNABLE:
- return ::java::lang::Thread$State::RUNNABLE;
- case JV_TERMINATED:
- return ::java::lang::Thread$State::TERMINATED;
- case JV_TIMED_WAITING:
- return ::java::lang::Thread$State::TIMED_WAITING;
- case JV_WAITING:
- return ::java::lang::Thread$State::WAITING;
- }
- // We don't really need a default, but this makes the compiler
- // happy.
- return ::java::lang::Thread$State::RUNNABLE;
- }
- 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;
- }
- // Attach the current native thread to an existing (but unstarted) Thread
- // object. Does not register thread with the garbage collector.
- // Returns -1 on failure, 0 upon success.
- jint
- _Jv_AttachCurrentThread(java::lang::Thread* thread)
- {
- JvSynchronize sync (thread);
- if (thread == NULL || thread->startable_flag == false)
- return -1;
- thread->startable_flag = false;
- natThread *nt = (natThread *) thread->data;
- nt->alive_flag = ::java::lang::Thread::THREAD_ALIVE;
- thread->state = JV_RUNNABLE;
- _Jv_ThreadRegister (nt->thread);
- return 0;
- }
- java::lang::Thread*
- _Jv_AttachCurrentThread(jstring name, java::lang::ThreadGroup* group)
- {
- // Register thread with GC before attempting any allocations.
- _Jv_GCAttachThread ();
- java::lang::Thread *thread = _Jv_ThreadCurrent ();
- if (thread != NULL)
- return thread;
- if (name == NULL)
- name = java::lang::Thread::gen_name ();
- thread = new java::lang::Thread (NULL, group, NULL, name, false);
- _Jv_AttachCurrentThread (thread);
- _Jv_NotifyThreadStart (thread);
- return thread;
- }
- java::lang::Thread*
- _Jv_AttachCurrentThreadAsDaemon(jstring name, java::lang::ThreadGroup* group)
- {
- java::lang::Thread *thread = _Jv_ThreadCurrent ();
- if (thread != NULL)
- return thread;
- if (name == NULL)
- name = java::lang::Thread::gen_name ();
- thread = new java::lang::Thread (NULL, group, NULL, name, false);
- thread->setDaemon (true);
- _Jv_AttachCurrentThread (thread);
- _Jv_NotifyThreadStart (thread);
- return thread;
- }
- jint
- _Jv_DetachCurrentThread (void)
- {
- java::lang::Thread *t = _Jv_ThreadCurrent ();
- if (t == NULL)
- return -1;
- _Jv_ThreadUnRegister ();
- _Jv_GCDetachThread ();
- // Release the monitors.
- t->finish_ ();
- return 0;
- }
|