X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fthreads%2Fthreads-common.c;h=89515056c98594f327eee75f526386e795cb11c2;hb=9f859ad50d3d5d98c185d40b86b2179bc4dc9aeb;hp=2054294b6a928e305b060269732a2465ae388afd;hpb=acd723494c2e56082393feb2637881897612c211;p=cacao.git diff --git a/src/threads/threads-common.c b/src/threads/threads-common.c index 2054294b6..89515056c 100644 --- a/src/threads/threads-common.c +++ b/src/threads/threads-common.c @@ -22,15 +22,21 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - $Id: signal.c 7246 2007-01-29 18:49:05Z twisti $ - */ #include "config.h" + +#include +#include +#include + #include "vm/types.h" +#include "mm/memory.h" + #include "native/jni.h" +#include "native/llni.h" #include "native/include/java_lang_Object.h" #include "native/include/java_lang_String.h" @@ -40,9 +46,11 @@ # include "native/include/java_lang_VMThread.h" #endif +#include "threads/critical.h" +#include "threads/lock-common.h" #include "threads/threads-common.h" -#include "threads/native/threads.h" +#include "toolbox/list.h" #include "vm/builtin.h" #include "vm/stringlocal.h" @@ -51,65 +59,529 @@ #include "vm/jit/stacktrace.h" #include "vmcore/class.h" + +#if defined(ENABLE_STATISTICS) +# include "vmcore/options.h" +# include "vmcore/statistics.h" +#endif + #include "vmcore/utf8.h" -/* threads_create_thread ******************************************************* +/* global variables ***********************************************************/ + +/* global threads list */ +static list_t *list_threads; + +/* global threads free-list */ +static list_t *list_threads_free; + +#if defined(__LINUX__) +/* XXX Remove for exact-GC. */ +bool threads_pthreads_implementation_nptl; +#endif + + +/* threads_preinit ************************************************************* + + Do some early initialization of stuff required. + + ATTENTION: Do NOT use any Java heap allocation here, as gc_init() + is called AFTER this function! + +*******************************************************************************/ + +void threads_preinit(void) +{ + threadobject *mainthread; +#if defined(__LINUX__) && defined(_CS_GNU_LIBPTHREAD_VERSION) + char *pathbuf; + size_t len; +#endif + +#if defined(__LINUX__) + /* XXX Remove for exact-GC. */ + + /* On Linux we need to check the pthread implementation. */ + + /* _CS_GNU_LIBPTHREAD_VERSION (GNU C library only; since glibc 2.3.2) */ + /* If the glibc is a pre-2.3.2 version, we fall back to + linuxthreads. */ + +# if defined(_CS_GNU_LIBPTHREAD_VERSION) + len = confstr(_CS_GNU_LIBPTHREAD_VERSION, NULL, (size_t) 0); + + /* Some systems return as length 0 (maybe cross-compilation + related). In this case we also fall back to linuxthreads. */ + + if (len > 0) { + pathbuf = MNEW(char, len); + + (void) confstr(_CS_GNU_LIBPTHREAD_VERSION, pathbuf, len); + + if (strstr(pathbuf, "NPTL") != NULL) + threads_pthreads_implementation_nptl = true; + else + threads_pthreads_implementation_nptl = false; + } + else + threads_pthreads_implementation_nptl = false; +# else + threads_pthreads_implementation_nptl = false; +# endif +#endif + + /* initialize the threads lists */ + + list_threads = list_create(OFFSET(threadobject, linkage)); + list_threads_free = list_create(OFFSET(threadobject, linkage)); + + /* Initialize the threads implementation (sets the thinlock on the + main thread). */ + + threads_impl_preinit(); + + /* create internal thread data-structure for the main thread */ + + mainthread = threads_thread_new(); + + /* thread is a Java thread and running */ + + mainthread->flags = THREAD_FLAG_JAVA; + mainthread->state = THREAD_STATE_RUNNABLE; - Creates a thread object with the given name. + /* store the internal thread data-structure in the TSD */ + + threads_set_current_threadobject(mainthread); + + /* initialize locking subsystems */ + + lock_init(); + + /* initialize the critical section */ + + critical_init(); +} + + +/* threads_list_first ********************************************************** + + Return the first entry in the threads list. + + NOTE: This function does not lock the lists. + +*******************************************************************************/ + +threadobject *threads_list_first(void) +{ + threadobject *t; + + t = list_first_unsynced(list_threads); + + return t; +} + + +/* threads_list_next *********************************************************** + + Return the next entry in the threads list. + + NOTE: This function does not lock the lists. *******************************************************************************/ -threadobject *threads_create_thread(utf *name) +threadobject *threads_list_next(threadobject *t) { - threadobject *thread; - java_lang_Thread *t; + threadobject *next; + + next = list_next_unsynced(list_threads, t); + + return next; +} + + +/* threads_list_get_non_daemons ************************************************ + + Return the number of non-daemon threads. + + NOTE: This function does a linear-search over the threads list, + because it's only used for joining the threads. + +*******************************************************************************/ + +s4 threads_list_get_non_daemons(void) +{ + threadobject *t; + s4 nondaemons; + + /* lock the threads lists */ + + threads_list_lock(); + + nondaemons = 0; + + for (t = threads_list_first(); t != NULL; t = threads_list_next(t)) { + if (!(t->flags & THREAD_FLAG_DAEMON)) + nondaemons++; + } + + /* unlock the threads lists */ + + threads_list_unlock(); + + return nondaemons; +} + + +/* threads_thread_new ********************************************************** + + Allocates and initializes an internal thread data-structure and + adds it to the threads list. + +*******************************************************************************/ + +threadobject *threads_thread_new(void) +{ + threadobject *t; + + /* lock the threads-lists */ + + threads_list_lock(); + + /* try to get a thread from the free-list */ + + t = list_first_unsynced(list_threads_free); + + /* is a free thread available? */ + + if (t != NULL) { + /* yes, remove it from the free list */ + + list_remove_unsynced(list_threads_free, t); + } + else { + /* no, allocate a new one */ + +#if defined(ENABLE_GC_BOEHM) + t = GCNEW_UNCOLLECTABLE(threadobject, 1); +#else + t = NEW(threadobject); +#endif + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + size_threadobject += sizeof(threadobject); +#endif + + /* clear memory */ + + MZERO(t, threadobject, 1); + + /* set the threads-index */ + + t->index = list_threads->size + 1; + } + + /* pre-compute the thinlock-word */ + + assert(t->index != 0); + + t->thinlock = lock_pre_compute_thinlock(t->index); + t->state = THREAD_STATE_NEW; + + /* initialize the implementation-specific bits */ + + threads_impl_thread_new(t); + + /* add the thread to the threads-list */ + + list_add_last_unsynced(list_threads, t); + + /* unlock the threads-lists */ + + threads_list_unlock(); + + return t; +} + + +/* threads_thread_free ********************************************************* + + Frees an internal thread data-structure by removing it from the + threads-list and adding it to the free-list. + + NOTE: The data-structure is NOT freed, the pointer keeps valid! + +*******************************************************************************/ + +void threads_thread_free(threadobject *t) +{ + int32_t index; + uint32_t state; + + /* lock the threads-lists */ + + threads_list_lock(); + + /* cleanup the implementation-specific bits */ + + threads_impl_thread_free(t); + + /* remove the thread from the threads-list */ + + list_remove_unsynced(list_threads, t); + + /* Clear memory, but keep the thread-index and the + thread-state. */ + + /* ATTENTION: Do this after list_remove, otherwise the linkage + pointers are invalid. */ + + index = t->index; + state = t->state; + + MZERO(t, threadobject, 1); + + t->index = index; + t->state = state; + + /* add the thread to the free list */ + + list_add_first_unsynced(list_threads_free, t); + + /* unlock the threads-lists */ + + threads_list_unlock(); +} + + +/* threads_thread_start_internal *********************************************** + + Start an internal thread in the JVM. No Java thread objects exists + so far. + + IN: + name.......UTF-8 name of the thread + f..........function pointer to C function to start + +*******************************************************************************/ + +bool threads_thread_start_internal(utf *name, functionptr f) +{ + threadobject *t; + java_lang_Thread *object; #if defined(WITH_CLASSPATH_GNU) java_lang_VMThread *vmt; #endif - /* create the vm internal thread object */ + /* Enter the join-mutex, so if the main-thread is currently + waiting to join all threads, the number of non-daemon threads + is correct. */ - thread = NEW(threadobject); + threads_mutex_join_lock(); - if (thread == NULL) - return NULL; + /* create internal thread data-structure */ + + t = threads_thread_new(); + + t->flags = THREAD_FLAG_INTERNAL | THREAD_FLAG_DAEMON; + + /* The thread is flagged as (non-)daemon thread, we can leave the + mutex. */ + + threads_mutex_join_unlock(); /* create the java thread object */ - t = (java_lang_Thread *) builtin_new(class_java_lang_Thread); + object = (java_lang_Thread *) builtin_new(class_java_lang_Thread); - if (t == NULL) - return NULL; + /* XXX memory leak!!! */ + if (object == NULL) + return false; #if defined(WITH_CLASSPATH_GNU) vmt = (java_lang_VMThread *) builtin_new(class_java_lang_VMThread); + /* XXX memory leak!!! */ if (vmt == NULL) - return NULL; + return false; - vmt->thread = t; - vmt->vmdata = (java_lang_Object *) thread; + LLNI_field_set_ref(vmt, thread, object); + LLNI_field_set_val(vmt, vmdata, (java_lang_Object *) t); - t->vmThread = vmt; + LLNI_field_set_ref(object, vmThread, vmt); #elif defined(WITH_CLASSPATH_CLDC1_1) - t->vm_thread = (java_lang_Object *) thread; + LLNI_field_set_val(object, vm_thread, (java_lang_Object *) t); #endif - thread->object = t; - thread->flags = THREAD_FLAG_DAEMON; + t->object = object; /* set java.lang.Thread fields */ - t->name = (java_lang_String *) javastring_new(name); +#if defined(WITH_CLASSPATH_GNU) + LLNI_field_set_ref(object, name , (java_lang_String *) javastring_new(name)); +#elif defined(WITH_CLASSPATH_CLDC1_1) + /* FIXME: In cldc the name is a char[] */ +/* LLNI_field_set_ref(object, name , (java_chararray *) javastring_new(name)); */ + LLNI_field_set_ref(object, name , NULL); +#endif + +#if defined(ENABLE_JAVASE) + LLNI_field_set_val(object, daemon , true); +#endif + + LLNI_field_set_val(object, priority, NORM_PRIORITY); + + /* start the thread */ + + threads_impl_thread_start(t, f); + + /* everything's ok */ + + return true; +} + + +/* threads_thread_start ******************************************************** + + Start a Java thread in the JVM. Only the java thread object exists + so far. + + IN: + object.....the java thread object java.lang.Thread + +*******************************************************************************/ + +void threads_thread_start(java_lang_Thread *object) +{ + threadobject *thread; +#if defined(WITH_CLASSPATH_GNU) + java_lang_VMThread *vmt; +#endif + + /* Enter the join-mutex, so if the main-thread is currently + waiting to join all threads, the number of non-daemon threads + is correct. */ + + threads_mutex_join_lock(); + + /* create internal thread data-structure */ + + thread = threads_thread_new(); + + /* this is a normal Java thread */ + + thread->flags = THREAD_FLAG_JAVA; + #if defined(ENABLE_JAVASE) - t->daemon = true; + /* is this a daemon thread? */ + + if (LLNI_field_direct(object, daemon) == true) + thread->flags |= THREAD_FLAG_DAEMON; +#endif + + /* The thread is flagged and (non-)daemon thread, we can leave the + mutex. */ + + threads_mutex_join_unlock(); + + /* link the two objects together */ + + thread->object = object; + +#if defined(WITH_CLASSPATH_GNU) + LLNI_field_get_ref(object, vmThread, vmt); + + assert(vmt); + assert(LLNI_field_direct(vmt, vmdata) == NULL); + + LLNI_field_set_val(vmt, vmdata, (java_lang_Object *) thread); +#elif defined(WITH_CLASSPATH_CLDC1_1) + LLNI_field_set_val(object, vm_thread, (java_lang_Object *) thread); +#endif + + /* Start the thread. Don't pass a function pointer (NULL) since + we want Thread.run()V here. */ + + threads_impl_thread_start(thread, NULL); +} + + +/* threads_thread_print_info *************************************************** + + Print information of the passed thread. + +*******************************************************************************/ + +void threads_thread_print_info(threadobject *t) +{ + java_lang_Thread *object; + utf *name; + + assert(t->state != THREAD_STATE_NEW); + + /* the thread may be currently in initalization, don't print it */ + + object = t->object; + + if (object != NULL) { + /* get thread name */ + +#if defined(WITH_CLASSPATH_GNU) + name = javastring_toutf((java_handle_t *) LLNI_field_direct(object, name), false); +#elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1) + /* FIXME: In cldc the name is a char[] */ +/* name = object->name; */ + name = utf_null; +#else +# error unknown classpath configuration #endif - t->priority = NORM_PRIORITY; - /* return the thread object */ + printf("\""); + utf_display_printable_ascii(name); + printf("\""); + + if (t->flags & THREAD_FLAG_DAEMON) + printf(" daemon"); + + printf(" prio=%d", LLNI_field_direct(object, priority)); - return thread; +#if SIZEOF_VOID_P == 8 + printf(" t=0x%016lx tid=0x%016lx (%ld)", + (ptrint) t, (ptrint) t->tid, (ptrint) t->tid); +#else + printf(" t=0x%08x tid=0x%08x (%d)", + (ptrint) t, (ptrint) t->tid, (ptrint) t->tid); +#endif + + printf(" index=%d", t->index); + + /* print thread state */ + + switch (t->state) { + case THREAD_STATE_NEW: + printf(" new"); + break; + case THREAD_STATE_RUNNABLE: + printf(" runnable"); + break; + case THREAD_STATE_BLOCKED: + printf(" blocked"); + break; + case THREAD_STATE_WAITING: + printf(" waiting"); + break; + case THREAD_STATE_TIMED_WAITING: + printf(" waiting on condition"); + break; + case THREAD_STATE_TERMINATED: + printf(" terminated"); + break; + default: + vm_abort("threads_thread_print_info: unknown thread state %d", + t->state); + } + } } @@ -137,17 +609,91 @@ ptrint threads_get_current_tid(void) } +/* threads_thread_state_runnable *********************************************** + + Set the current state of the given thread to THREAD_STATE_RUNNABLE. + +*******************************************************************************/ + +void threads_thread_state_runnable(threadobject *t) +{ + /* set the state inside the lock */ + + threads_list_lock(); + + t->state = THREAD_STATE_RUNNABLE; + + threads_list_unlock(); +} + + +/* threads_thread_state_waiting ************************************************ + + Set the current state of the given thread to THREAD_STATE_WAITING. + +*******************************************************************************/ + +void threads_thread_state_waiting(threadobject *t) +{ + /* set the state in the lock */ + + threads_list_lock(); + + t->state = THREAD_STATE_WAITING; + + threads_list_unlock(); +} + + +/* threads_thread_state_timed_waiting ****************************************** + + Set the current state of the given thread to + THREAD_STATE_TIMED_WAITING. + +*******************************************************************************/ + +void threads_thread_state_timed_waiting(threadobject *t) +{ + /* set the state in the lock */ + + threads_list_lock(); + + t->state = THREAD_STATE_TIMED_WAITING; + + threads_list_unlock(); +} + + +/* threads_thread_state_terminated ********************************************* + + Set the current state of the given thread to + THREAD_STATE_TERMINATED. + +*******************************************************************************/ + +void threads_thread_state_terminated(threadobject *t) +{ + /* set the state in the lock */ + + threads_list_lock(); + + t->state = THREAD_STATE_TERMINATED; + + threads_list_unlock(); +} + + /* threads_thread_get_state **************************************************** Returns the current state of the given thread. *******************************************************************************/ -utf *threads_thread_get_state(threadobject *thread) +utf *threads_thread_get_state(threadobject *t) { utf *u; - switch (thread->state) { + switch (t->state) { case THREAD_STATE_NEW: u = utf_new_char("NEW"); break; @@ -167,7 +713,11 @@ utf *threads_thread_get_state(threadobject *thread) u = utf_new_char("TERMINATED"); break; default: - vm_abort("threads_get_state: unknown thread state %d", thread->state); + vm_abort("threads_get_state: unknown thread state %d", t->state); + + /* keep compiler happy */ + + u = NULL; } return u; @@ -199,6 +749,10 @@ bool threads_thread_is_alive(threadobject *thread) default: vm_abort("threads_is_alive: unknown thread state %d", thread->state); + + /* keep compiler happy */ + + result = false; } return result; @@ -214,94 +768,43 @@ bool threads_thread_is_alive(threadobject *thread) void threads_dump(void) { - threadobject *thread; - java_lang_Thread *t; - utf *name; - - thread = mainthreadobj; + threadobject *t; /* XXX we should stop the world here */ - printf("Full thread dump CACAO "VERSION":\n"); + /* lock the threads lists */ - /* iterate over all started threads */ - - do { - /* get thread object */ - - t = thread->object; + threads_list_lock(); - /* the thread may be currently in initalization, don't print it */ - - if (t != NULL) { - /* get thread name */ + printf("Full thread dump CACAO "VERSION":\n"); -#if defined(ENABLE_JAVASE) - name = javastring_toutf((java_objectheader *) t->name, false); -#elif defined(ENABLE_JAVAME_CLDC1_1) - name = t->name; -#endif + /* iterate over all started threads */ - printf("\n\""); - utf_display_printable_ascii(name); - printf("\""); + for (t = threads_list_first(); t != NULL; t = threads_list_next(t)) { + /* print thread info */ - if (thread->flags & THREAD_FLAG_DAEMON) - printf(" daemon"); + printf("\n"); + threads_thread_print_info(t); + printf("\n"); - printf(" prio=%d", t->priority); + /* print trace of thread */ -#if SIZEOF_VOID_P == 8 - printf(" tid=0x%016lx", (ptrint) thread->tid); -#else - printf(" tid=0x%08lx", (ptrint) thread->tid); -#endif + threads_thread_print_stacktrace(t); + } - /* print thread state */ - - switch (thread->state) { - case THREAD_STATE_NEW: - printf(" new"); - break; - case THREAD_STATE_RUNNABLE: - printf(" runnable"); - break; - case THREAD_STATE_BLOCKED: - printf(" blocked"); - break; - case THREAD_STATE_WAITING: - printf(" waiting"); - break; - case THREAD_STATE_TIMED_WAITING: - printf(" waiting on condition"); - break; - case THREAD_STATE_TERMINATED: - printf(" terminated"); - break; - default: - vm_abort("threads_dump: unknown thread state %d", - thread->state); - } - - printf("\n"); - - /* print trace of thread */ - - threads_print_stacktrace(thread); - } + /* unlock the threads lists */ - thread = thread->next; - } while ((thread != NULL) && (thread != mainthreadobj)); + threads_list_unlock(); } -/* threads_print_stacktrace **************************************************** +/* threads_thread_print_stacktrace ********************************************* - Print the current stacktrace of the given thread. + Print the current stacktrace of the current thread. *******************************************************************************/ -void threads_print_stacktrace(threadobject *thread) +void threads_thread_print_stacktrace(threadobject *thread) { stackframeinfo *sfi; stacktracebuffer *stb; @@ -330,6 +833,22 @@ void threads_print_stacktrace(threadobject *thread) } +/* threads_print_stacktrace **************************************************** + + Print the current stacktrace of the current thread. + +*******************************************************************************/ + +void threads_print_stacktrace(void) +{ + threadobject *thread; + + thread = THREADOBJECT; + + threads_thread_print_stacktrace(thread); +} + + /* * 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