1 /* src/threads/threads-common.c - machine independent thread functions
3 Copyright (C) 2007 R. Grafl, A. Krall, C. Kruegel,
4 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6 J. Wenninger, Institut f. Computersprachen - TU Wien
8 This file is part of CACAO.
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License as
12 published by the Free Software Foundation; either version 2, or (at
13 your option) any later version.
15 This program is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 $Id: threads-common.c 7831 2007-04-26 12:48:16Z twisti $
36 #include "native/jni.h"
38 #include "native/include/java_lang_Object.h"
39 #include "native/include/java_lang_String.h"
40 #include "native/include/java_lang_Thread.h"
42 #if defined(WITH_CLASSPATH_GNU)
43 # include "native/include/java_lang_VMThread.h"
46 #include "threads/critical.h"
47 #include "threads/lock-common.h"
48 #include "threads/threads-common.h"
50 #include "vm/builtin.h"
51 #include "vm/stringlocal.h"
54 #include "vm/jit/stacktrace.h"
56 #include "vmcore/class.h"
58 #if defined(ENABLE_STATISTICS)
59 # include "vmcore/options.h"
60 # include "vmcore/statistics.h"
63 #include "vmcore/utf8.h"
66 /* global variables ***********************************************************/
68 /* global threads table */
69 static threads_table_t threads_table;
72 /* prototypes *****************************************************************/
74 static void threads_table_init(void);
76 #if !defined(NDEBUG) && 0
77 static void threads_table_dump(FILE *file);
81 /* threads_preinit *************************************************************
83 Do some early initialization of stuff required.
85 ATTENTION: Do NOT use any Java heap allocation here, as gc_init()
86 is called AFTER this function!
88 *******************************************************************************/
90 void threads_preinit(void)
92 /* initialize the threads implementation */
94 threads_impl_preinit();
96 /* initialize the threads table */
100 /* initialize subsystems */
108 /* threads_table_init **********************************************************
110 Initialize the global threads table.
112 *******************************************************************************/
114 #define THREADS_INITIAL_TABLE_SIZE 8
116 static void threads_table_init(void)
121 size = THREADS_INITIAL_TABLE_SIZE;
123 threads_table.table = MNEW(threads_table_entry_t, size);
124 threads_table.size = size;
126 /* link the entries in a freelist */
128 for (i = 0; i < size; i++) {
129 threads_table.table[i].nextfree = i + 1;
132 /* terminate the freelist */
134 threads_table.table[size - 1].nextfree = 0; /* index 0 is never free */
138 /* threads_table_add ***********************************************************
140 Add a thread to the global threads table. The index is entered in the
141 threadobject. The thinlock value for the thread is pre-computed.
144 thread............the thread to add
147 The table index for the newly added thread. This value has also been
148 entered in the threadobject.
151 The caller must hold the threadlistlock!
153 *******************************************************************************/
155 s4 threads_table_add(threadobject *thread)
162 /* table[0] serves as the head of the freelist */
164 index = threads_table.table[0].nextfree;
166 /* if we got a free index, use it */
170 threads_table.table[0].nextfree = threads_table.table[index].nextfree;
171 threads_table.table[index].thread = thread;
173 thread->index = index;
174 thread->thinlock = lock_pre_compute_thinlock(index);
179 /* we must grow the table */
181 oldsize = threads_table.size;
182 newsize = oldsize * 2;
184 threads_table.table = MREALLOC(threads_table.table, threads_table_entry_t,
186 threads_table.size = newsize;
188 /* link the new entries to a free list */
190 for (i = oldsize; i < newsize; i++) {
191 threads_table.table[i].nextfree = i + 1;
194 /* terminate the freelist */
196 threads_table.table[newsize - 1].nextfree = 0; /* index 0 is never free */
198 /* use the first of the new entries */
205 /* threads_table_remove *******************************************************
207 Remove a thread from the global threads table.
210 thread............the thread to remove
213 The caller must hold the threadlistlock!
215 ******************************************************************************/
217 void threads_table_remove(threadobject *thread)
221 index = thread->index;
223 /* put the index into the freelist */
225 threads_table.table[index] = threads_table.table[0];
226 threads_table.table[0].nextfree = index;
228 /* delete the index in the threadobject to discover bugs */
235 /* threads_table_dump *********************************************************
237 Dump the threads table for debugging purposes.
240 file..............stream to write to
242 ******************************************************************************/
244 #if !defined(NDEBUG) && 0
245 static void threads_table_dump(FILE *file)
251 pthread_mutex_lock(&threadlistlock);
253 size = threads_table.size;
255 fprintf(file, "======== THREADS TABLE (size %d) ========\n", size);
257 for (i=0; i<size; ++i) {
258 index = threads_table.table[i].nextfree;
260 fprintf(file, "%4d: ", i);
263 fprintf(file, "free, nextfree = %d\n", (int) index);
266 fprintf(file, "thread %p\n", (void*) threads_table.table[i].thread);
270 fprintf(file, "======== END OF THREADS TABLE ========\n");
272 pthread_mutex_unlock(&threadlistlock);
277 /* threads_create_thread *******************************************************
279 Creates and initializes an internal thread data-structure.
281 *******************************************************************************/
283 threadobject *threads_create_thread(void)
285 threadobject *thread;
287 /* allocate internal thread data-structure */
289 #if defined(ENABLE_GC_BOEHM)
290 thread = GCNEW_UNCOLLECTABLE(threadobject, 1);
292 thread = NEW(threadobject);
295 #if defined(ENABLE_STATISTICS)
297 size_threadobject += sizeof(threadobject);
300 /* initialize thread data structure */
302 threads_init_threadobject(thread);
303 lock_init_execution_env(thread);
309 /* threads_thread_start_internal ***********************************************
311 Start an internal thread in the JVM. No Java thread objects exists
315 name.......UTF-8 name of the thread
316 f..........function pointer to C function to start
318 *******************************************************************************/
320 bool threads_thread_start_internal(utf *name, functionptr f)
322 threadobject *thread;
324 #if defined(WITH_CLASSPATH_GNU)
325 java_lang_VMThread *vmt;
328 /* create internal thread data-structure */
330 thread = threads_create_thread();
332 /* create the java thread object */
334 t = (java_lang_Thread *) builtin_new(class_java_lang_Thread);
339 #if defined(WITH_CLASSPATH_GNU)
340 vmt = (java_lang_VMThread *) builtin_new(class_java_lang_VMThread);
346 vmt->vmdata = (java_lang_Object *) thread;
349 #elif defined(WITH_CLASSPATH_CLDC1_1)
350 t->vm_thread = (java_lang_Object *) thread;
354 thread->flags = THREAD_FLAG_DAEMON;
356 /* set java.lang.Thread fields */
358 t->name = (java_lang_String *) javastring_new(name);
359 #if defined(ENABLE_JAVASE)
362 t->priority = NORM_PRIORITY;
364 /* start the thread */
366 threads_impl_thread_start(thread, f);
368 /* everything's ok */
374 /* threads_thread_start ********************************************************
376 Start a Java thread in the JVM. Only the java thread object exists
380 object.....the java thread object java.lang.Thread
382 *******************************************************************************/
384 void threads_thread_start(java_lang_Thread *object)
386 threadobject *thread;
388 /* create internal thread data-structure */
390 thread = threads_create_thread();
392 /* link the two objects together */
394 thread->object = object;
396 #if defined(ENABLE_JAVASE)
397 /* is this a daemon thread? */
399 if (object->daemon == true)
400 thread->flags |= THREAD_FLAG_DAEMON;
403 #if defined(WITH_CLASSPATH_GNU)
404 assert(object->vmThread);
405 assert(object->vmThread->vmdata == NULL);
407 object->vmThread->vmdata = (java_lang_Object *) thread;
408 #elif defined(WITH_CLASSPATH_CLDC1_1)
409 object->vm_thread = (java_lang_Object *) thread;
412 /* Start the thread. Don't pass a function pointer (NULL) since
413 we want Thread.run()V here. */
415 threads_impl_thread_start(thread, NULL);
419 /* threads_get_current_tid *****************************************************
421 Return the tid of the current thread.
426 *******************************************************************************/
428 ptrint threads_get_current_tid(void)
430 threadobject *thread;
432 thread = THREADOBJECT;
434 /* this may happen during bootstrap */
439 return (ptrint) thread->tid;
443 /* threads_thread_get_state ****************************************************
445 Returns the current state of the given thread.
447 *******************************************************************************/
449 utf *threads_thread_get_state(threadobject *thread)
453 switch (thread->state) {
454 case THREAD_STATE_NEW:
455 u = utf_new_char("NEW");
457 case THREAD_STATE_RUNNABLE:
458 u = utf_new_char("RUNNABLE");
460 case THREAD_STATE_BLOCKED:
461 u = utf_new_char("BLOCKED");
463 case THREAD_STATE_WAITING:
464 u = utf_new_char("WAITING");
466 case THREAD_STATE_TIMED_WAITING:
467 u = utf_new_char("TIMED_WAITING");
469 case THREAD_STATE_TERMINATED:
470 u = utf_new_char("TERMINATED");
473 vm_abort("threads_get_state: unknown thread state %d", thread->state);
480 /* threads_thread_is_alive *****************************************************
482 Returns if the give thread is alive.
484 *******************************************************************************/
486 bool threads_thread_is_alive(threadobject *thread)
490 switch (thread->state) {
491 case THREAD_STATE_NEW:
492 case THREAD_STATE_TERMINATED:
496 case THREAD_STATE_RUNNABLE:
497 case THREAD_STATE_BLOCKED:
498 case THREAD_STATE_WAITING:
499 case THREAD_STATE_TIMED_WAITING:
504 vm_abort("threads_is_alive: unknown thread state %d", thread->state);
511 /* threads_dump ****************************************************************
513 Dumps info for all threads running in the JVM. This function is
514 called when SIGQUIT (<ctrl>-\) is sent to CACAO.
516 *******************************************************************************/
518 void threads_dump(void)
520 threadobject *thread;
524 /* XXX we should stop the world here */
526 printf("Full thread dump CACAO "VERSION":\n");
528 /* iterate over all started threads */
530 thread = mainthreadobj;
533 /* get thread object */
537 /* the thread may be currently in initalization, don't print it */
540 /* get thread name */
542 #if defined(ENABLE_JAVASE)
543 name = javastring_toutf((java_objectheader *) t->name, false);
544 #elif defined(ENABLE_JAVAME_CLDC1_1)
549 utf_display_printable_ascii(name);
552 if (thread->flags & THREAD_FLAG_DAEMON)
555 printf(" prio=%d", t->priority);
557 #if SIZEOF_VOID_P == 8
558 printf(" tid=0x%016lx (%ld)",
559 (ptrint) thread->tid, (ptrint) thread->tid);
561 printf(" tid=0x%08x (%d)",
562 (ptrint) thread->tid, (ptrint) thread->tid);
565 /* print thread state */
567 switch (thread->state) {
568 case THREAD_STATE_NEW:
571 case THREAD_STATE_RUNNABLE:
574 case THREAD_STATE_BLOCKED:
577 case THREAD_STATE_WAITING:
580 case THREAD_STATE_TIMED_WAITING:
581 printf(" waiting on condition");
583 case THREAD_STATE_TERMINATED:
584 printf(" terminated");
587 vm_abort("threads_dump: unknown thread state %d",
593 /* print trace of thread */
595 threads_thread_print_stacktrace(thread);
598 thread = thread->next;
599 } while ((thread != NULL) && (thread != mainthreadobj));
603 /* threads_thread_print_stacktrace *********************************************
605 Print the current stacktrace of the current thread.
607 *******************************************************************************/
609 void threads_thread_print_stacktrace(threadobject *thread)
612 stacktracebuffer *stb;
615 /* mark start of dump memory area */
617 dumpsize = dump_size();
619 /* create a stacktrace for the passed thread */
621 sfi = thread->_stackframeinfo;
623 stb = stacktrace_create(sfi);
625 /* print stacktrace */
628 stacktrace_print_trace_from_buffer(stb);
630 puts("\t<<No stacktrace available>>");
634 dump_release(dumpsize);
638 /* threads_print_stacktrace ****************************************************
640 Print the current stacktrace of the current thread.
642 *******************************************************************************/
644 void threads_print_stacktrace(void)
646 threadobject *thread;
648 thread = THREADOBJECT;
650 threads_thread_print_stacktrace(thread);
655 * These are local overrides for various environment variables in Emacs.
656 * Please do not remove this and leave it at the end of the file, where
657 * Emacs will automagically detect them.
658 * ---------------------------------------------------------------------
661 * indent-tabs-mode: t
665 * vim:noexpandtab:sw=4:ts=4: