* src/threads/posix/thread-posix.hpp: Likewise.
* src/threads/threadlist.cpp (ThreadList::dump_threads): Use above mechanism.
* src/native/vm/openjdk/jvm.cpp (JVM_SuspendThread, JVM_ResumeThread): Likewise.
* src/vm/signal.cpp (signal_handler_sigusr1): Added generic suspension handler.
* src/vm/signallocal.hpp (md_signal_handler_sigusr1): Removed prototype.
* src/vm/jit/alpha/linux/md-os.c: Removed implementation of above function.
* src/vm/jit/arm/linux/md-os.c: Likewise.
* src/vm/jit/i386/freebsd/md-os.c: Likewise.
* src/vm/jit/i386/linux/md-os.c: Likewise.
* src/vm/jit/i386/solaris/md-os.c: Likewise.
* src/vm/jit/m68k/linux/md-os.c: Likewise.
* src/vm/jit/powerpc/linux/md-os.c: Likewise.
* src/vm/jit/x86_64/linux/md-os.c: Likewise.
* src/vm/jit/x86_64/solaris/md-os.c: Likewise.
void JVM_SuspendThread(JNIEnv* env, jobject jthread)
{
- log_println("JVM_SuspendThread: Deprecated. Not implemented.");
+ java_handle_t *h;
+ threadobject *t;
+
+ TRACEJVMCALLS(("JVM_SuspendThread(env=%p, jthread=%p)", env, jthread));
+
+ if (opt_PrintWarnings)
+ log_println("JVM_SuspendThread: Deprecated, do not use!");
+
+ h = (java_handle_t *) jthread;
+ t = thread_get_thread(h);
+
+ /* The threadobject is null when a thread is created in Java. */
+
+ if (t == NULL)
+ return;
+
+ threads_suspend_thread(t, SUSPEND_REASON_JAVA);
}
void JVM_ResumeThread(JNIEnv* env, jobject jthread)
{
- log_println("JVM_ResumeThread: Deprecated. Not implemented.");
+ java_handle_t *h;
+ threadobject *t;
+
+ TRACEJVMCALLS(("JVM_ResumeThread(env=%p, jthread=%p)", env, jthread));
+
+ if (opt_PrintWarnings)
+ log_println("JVM_ResumeThread: Deprecated, do not use!");
+
+ h = (java_handle_t *) jthread;
+ t = thread_get_thread(h);
+
+ /* The threadobject is null when a thread is created in Java. */
+
+ if (t == NULL)
+ return;
+
+ threads_resume_thread(t, SUSPEND_REASON_JAVA);
}
}
-/* threads_suspend_thread ******************************************************
-
- Suspend the passed thread. Execution stops until the thread
- is explicitly resumend again.
-
- IN:
- reason.....Reason for suspending this thread.
-
-*******************************************************************************/
-
-bool threads_suspend_thread(threadobject *thread, s4 reason)
+/**
+ * Internal helper function which suspends the current thread. This is
+ * the core method of the suspension mechanism actually blocking the
+ * execution until the suspension reason is cleared again. Note that
+ * the current thread needs to hold the suspension mutex while calling
+ * this function.
+ */
+static void threads_suspend_self()
{
- /* acquire the suspendmutex */
- thread->suspendmutex->lock();
-
- if (thread->suspended) {
- thread->suspendmutex->unlock();
- return false;
- }
+ threadobject* thread = THREADOBJECT;
- /* set the reason for the suspension */
- thread->suspend_reason = reason;
+ DEBUGTHREADS("suspending", thread);
- /* send the suspend signal to the thread */
- assert(thread != THREADOBJECT);
- if (pthread_kill(thread->tid, SIGUSR1) != 0)
- vm_abort("threads_suspend_thread: pthread_kill failed: %s",
- strerror(errno));
+ // Mark thread as suspended.
+ assert(!thread->suspended);
+ assert(thread->suspend_reason != SUSPEND_REASON_NONE);
+ thread->suspended = true;
- /* REMEMBER: do not release the suspendmutex, this is done
- by the thread itself in threads_suspend_ack(). */
+ // Acknowledge the suspension.
+ thread->suspendcond->broadcast();
- return true;
-}
+#if defined(ENABLE_GC_CACAO)
+ // If we are stopping the world, we should send a global ack.
+ if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD)
+ threads_sem_post(&suspend_ack);
+#endif
+ // Release the suspension mutex and wait till we are resumed.
+ thread->suspendcond->wait(thread->suspendmutex);
-/* threads_suspend_ack *********************************************************
+#if defined(ENABLE_GC_CACAO)
+ // XXX This is propably not ok!
+ // If we are starting the world, we should send a global ack.
+ if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD)
+ threads_sem_post(&suspend_ack);
+#endif
- Acknowledges the suspension of the current thread.
+ // Mark thread as not suspended.
+ assert(thread->suspended);
+ assert(thread->suspend_reason == SUSPEND_REASON_NONE);
+ thread->suspended = false;
- IN:
- pc.....The PC where the thread suspended its execution.
- sp.....The SP before the thread suspended its execution.
+ DEBUGTHREADS("resuming", thread);
+}
-*******************************************************************************/
-#if defined(ENABLE_GC_CACAO)
-void threads_suspend_ack(u1* pc, u1* sp)
+/**
+ * Suspend the passed thread. Execution of that thread stops until the thread
+ * is explicitly resumend again.
+ *
+ * @param thread The thread to be suspended.
+ * @param reason Reason for suspending the given thread.
+ * @return True of operation was successful, false otherwise.
+ */
+bool threads_suspend_thread(threadobject *thread, int32_t reason)
{
- threadobject *thread;
-
- thread = THREADOBJECT;
+ // Sanity check.
+ assert(reason != SUSPEND_REASON_NONE);
- assert(thread->suspend_reason != 0);
+ // Guard this with the suspension mutex.
+ MutexLocker ml(*thread->suspendmutex);
- /* TODO: remember dump memory size */
-
- /* inform the GC about the suspension */
- if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD && gc_pending) {
+ // Check if thread is already suspended.
+ if (thread->suspended)
+ return false;
- /* check if the GC wants to leave the thread running */
- if (!gc_suspend(thread, pc, sp)) {
+ // Check if thread is in the process of suspending.
+ if (thread->suspend_reason != SUSPEND_REASON_NONE)
+ return false;
- /* REMEMBER: we do not unlock the suspendmutex because the thread
- will suspend itself again at a later time */
- return;
+ // Set the reason for suspending the thread.
+ thread->suspend_reason = reason;
- }
+ if (thread == THREADOBJECT) {
+ // We already hold the suspension mutex and can suspend ourselves
+ // immediately without using signals at all.
+ threads_suspend_self();
}
-
- /* mark this thread as suspended and remember the PC */
- thread->pc = pc;
- thread->suspended = true;
-
- /* if we are stopping the world, we should send a global ack */
- if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD) {
- threads_sem_post(&suspend_ack);
+ else {
+ // Send the suspend signal to the other thread.
+ if (pthread_kill(thread->tid, SIGUSR1) != 0)
+ os::abort_errno("threads_suspend_thread: pthread_kill failed");
+
+ // Wait for the thread to acknowledge the suspension.
+ // XXX A possible optimization would be to not wait here, but you
+ // better think this through twice before trying it!
+ thread->suspendcond->wait(thread->suspendmutex);
}
- DEBUGTHREADS("suspending", thread);
+ return true;
+}
- /* release the suspension mutex and wait till we are resumed */
- thread->suspendcond->wait(thread->suspendmutex);
- DEBUGTHREADS("resuming", thread);
+/**
+ * Resumes execution of the passed thread.
+ *
+ * @param thread The thread to be resumed.
+ * @param reason Reason for suspending the given thread.
+ * @return True of operation was successful, false otherwise.
+ */
+bool threads_resume_thread(threadobject *thread, int32_t reason)
+{
+ // Sanity check.
+ assert(thread != THREADOBJECT);
+ assert(reason != SUSPEND_REASON_NONE);
- /* if we are stopping the world, we should send a global ack */
- if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD) {
- threads_sem_post(&suspend_ack);
- }
+ // Guard this with the suspension mutex.
+ MutexLocker ml(*thread->suspendmutex);
- /* TODO: free dump memory */
+ // Check if thread really is suspended.
+ if (!thread->suspended)
+ return false;
- /* release the suspendmutex */
- thread->suspendmutex->unlock();
-}
-#endif
+ // Threads can only be resumed for the same reason they were suspended.
+ if (thread->suspend_reason != reason)
+ return false;
+ // Clear the reason for suspending the thread.
+ thread->suspend_reason = SUSPEND_REASON_NONE;
-/* threads_resume_thread *******************************************************
+ // Tell everyone that the thread should resume.
+ thread->suspendcond->broadcast();
- Resumes the execution of the passed thread.
+ return true;
+}
-*******************************************************************************/
-#if defined(ENABLE_GC_CACAO)
-bool threads_resume_thread(threadobject *thread)
+/**
+ * Acknowledges the suspension of the current thread.
+ */
+void threads_suspend_ack()
{
- /* acquire the suspendmutex */
- thread->suspendmutex->lock();
+ threadobject* thread = THREADOBJECT;
- if (!thread->suspended) {
- thread->suspendmutex->unlock();
- return false;
- }
-
- thread->suspended = false;
+ // Guard this with the suspension mutex.
+ MutexLocker ml(*thread->suspendmutex);
- /* tell everyone that the thread should resume */
- assert(thread != THREADOBJECT);
- thread->suspendcond->broadcast();
-
- /* release the suspendmutex */
- thread->suspendmutex->unlock();
-
- return true;
+ // Suspend ourselves while holding the suspension mutex.
+ threads_suspend_self();
}
-#endif
/* threads_join_all_threads ****************************************************
#define THREAD_FLAG_DAEMON 0x04 /* daemon thread */
#define THREAD_FLAG_IN_NATIVE 0x08 /* currently executing native code */
-#define SUSPEND_REASON_JNI 1 /* suspended from JNI */
-#define SUSPEND_REASON_STOPWORLD 2 /* suspended from stop-thw-world */
+#define SUSPEND_REASON_NONE 0 /* no reason to suspend */
+#define SUSPEND_REASON_JAVA 1 /* suspended from java.lang.Thread */
+#define SUSPEND_REASON_STOPWORLD 2 /* suspended from stop-the-world */
+#define SUSPEND_REASON_DUMP 3 /* suspended from threadlist dumping */
+#define SUSPEND_REASON_JVMTI 4 /* suspended from JVMTI agent */
typedef struct threadobject threadobject;
void threads_set_thread_priority(pthread_t tid, int priority);
-#if defined(ENABLE_GC_CACAO)
-bool threads_suspend_thread(threadobject *thread, s4 reason);
-void threads_suspend_ack(u1* pc, u1* sp);
-bool threads_resume_thread(threadobject *thread);
-#endif
+bool threads_suspend_thread(threadobject *thread, int32_t reason);
+bool threads_resume_thread(threadobject *thread, int32_t reason);
+void threads_suspend_ack();
void threads_join_all_threads(void);
*/
void ThreadList::dump_threads()
{
- // XXX we should stop the world here
+ // XXX we should stop the world here and remove explicit
+ // thread suspension from the loop below.
// Lock the thread lists.
lock();
printf("Full thread dump CACAO "VERSION":\n");
// Iterate over all started threads.
+ threadobject* self = THREADOBJECT;
for (List<threadobject*>::iterator it = _active_thread_list.begin(); it != _active_thread_list.end(); it++) {
threadobject* t = *it;
if (t->state == THREAD_STATE_NEW)
continue;
-#if defined(ENABLE_GC_CACAO)
- /* Suspend the thread. */
- /* XXX Is the suspend reason correct? */
+ /* Suspend the thread (and ignore return value). */
- if (threads_suspend_thread(t, SUSPEND_REASON_JNI) == false)
- vm_abort("threads_dump: threads_suspend_thread failed");
-#endif
+ if (t != self)
+ (void) threads_suspend_thread(t, SUSPEND_REASON_DUMP);
/* Print thread info. */
stacktrace_print_of_thread(t);
-#if defined(ENABLE_GC_CACAO)
- /* Resume the thread. */
+ /* Resume the thread (and ignore return value). */
- if (threads_resume_thread(t) == false)
- vm_abort("threads_dump: threads_resume_thread failed");
-#endif
+ if (t != self)
+ (void) threads_resume_thread(t, SUSPEND_REASON_DUMP);
}
// Unlock the thread lists.
}
-/* md_signal_handler_sigusr1 ***************************************************
-
- Signal handler for suspending threads.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
-{
- ucontext_t *_uc;
- mcontext_t *_mc;
- u1 *pc;
- u1 *sp;
-
- _uc = (ucontext_t *) _p;
- _mc = &_uc->uc_mcontext;
-
- /* get the PC and SP for this thread */
- pc = (u1 *) _mc->sc_pc;
- sp = (u1 *) _mc->sc_regs[REG_SP];
-
- /* now suspend the current thread */
- threads_suspend_ack(pc, sp);
-}
-#endif
-
-
/* md_signal_handler_sigusr2 ***************************************************
Signal handler for profiling sampling.
}
-/* md_signal_handler_sigusr1 ***************************************************
-
- Signal handler for suspending threads.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
-{
- ucontext_t *_uc;
- scontext_t *_sc;
- u1 *pc;
- u1 *sp;
-
- _uc = (ucontext_t *) _p;
- _sc = &_uc->uc_mcontext;
-
- /* get the PC and SP for this thread */
- pc = (u1 *) _sc->arm_pc;
- sp = (u1 *) _sc->arm_sp;
-
- /* now suspend the current thread */
- threads_suspend_ack(pc, sp);
-}
-#endif
-
-
/* md_signal_handler_sigusr2 ***************************************************
Signal handler for profiling sampling.
}
-/* md_signal_handler_sigusr1 ***************************************************
-
- Signal handler for suspending threads.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
-{
- ucontext_t *_uc;
- mcontext_t *_mc;
- u1 *pc;
- u1 *sp;
-
- _uc = (ucontext_t *) _p;
- _mc = &_uc->uc_mcontext;
-
- /* get the PC and SP for this thread */
- pc = (u1 *) _mc->mc_eip;
- sp = (u1 *) _mc->mc_esp;
-
- /* now suspend the current thread */
- threads_suspend_ack(pc, sp);
-}
-#endif
-
-
/* md_signal_handler_sigusr2 ***************************************************
Signal handler for profiling sampling.
}
-/* md_signal_handler_sigusr1 ***************************************************
-
- Signal handler for suspending threads.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
-{
- ucontext_t *_uc;
- mcontext_t *_mc;
- u1 *pc;
- u1 *sp;
-
- _uc = (ucontext_t *) _p;
- _mc = &_uc->uc_mcontext;
-
- /* get the PC and SP for this thread */
- pc = (u1 *) _mc->gregs[REG_EIP];
- sp = (u1 *) _mc->gregs[REG_ESP];
-
- /* now suspend the current thread */
- threads_suspend_ack(pc, sp);
-}
-#endif
-
-
/* md_signal_handler_sigusr2 ***************************************************
Signal handler for profiling sampling.
}
-/* md_signal_handler_sigusr1 ***************************************************
-
- Signal handler for suspending threads.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
-{
- ucontext_t *_uc;
- mcontext_t *_mc;
- u1 *pc;
- u1 *sp;
-
- _uc = (ucontext_t *) _p;
- _mc = &_uc->uc_mcontext;
-
- /* get the PC and SP for this thread */
- pc = (u1 *) _mc->gregs[EIP];
- sp = (u1 *) _mc->gregs[UESP];
-
- /* now suspend the current thread */
- threads_suspend_ack(pc, sp);
-}
-#endif
-
-
/* md_signal_handler_sigusr2 ***************************************************
Signal handler for profiling sampling.
}
-/* md_signal_handler_sigusr1 ***************************************************
-
- Signal handler for suspending threads.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
-{
- ucontext_t *_uc;
- mcontext_t *_mc;
- u1 *pc;
- u1 *sp;
-
- _uc = (ucontext_t *) _p;
- _mc = &_uc->uc_mcontext;
-
- /* get the PC and SP for this thread */
- pc = (u1 *) _mc->gregs[R_PC];
- sp = (u1 *) _mc->gregs[R_SP];
-
- /* now suspend the current thread */
- threads_suspend_ack(pc, sp);
-}
-#endif
-
-
/*
* These are local overrides for various environment variables in Emacs.
* Please do not remove this and leave it at the end of the file, where
}
-/* md_signal_handler_sigusr1 ***************************************************
-
- Signal handler for suspending threads.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
-{
- ucontext_t *_uc;
- mcontext_t *_mc;
- unsigned long *_gregs;
- u1 *pc;
- u1 *sp;
-
- _uc = (ucontext_t *) _p;
-
-#if defined(__UCLIBC__)
- _mc = &(_uc->uc_mcontext);
- _gregs = _mc->regs->gpr;
-#else
- _mc = _uc->uc_mcontext.uc_regs;
- _gregs = _mc->gregs;
-#endif
-
- /* get the PC and SP for this thread */
-
- pc = (u1 *) _gregs[PT_NIP];
- sp = (u1 *) _gregs[REG_SP];
-
- /* now suspend the current thread */
-
- threads_suspend_ack(pc, sp);
-}
-#endif
-
-
/* md_signal_handler_sigusr2 ***************************************************
Signal handler for profiling sampling.
}
-/* md_signal_handler_sigusr1 ***************************************************
-
- Signal handler for suspending threads.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
-{
- ucontext_t *_uc;
- mcontext_t *_mc;
- u1 *pc;
- u1 *sp;
-
- _uc = (ucontext_t *) _p;
- _mc = &_uc->uc_mcontext;
-
- /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
- different to the ones in <ucontext.h>. */
-
- /* get the PC and SP for this thread */
- pc = (u1 *) _mc->gregs[REG_RIP];
- sp = (u1 *) _mc->gregs[REG_RSP];
-
- /* now suspend the current thread */
- threads_suspend_ack(pc, sp);
-}
-#endif
-
-
/* md_signal_handler_sigusr2 ***************************************************
Signal handler for profiling sampling.
}
-/* md_signal_handler_sigusr1 ***************************************************
-
- Signal handler for suspending threads.
-
-*******************************************************************************/
-
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
-void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
-{
- ucontext_t *_uc;
- mcontext_t *_mc;
- u1 *pc;
- u1 *sp;
-
- _uc = (ucontext_t *) _p;
- _mc = &_uc->uc_mcontext;
-
- /* ATTENTION: Don't use CACAO's internal REG_* defines as they are
- different to the ones in <ucontext.h>. */
-
- /* get the PC and SP for this thread */
- pc = (u1 *) _mc->gregs[REG_RIP];
- sp = (u1 *) _mc->gregs[REG_RSP];
-
- /* now suspend the current thread */
- threads_suspend_ack(pc, sp);
-}
-#endif
-
-
/* md_signal_handler_sigusr2 ***************************************************
Signal handler for profiling sampling.
/* function prototypes ********************************************************/
void signal_handler_sighup(int sig, siginfo_t *siginfo, void *_p);
+void signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p);
/* signal_init *****************************************************************
signal_register_signal(Signal_INTERRUPT_SYSTEM_CALL, (functionptr) signal_handler_sighup, 0);
#endif
-#if defined(ENABLE_THREADS) && defined(ENABLE_GC_CACAO)
- /* SIGUSR1 handler for the exact GC to suspend threads */
+#if defined(ENABLE_THREADS)
+ /* SIGUSR1 handler for thread suspension */
- signal_register_signal(SIGUSR1, (functionptr) md_signal_handler_sigusr1,
+ signal_register_signal(SIGUSR1, (functionptr) signal_handler_sigusr1,
SA_SIGINFO);
#endif
#endif
+/* signal_handler_sigusr1 ******************************************************
+
+ Signal handler for suspending threads.
+
+*******************************************************************************/
+
+#if defined(ENABLE_THREADS)
+void signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p)
+{
+ // Really suspend ourselves by acknowledging the suspension.
+ threads_suspend_ack();
+}
+#endif
+
+
/*
* These are local overrides for various environment variables in Emacs.
* Please do not remove this and leave it at the end of the file, where
void md_signal_handler_sigtrap(int sig, siginfo_t *siginfo, void *_p);
#endif
-void md_signal_handler_sigusr1(int sig, siginfo_t *siginfo, void *_p);
-
void md_signal_handler_sigusr2(int sig, siginfo_t *siginfo, void *_p);
#ifdef __cplusplus