1 /* src/threads/native/threads.c - native threads support
3 Copyright (C) 1996-2005, 2006, 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.c 7674 2007-04-05 13:27:11Z michi $
32 /* XXX cleanup these includes */
37 #include <sys/types.h>
50 #if !defined(USE_FAKE_ATOMIC_INSTRUCTIONS)
51 # include "machine-instr.h"
53 # include "threads/native/generic-primitives.h"
56 #include "mm/gc-common.h"
57 #include "mm/memory.h"
59 #include "native/jni.h"
60 #include "native/native.h"
61 #include "native/include/java_lang_Object.h"
62 #include "native/include/java_lang_String.h"
63 #include "native/include/java_lang_Throwable.h"
64 #include "native/include/java_lang_Thread.h"
66 #if defined(ENABLE_JAVASE)
67 # include "native/include/java_lang_ThreadGroup.h"
70 #if defined(WITH_CLASSPATH_GNU)
71 # include "native/include/java_lang_VMThread.h"
74 #include "threads/threads-common.h"
76 #include "threads/native/threads.h"
78 #include "toolbox/avl.h"
79 #include "toolbox/logging.h"
81 #include "vm/builtin.h"
82 #include "vm/exceptions.h"
83 #include "vm/global.h"
84 #include "vm/stringlocal.h"
87 #include "vm/jit/asmpart.h"
89 #include "vmcore/options.h"
91 #if defined(ENABLE_STATISTICS)
92 # include "vmcore/statistics.h"
95 #if !defined(__DARWIN__)
96 # if defined(__LINUX__)
97 # define GC_LINUX_THREADS
98 # elif defined(__MIPS__)
99 # define GC_IRIX_THREADS
101 # include <semaphore.h>
102 # if defined(ENABLE_GC_BOEHM)
103 # include "mm/boehm-gc/include/gc.h"
107 #if defined(ENABLE_JVMTI)
108 #include "native/jvmti/cacaodbg.h"
111 #if defined(__DARWIN__)
112 /* Darwin has no working semaphore implementation. This one is taken
116 This is a very simple semaphore implementation for darwin. It
117 is implemented in terms of pthreads calls so it isn't async signal
118 safe. This isn't a problem because signals aren't used to
119 suspend threads on darwin.
122 static int sem_init(sem_t *sem, int pshared, int value)
129 if (pthread_mutex_init(&sem->mutex, NULL) < 0)
132 if (pthread_cond_init(&sem->cond, NULL) < 0)
138 static int sem_post(sem_t *sem)
140 if (pthread_mutex_lock(&sem->mutex) < 0)
145 if (pthread_cond_signal(&sem->cond) < 0) {
146 pthread_mutex_unlock(&sem->mutex);
150 if (pthread_mutex_unlock(&sem->mutex) < 0)
156 static int sem_wait(sem_t *sem)
158 if (pthread_mutex_lock(&sem->mutex) < 0)
161 while (sem->value == 0) {
162 pthread_cond_wait(&sem->cond, &sem->mutex);
167 if (pthread_mutex_unlock(&sem->mutex) < 0)
173 static int sem_destroy(sem_t *sem)
175 if (pthread_cond_destroy(&sem->cond) < 0)
178 if (pthread_mutex_destroy(&sem->mutex) < 0)
183 #endif /* defined(__DARWIN__) */
186 /* internally used constants **************************************************/
188 /* CAUTION: Do not change these values. Boehm GC code depends on them. */
189 #define STOPWORLD_FROM_GC 1
190 #define STOPWORLD_FROM_CLASS_NUMBERING 2
192 #define THREADS_INITIAL_TABLE_SIZE 8
195 /* startupinfo *****************************************************************
197 Struct used to pass info from threads_start_thread to
198 threads_startup_thread.
200 ******************************************************************************/
203 threadobject *thread; /* threadobject for this thread */
204 functionptr function; /* function to run in the new thread */
205 sem_t *psem; /* signals when thread has been entered */
206 /* in the thread list */
207 sem_t *psem_first; /* signals when pthread_create has returned */
211 /* prototypes *****************************************************************/
213 static void threads_table_init(void);
214 static s4 threads_table_add(threadobject *thread);
215 static void threads_table_remove(threadobject *thread);
216 static void threads_calc_absolute_time(struct timespec *tm, s8 millis, s4 nanos);
218 #if !defined(NDEBUG) && 0
219 static void threads_table_dump(FILE *file);
222 /******************************************************************************/
223 /* GLOBAL VARIABLES */
224 /******************************************************************************/
226 /* the main thread */
227 threadobject *mainthreadobj;
229 static methodinfo *method_thread_init;
231 /* the thread object of the current thread */
232 /* This is either a thread-local variable defined with __thread, or */
233 /* a thread-specific value stored with key threads_current_threadobject_key. */
234 #if defined(HAVE___THREAD)
235 __thread threadobject *threads_current_threadobject;
237 pthread_key_t threads_current_threadobject_key;
240 /* global threads table */
241 static threads_table_t threads_table;
243 /* global compiler mutex */
244 static pthread_mutex_t compiler_mutex;
246 /* global mutex for changing the thread list */
247 static pthread_mutex_t threadlistlock;
249 /* global mutex for stop-the-world */
250 static pthread_mutex_t stopworldlock;
252 /* this is one of the STOPWORLD_FROM_ constants, telling why the world is */
254 static volatile int stopworldwhere;
256 /* semaphore used for acknowleding thread suspension */
257 static sem_t suspend_ack;
258 #if defined(__MIPS__)
259 static pthread_mutex_t suspend_ack_lock = PTHREAD_MUTEX_INITIALIZER;
260 static pthread_cond_t suspend_cond = PTHREAD_COND_INITIALIZER;
263 static pthread_attr_t threadattr;
265 /* mutexes used by the fake atomic instructions */
266 #if defined(USE_FAKE_ATOMIC_INSTRUCTIONS)
267 pthread_mutex_t _atomic_add_lock = PTHREAD_MUTEX_INITIALIZER;
268 pthread_mutex_t _cas_lock = PTHREAD_MUTEX_INITIALIZER;
269 pthread_mutex_t _mb_lock = PTHREAD_MUTEX_INITIALIZER;
273 /* threads_sem_init ************************************************************
275 Initialize a semaphore. Checks against errors and interruptions.
278 sem..............the semaphore to initialize
279 shared...........true if this semaphore will be shared between processes
280 value............the initial value for the semaphore
282 *******************************************************************************/
284 void threads_sem_init(sem_t *sem, bool shared, int value)
291 r = sem_init(sem, shared, value);
294 } while (errno == EINTR);
296 vm_abort("sem_init failed: %s", strerror(errno));
300 /* threads_sem_wait ************************************************************
302 Wait for a semaphore, non-interruptible.
304 IMPORTANT: Always use this function instead of `sem_wait` directly, as
305 `sem_wait` may be interrupted by signals!
308 sem..............the semaphore to wait on
310 *******************************************************************************/
312 void threads_sem_wait(sem_t *sem)
322 } while (errno == EINTR);
324 vm_abort("sem_wait failed: %s", strerror(errno));
328 /* threads_sem_post ************************************************************
330 Increase the count of a semaphore. Checks for errors.
333 sem..............the semaphore to increase the count of
335 *******************************************************************************/
337 void threads_sem_post(sem_t *sem)
343 /* unlike sem_wait, sem_post is not interruptible */
349 vm_abort("sem_post failed: %s", strerror(errno));
353 /* compiler_lock ***************************************************************
355 Enter the compiler lock.
357 ******************************************************************************/
359 void compiler_lock(void)
361 pthread_mutex_lock(&compiler_mutex);
365 /* compiler_unlock *************************************************************
367 Release the compiler lock.
369 ******************************************************************************/
371 void compiler_unlock(void)
373 pthread_mutex_unlock(&compiler_mutex);
377 /* lock_stopworld **************************************************************
379 Enter the stopworld lock, specifying why the world shall be stopped.
382 where........ STOPWORLD_FROM_GC (1) from within GC
383 STOPWORLD_FROM_CLASS_NUMBERING (2) class numbering
385 ******************************************************************************/
387 void lock_stopworld(int where)
389 pthread_mutex_lock(&stopworldlock);
390 stopworldwhere = where;
394 /* unlock_stopworld ************************************************************
396 Release the stopworld lock.
398 ******************************************************************************/
400 void unlock_stopworld(void)
403 pthread_mutex_unlock(&stopworldlock);
406 #if defined(__DARWIN__)
407 /* Caller must hold threadlistlock */
408 static void threads_cast_darwinstop(void)
410 threadobject *tobj = mainthreadobj;
411 threadobject *self = THREADOBJECT;
416 thread_state_flavor_t flavor = MACHINE_THREAD_STATE;
417 mach_msg_type_number_t thread_state_count = MACHINE_THREAD_STATE_COUNT;
418 #if defined(__I386__)
419 i386_thread_state_t thread_state;
421 ppc_thread_state_t thread_state;
423 mach_port_t thread = tobj->mach_thread;
426 r = thread_suspend(thread);
428 if (r != KERN_SUCCESS)
429 vm_abort("thread_suspend failed");
431 r = thread_get_state(thread, flavor, (natural_t *) &thread_state,
432 &thread_state_count);
434 if (r != KERN_SUCCESS)
435 vm_abort("thread_get_state failed");
437 thread_restartcriticalsection((ucontext_t *) &thread_state);
439 r = thread_set_state(thread, flavor, (natural_t *) &thread_state,
442 if (r != KERN_SUCCESS)
443 vm_abort("thread_set_state failed");
447 } while (tobj != mainthreadobj);
450 static void threads_cast_darwinresume(void)
452 threadobject *tobj = mainthreadobj;
453 threadobject *self = THREADOBJECT;
458 mach_port_t thread = tobj->mach_thread;
461 r = thread_resume(thread);
463 if (r != KERN_SUCCESS)
464 vm_abort("thread_resume failed");
468 } while (tobj != mainthreadobj);
473 #if defined(__MIPS__)
474 static void threads_cast_irixresume(void)
476 pthread_mutex_lock(&suspend_ack_lock);
477 pthread_cond_broadcast(&suspend_cond);
478 pthread_mutex_unlock(&suspend_ack_lock);
483 #if !defined(__DARWIN__)
484 static void threads_sigsuspend_handler(ucontext_t *ctx)
489 /* XXX TWISTI: this is just a quick hack */
490 #if defined(ENABLE_JIT)
491 thread_restartcriticalsection(ctx);
494 /* Do as Boehm does. On IRIX a condition variable is used for wake-up
495 (not POSIX async-safe). */
496 #if defined(__IRIX__)
497 pthread_mutex_lock(&suspend_ack_lock);
498 threads_sem_post(&suspend_ack);
499 pthread_cond_wait(&suspend_cond, &suspend_ack_lock);
500 pthread_mutex_unlock(&suspend_ack_lock);
501 #elif defined(__CYGWIN__)
505 threads_sem_post(&suspend_ack);
509 sigdelset(&sigs, sig);
517 /* threads_stopworld ***********************************************************
519 Stops the world from turning. All threads except the calling one
520 are suspended. The function returns as soon as all threads have
521 acknowledged their suspension.
523 *******************************************************************************/
525 #if !defined(DISABLE_GC)
526 void threads_stopworld(void)
528 #if !defined(__DARWIN__) && !defined(__CYGWIN__)
529 threadobject *tobj = mainthreadobj;
530 threadobject *self = THREADOBJECT;
535 lock_stopworld(STOPWORLD_FROM_CLASS_NUMBERING);
536 pthread_mutex_lock(&threadlistlock);
538 #if defined(__DARWIN__)
539 threads_cast_darwinstop();
540 #elif defined(__CYGWIN__)
544 /* count how many threads we suspended */
547 /* suspend all running threads */
550 result = threads_suspend_thread(tobj, SUSPEND_REASON_STOPWORLD);
555 } while (tobj != mainthreadobj);
557 /* wait till all threads are suspended */
558 for (i = 0; i < count; i++)
559 threads_sem_wait(&suspend_ack);
562 pthread_mutex_unlock(&threadlistlock);
564 #endif /* !defined(DISABLE_GC) */
567 /* threads_startworld **********************************************************
569 Starts the world again after it has previously been stopped.
571 *******************************************************************************/
573 #if !defined(DISABLE_GC)
574 void threads_startworld(void)
576 #if !defined(__DARWIN__) && !defined(__CYGWIN__)
577 threadobject *tobj = mainthreadobj;
578 threadobject *self = THREADOBJECT;
582 pthread_mutex_lock(&threadlistlock);
584 #if defined(__DARWIN__)
585 threads_cast_darwinresume();
586 #elif defined(__MIPS__)
587 threads_cast_irixresume();
588 #elif defined(__CYGWIN__)
592 /* resume all thread we haltet */
595 result = threads_resume_thread(tobj);
599 } while (tobj != mainthreadobj);
602 pthread_mutex_unlock(&threadlistlock);
605 #endif /* DISABLE_GC */
608 /* threads_set_current_threadobject ********************************************
610 Set the current thread object.
613 thread.......the thread object to set
615 *******************************************************************************/
617 static void threads_set_current_threadobject(threadobject *thread)
619 #if !defined(HAVE___THREAD)
620 pthread_setspecific(threads_current_threadobject_key, thread);
622 threads_current_threadobject = thread;
627 /* threads_init_threadobject **************************************************
629 Initialize implementation fields of a threadobject.
632 thread............the threadobject
634 ******************************************************************************/
636 static void threads_init_threadobject(threadobject *thread)
638 thread->tid = pthread_self();
642 #if defined(ENABLE_GC_CACAO)
643 thread->flags |= THREAD_FLAG_IN_NATIVE;
644 thread->gc_critical = false;
647 /* TODO destroy all those things */
648 pthread_mutex_init(&(thread->joinmutex), NULL);
649 pthread_cond_init(&(thread->joincond), NULL);
651 pthread_mutex_init(&(thread->waitmutex), NULL);
652 pthread_cond_init(&(thread->waitcond), NULL);
654 thread->interrupted = false;
655 thread->signaled = false;
656 thread->sleeping = false;
660 /* threads_get_current_threadobject ********************************************
662 Return the threadobject of the current thread.
665 the current threadobject *
667 *******************************************************************************/
669 threadobject *threads_get_current_threadobject(void)
675 /* threads_preinit *************************************************************
677 Do some early initialization of stuff required.
679 ATTENTION: Do NOT use any Java heap allocation here, as gc_init()
680 is called AFTER this function!
682 *******************************************************************************/
684 void threads_preinit(void)
686 pthread_mutexattr_t mutexattr;
687 pthread_mutexattr_init(&mutexattr);
688 pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
689 pthread_mutex_init(&compiler_mutex, &mutexattr);
690 pthread_mutexattr_destroy(&mutexattr);
692 pthread_mutex_init(&threadlistlock, NULL);
693 pthread_mutex_init(&stopworldlock, NULL);
695 mainthreadobj = NEW(threadobject);
697 #if defined(ENABLE_STATISTICS)
699 size_threadobject += sizeof(threadobject);
702 mainthreadobj->object = NULL;
703 mainthreadobj->tid = pthread_self();
704 mainthreadobj->index = 1;
705 mainthreadobj->thinlock = lock_pre_compute_thinlock(mainthreadobj->index);
707 #if !defined(HAVE___THREAD)
708 pthread_key_create(&threads_current_threadobject_key, NULL);
710 threads_set_current_threadobject(mainthreadobj);
712 threads_sem_init(&suspend_ack, 0, 0);
714 /* initialize the threads table */
716 threads_table_init();
718 /* initialize subsystems */
726 /* threads_init ****************************************************************
728 Initializes the threads required by the JVM: main, finalizer.
730 *******************************************************************************/
732 bool threads_init(void)
734 java_lang_String *threadname;
735 threadobject *tempthread;
736 java_objectheader *o;
738 #if defined(ENABLE_JAVASE)
739 java_lang_ThreadGroup *threadgroup;
744 #if defined(WITH_CLASSPATH_GNU)
745 java_lang_VMThread *vmt;
748 tempthread = mainthreadobj;
750 /* XXX We have to find a new way to free lock records */
751 /* with the new locking algorithm. */
752 /* lock_record_free_pools(mainthreadobj->ee.lockrecordpools); */
755 /* This is kinda tricky, we grow the java.lang.Thread object so we
756 can keep the execution environment there. No Thread object must
757 have been created at an earlier time. */
759 class_java_lang_Thread->instancesize = sizeof(threadobject);
762 /* get methods we need in this file */
764 #if defined(WITH_CLASSPATH_GNU)
766 class_resolveclassmethod(class_java_lang_Thread,
768 utf_new_char("(Ljava/lang/VMThread;Ljava/lang/String;IZ)V"),
769 class_java_lang_Thread,
773 class_resolveclassmethod(class_java_lang_Thread,
775 utf_new_char("(Ljava/lang/String;)V"),
776 class_java_lang_Thread,
780 if (method_thread_init == NULL)
783 /* create a vm internal thread object for the main thread */
784 /* XXX Michi: we do not need to do this here, we could use the one
785 created by threads_preinit() */
787 #if defined(ENABLE_GC_CACAO)
788 mainthreadobj = NEW(threadobject);
790 # if defined(ENABLE_STATISTICS)
792 size_threadobject += sizeof(threadobject);
795 mainthreadobj = GCNEW(threadobject);
798 if (mainthreadobj == NULL)
801 /* create a java.lang.Thread for the main thread */
803 mainthreadobj->object = (java_lang_Thread *) builtin_new(class_java_lang_Thread);
805 if (mainthreadobj->object == NULL)
808 FREE(tempthread, threadobject);
810 threads_init_threadobject(mainthreadobj);
811 threads_set_current_threadobject(mainthreadobj);
812 lock_init_execution_env(mainthreadobj);
814 /* thread is running */
816 mainthreadobj->state = THREAD_STATE_RUNNABLE;
818 mainthreadobj->next = mainthreadobj;
819 mainthreadobj->prev = mainthreadobj;
821 threads_table_add(mainthreadobj);
823 /* mark main thread as Java thread */
825 mainthreadobj->flags = THREAD_FLAG_JAVA;
827 #if defined(ENABLE_INTRP)
828 /* create interpreter stack */
831 MSET(intrp_main_stack, 0, u1, opt_stacksize);
832 mainthreadobj->_global_sp = (Cell*) (intrp_main_stack + opt_stacksize);
836 threadname = javastring_new(utf_new_char("main"));
838 #if defined(ENABLE_JAVASE)
839 /* allocate and init ThreadGroup */
841 threadgroup = (java_lang_ThreadGroup *)
842 native_new_and_init(class_java_lang_ThreadGroup);
844 if (threadgroup == NULL)
848 #if defined(WITH_CLASSPATH_GNU)
849 /* create a java.lang.VMThread for the main thread */
851 vmt = (java_lang_VMThread *) builtin_new(class_java_lang_VMThread);
858 vmt->thread = mainthreadobj->object;
859 vmt->vmdata = (java_lang_Object *) mainthreadobj;
861 /* call java.lang.Thread.<init>(Ljava/lang/VMThread;Ljava/lang/String;IZ)V */
862 o = (java_objectheader *) mainthreadobj->object;
864 (void) vm_call_method(method_thread_init, o, vmt, threadname, NORM_PRIORITY,
866 #elif defined(WITH_CLASSPATH_CLDC1_1)
869 mainthreadobj->object->vm_thread = (java_lang_Object *) mainthreadobj;
871 /* call public Thread(String name) */
873 o = (java_objectheader *) mainthreadobj->object;
875 (void) vm_call_method(method_thread_init, o, threadname);
881 #if defined(ENABLE_JAVASE)
882 mainthreadobj->object->group = threadgroup;
884 /* add main thread to java.lang.ThreadGroup */
886 m = class_resolveclassmethod(class_java_lang_ThreadGroup,
888 utf_java_lang_Thread__V,
889 class_java_lang_ThreadGroup,
892 o = (java_objectheader *) threadgroup;
893 t = mainthreadobj->object;
895 (void) vm_call_method(m, o, t);
902 threads_set_thread_priority(pthread_self(), NORM_PRIORITY);
904 /* initialize the thread attribute object */
906 if (pthread_attr_init(&threadattr)) {
907 log_println("pthread_attr_init failed: %s", strerror(errno));
911 pthread_attr_setdetachstate(&threadattr, PTHREAD_CREATE_DETACHED);
913 /* everything's ok */
919 /* threads_table_init *********************************************************
921 Initialize the global threads table.
923 ******************************************************************************/
925 static void threads_table_init(void)
930 size = THREADS_INITIAL_TABLE_SIZE;
932 threads_table.size = size;
933 threads_table.table = MNEW(threads_table_entry_t, size);
935 /* link the entries in a freelist */
937 for (i=0; i<size; ++i) {
938 threads_table.table[i].nextfree = i+1;
941 /* terminate the freelist */
943 threads_table.table[size-1].nextfree = 0; /* index 0 is never free */
947 /* threads_table_add **********************************************************
949 Add a thread to the global threads table. The index is entered in the
950 threadobject. The thinlock value for the thread is pre-computed.
953 thread............the thread to add
956 The table index for the newly added thread. This value has also been
957 entered in the threadobject.
960 The caller must hold the threadlistlock!
962 ******************************************************************************/
964 static s4 threads_table_add(threadobject *thread)
971 /* table[0] serves as the head of the freelist */
973 index = threads_table.table[0].nextfree;
975 /* if we got a free index, use it */
979 threads_table.table[0].nextfree = threads_table.table[index].nextfree;
980 threads_table.table[index].thread = thread;
981 thread->index = index;
982 thread->thinlock = lock_pre_compute_thinlock(index);
986 /* we must grow the table */
988 oldsize = threads_table.size;
989 newsize = oldsize * 2;
991 threads_table.table = MREALLOC(threads_table.table, threads_table_entry_t,
993 threads_table.size = newsize;
995 /* link the new entries to a free list */
997 for (i=oldsize; i<newsize; ++i) {
998 threads_table.table[i].nextfree = i+1;
1001 /* terminate the freelist */
1003 threads_table.table[newsize-1].nextfree = 0; /* index 0 is never free */
1005 /* use the first of the new entries */
1012 /* threads_table_remove *******************************************************
1014 Remove a thread from the global threads table.
1017 thread............the thread to remove
1020 The caller must hold the threadlistlock!
1022 ******************************************************************************/
1024 static void threads_table_remove(threadobject *thread)
1028 index = thread->index;
1030 /* put the index into the freelist */
1032 threads_table.table[index] = threads_table.table[0];
1033 threads_table.table[0].nextfree = index;
1035 /* delete the index in the threadobject to discover bugs */
1036 #if !defined(NDEBUG)
1042 /* threads_startup_thread ******************************************************
1044 Thread startup function called by pthread_create.
1046 Thread which have a startup.function != NULL are marked as internal
1047 threads. All other threads are threated as normal Java threads.
1049 NOTE: This function is not called directly by pthread_create. The Boehm GC
1050 inserts its own GC_start_routine in between, which then calls
1054 t............the argument passed to pthread_create, ie. a pointer to
1055 a startupinfo struct. CAUTION: When the `psem` semaphore
1056 is posted, the startupinfo struct becomes invalid! (It
1057 is allocated on the stack of threads_start_thread.)
1059 ******************************************************************************/
1061 static void *threads_startup_thread(void *t)
1063 startupinfo *startup;
1064 threadobject *thread;
1065 #if defined(WITH_CLASSPATH_GNU)
1066 java_lang_VMThread *vmt;
1069 threadobject *tnext;
1072 java_objectheader *o;
1073 functionptr function;
1075 #if defined(ENABLE_INTRP)
1076 u1 *intrp_thread_stack;
1078 /* create interpreter stack */
1081 intrp_thread_stack = GCMNEW(u1, opt_stacksize);
1082 MSET(intrp_thread_stack, 0, u1, opt_stacksize);
1085 intrp_thread_stack = NULL;
1088 /* get passed startupinfo structure and the values in there */
1091 t = NULL; /* make sure it's not used wrongly */
1093 thread = startup->thread;
1094 function = startup->function;
1095 psem = startup->psem;
1097 /* Seems like we've encountered a situation where thread->tid was not set by
1098 * pthread_create. We alleviate this problem by waiting for pthread_create
1100 threads_sem_wait(startup->psem_first);
1102 /* set the thread object */
1104 #if defined(__DARWIN__)
1105 thread->mach_thread = mach_thread_self();
1108 threads_init_threadobject(thread);
1109 threads_set_current_threadobject(thread);
1111 /* thread is running */
1113 thread->state = THREAD_STATE_RUNNABLE;
1115 /* insert the thread into the threadlist and the threads table */
1117 pthread_mutex_lock(&threadlistlock);
1119 thread->prev = mainthreadobj;
1120 thread->next = tnext = mainthreadobj->next;
1121 mainthreadobj->next = thread;
1122 tnext->prev = thread;
1124 threads_table_add(thread);
1126 pthread_mutex_unlock(&threadlistlock);
1128 /* init data structures of this thread */
1130 lock_init_execution_env(thread);
1132 /* tell threads_startup_thread that we registered ourselves */
1133 /* CAUTION: *startup becomes invalid with this! */
1136 threads_sem_post(psem);
1138 /* set our priority */
1140 threads_set_thread_priority(thread->tid, thread->object->priority);
1142 #if defined(ENABLE_INTRP)
1143 /* set interpreter stack */
1146 thread->_global_sp = (Cell *) (intrp_thread_stack + opt_stacksize);
1149 #if defined(ENABLE_JVMTI)
1150 /* fire thread start event */
1153 jvmti_ThreadStartEnd(JVMTI_EVENT_THREAD_START);
1156 /* find and run the Thread.run()V method if no other function was passed */
1158 if (function == NULL) {
1159 /* this is a normal Java thread */
1161 thread->flags |= THREAD_FLAG_JAVA;
1163 #if defined(WITH_CLASSPATH_GNU)
1164 /* We need to start the run method of
1165 java.lang.VMThread. Since this is a final class, we can use
1166 the class object directly. */
1168 c = class_java_lang_VMThread;
1169 #elif defined(WITH_CLASSPATH_CLDC1_1)
1170 c = thread->object->header.vftbl->class;
1173 m = class_resolveclassmethod(c, utf_run, utf_void__void, c, true);
1176 vm_abort("threads_startup_thread: run() method not found in class");
1178 /* set ThreadMXBean variables */
1180 _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount++;
1181 _Jv_jvm->java_lang_management_ThreadMXBean_TotalStartedThreadCount++;
1183 if (_Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount >
1184 _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount)
1185 _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount =
1186 _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount;
1188 #if defined(WITH_CLASSPATH_GNU)
1189 /* we need to start the run method of java.lang.VMThread */
1191 vmt = (java_lang_VMThread *) thread->object->vmThread;
1192 o = (java_objectheader *) vmt;
1194 #elif defined(WITH_CLASSPATH_CLDC1_1)
1195 o = (java_objectheader *) thread->object;
1198 /* run the thread */
1200 (void) vm_call_method(m, o);
1203 /* this is an internal thread */
1205 thread->flags |= THREAD_FLAG_INTERNAL;
1207 /* set ThreadMXBean variables */
1209 _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount++;
1210 _Jv_jvm->java_lang_management_ThreadMXBean_TotalStartedThreadCount++;
1212 if (_Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount >
1213 _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount)
1214 _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount =
1215 _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount;
1217 /* call passed function, e.g. finalizer_thread */
1222 #if defined(ENABLE_JVMTI)
1223 /* fire thread end event */
1226 jvmti_ThreadStartEnd(JVMTI_EVENT_THREAD_END);
1229 threads_detach_thread(thread);
1231 /* set ThreadMXBean variables */
1233 _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount--;
1239 /* threads_start_javathread ***************************************************
1241 Start a thread in the JVM. Only the java thread object exists so far.
1244 object.....the java thread object java.lang.Thread
1246 ******************************************************************************/
1248 void threads_start_javathread(java_lang_Thread *object)
1250 threadobject *thread;
1252 /* create the vm internal threadobject */
1254 thread = NEW(threadobject);
1256 #if defined(ENABLE_STATISTICS)
1258 size_threadobject += sizeof(threadobject);
1261 /* link the two objects together */
1263 thread->object = object;
1265 #if defined(WITH_CLASSPATH_GNU)
1266 assert(object->vmThread);
1267 assert(object->vmThread->vmdata == NULL);
1268 object->vmThread->vmdata = (java_lang_Object *) thread;
1269 #elif defined(WITH_CLASSPATH_CLDC1_1)
1270 object->vm_thread = (java_lang_Object *) thread;
1273 /* actually start the thread */
1274 /* don't pass a function pointer (NULL) since we want Thread.run()V here */
1276 threads_start_thread(thread, NULL);
1280 /* threads_start_thread ********************************************************
1282 Start a thread in the JVM. Both (vm internal and java) thread objects exist.
1285 thread.......the thread object
1286 function.....function to run in the new thread. NULL means that the
1287 "run" method of the object `t` should be called
1289 ******************************************************************************/
1291 void threads_start_thread(threadobject *thread, functionptr function)
1295 pthread_attr_t attr;
1296 startupinfo startup;
1298 /* fill startupinfo structure passed by pthread_create to
1299 * threads_startup_thread */
1301 startup.thread = thread;
1302 startup.function = function; /* maybe we don't call Thread.run()V */
1303 startup.psem = &sem;
1304 startup.psem_first = &sem_first;
1306 threads_sem_init(&sem, 0, 0);
1307 threads_sem_init(&sem_first, 0, 0);
1309 /* initialize thread attribute object */
1311 if (pthread_attr_init(&attr))
1312 vm_abort("pthread_attr_init failed: %s", strerror(errno));
1314 /* initialize thread stacksize */
1316 if (pthread_attr_setstacksize(&attr, opt_stacksize))
1317 vm_abort("pthread_attr_setstacksize failed: %s", strerror(errno));
1319 /* create the thread */
1321 if (pthread_create(&(thread->tid), &attr, threads_startup_thread, &startup))
1322 vm_abort("pthread_create failed: %s", strerror(errno));
1324 /* signal that pthread_create has returned, so thread->tid is valid */
1326 threads_sem_post(&sem_first);
1328 /* wait here until the thread has entered itself into the thread list */
1330 threads_sem_wait(&sem);
1335 sem_destroy(&sem_first);
1339 /* threads_set_thread_priority *************************************************
1341 Set the priority of the given thread.
1344 tid..........thread id
1345 priority.....priority to set
1347 ******************************************************************************/
1349 void threads_set_thread_priority(pthread_t tid, int priority)
1351 struct sched_param schedp;
1354 pthread_getschedparam(tid, &policy, &schedp);
1355 schedp.sched_priority = priority;
1356 pthread_setschedparam(tid, policy, &schedp);
1360 /* threads_attach_current_thread ***********************************************
1362 Attaches the current thread to the VM. Used in JNI.
1364 *******************************************************************************/
1366 bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon)
1368 threadobject *thread;
1370 java_lang_String *s;
1371 java_objectheader *o;
1372 java_lang_Thread *t;
1374 #if defined(ENABLE_JAVASE)
1375 java_lang_ThreadGroup *group;
1379 #if defined(WITH_CLASSPATH_GNU)
1380 java_lang_VMThread *vmt;
1383 /* create a vm internal thread object */
1385 thread = NEW(threadobject);
1387 #if defined(ENABLE_STATISTICS)
1389 size_threadobject += sizeof(threadobject);
1395 /* create a java.lang.Thread object */
1397 t = (java_lang_Thread *) builtin_new(class_java_lang_Thread);
1404 threads_init_threadobject(thread);
1405 threads_set_current_threadobject(thread);
1406 lock_init_execution_env(thread);
1408 /* thread is running */
1410 thread->state = THREAD_STATE_RUNNABLE;
1412 /* insert the thread into the threadlist and the threads table */
1414 pthread_mutex_lock(&threadlistlock);
1416 thread->prev = mainthreadobj;
1417 thread->next = mainthreadobj->next;
1418 mainthreadobj->next = thread;
1419 thread->next->prev = thread;
1421 threads_table_add(thread);
1423 pthread_mutex_unlock(&threadlistlock);
1425 /* mark thread as Java thread */
1427 thread->flags = THREAD_FLAG_JAVA;
1430 thread->flags |= THREAD_FLAG_DAEMON;
1432 #if defined(ENABLE_INTRP)
1433 /* create interpreter stack */
1436 MSET(intrp_main_stack, 0, u1, opt_stacksize);
1437 thread->_global_sp = (Cell *) (intrp_main_stack + opt_stacksize);
1441 #if defined(WITH_CLASSPATH_GNU)
1442 /* create a java.lang.VMThread object */
1444 vmt = (java_lang_VMThread *) builtin_new(class_java_lang_VMThread);
1449 /* set the thread */
1452 vmt->vmdata = (java_lang_Object *) thread;
1453 #elif defined(WITH_CLASSPATH_CLDC1_1)
1454 t->vm_thread = (java_lang_Object *) thread;
1457 if (vm_aargs != NULL) {
1458 u = utf_new_char(vm_aargs->name);
1459 #if defined(ENABLE_JAVASE)
1460 group = (java_lang_ThreadGroup *) vm_aargs->group;
1465 #if defined(ENABLE_JAVASE)
1466 group = mainthreadobj->object->group;
1470 s = javastring_new(u);
1472 o = (java_objectheader *) thread->object;
1474 #if defined(WITH_CLASSPATH_GNU)
1475 (void) vm_call_method(method_thread_init, o, vmt, s, NORM_PRIORITY,
1477 #elif defined(WITH_CLASSPATH_CLDC1_1)
1478 (void) vm_call_method(method_thread_init, o, s);
1484 #if defined(ENABLE_JAVASE)
1485 /* store the thread group in the object */
1487 thread->object->group = group;
1489 /* add thread to given thread-group */
1491 m = class_resolveclassmethod(group->header.vftbl->class,
1493 utf_java_lang_Thread__V,
1494 class_java_lang_ThreadGroup,
1497 o = (java_objectheader *) group;
1499 (void) vm_call_method(m, o, t);
1509 /* threads_detach_thread *******************************************************
1511 Detaches the passed thread from the VM. Used in JNI.
1513 *******************************************************************************/
1515 bool threads_detach_thread(threadobject *thread)
1517 #if defined(ENABLE_JAVASE)
1518 java_lang_ThreadGroup *group;
1520 java_objectheader *o;
1521 java_lang_Thread *t;
1524 /* Allow lock record pools to be used by other threads. They
1525 cannot be deleted so we'd better not waste them. */
1527 /* XXX We have to find a new way to free lock records */
1528 /* with the new locking algorithm. */
1529 /* lock_record_free_pools(thread->ee.lockrecordpools); */
1531 /* XXX implement uncaught exception stuff (like JamVM does) */
1533 #if defined(ENABLE_JAVASE)
1534 /* remove thread from the thread group */
1536 group = thread->object->group;
1538 /* XXX TWISTI: should all threads be in a ThreadGroup? */
1540 if (group != NULL) {
1541 m = class_resolveclassmethod(group->header.vftbl->class,
1543 utf_java_lang_Thread__V,
1544 class_java_lang_ThreadGroup,
1550 o = (java_objectheader *) group;
1553 (void) vm_call_method(m, o, t);
1560 /* thread is terminated */
1562 thread->state = THREAD_STATE_TERMINATED;
1564 /* remove thread from thread list and threads table, do this
1567 pthread_mutex_lock(&threadlistlock);
1569 thread->next->prev = thread->prev;
1570 thread->prev->next = thread->next;
1572 threads_table_remove(thread);
1574 pthread_mutex_unlock(&threadlistlock);
1576 /* reset thread id (lock on joinmutex? TWISTI) */
1578 pthread_mutex_lock(&(thread->joinmutex));
1580 pthread_mutex_unlock(&(thread->joinmutex));
1582 /* tell everyone that a thread has finished */
1584 pthread_cond_broadcast(&(thread->joincond));
1586 /* free the vm internal thread object */
1588 FREE(thread, threadobject);
1590 #if defined(ENABLE_STATISTICS)
1592 size_threadobject -= sizeof(threadobject);
1599 /* threads_suspend_thread ******************************************************
1601 Suspend the passed thread. Execution stops until the thread
1602 is explicitly resumend again.
1605 reason.....Reason for suspending this thread.
1607 *******************************************************************************/
1609 bool threads_suspend_thread(threadobject *thread, s4 reason)
1611 /* acquire the suspendmutex */
1612 pthread_mutex_lock(&(thread->suspendmutex));
1614 if (thread->suspended) {
1615 pthread_mutex_unlock(&(thread->suspendmutex));
1619 /* set the reason for the suspension */
1620 thread->suspend_reason = reason;
1622 /* send the suspend signal to the thread */
1623 assert(thread != THREADOBJECT);
1624 pthread_kill(thread->tid, SIGUSR1);
1626 /* REMEMBER: do not release the suspendmutex, this is done
1627 by the thread itself in threads_suspend_ack(). */
1633 /* threads_suspend_ack *********************************************************
1635 Acknowledges the suspension of the current thread.
1638 pc.....The PC where the thread suspended its execution.
1639 sp.....The SP before the thread suspended its execution.
1641 *******************************************************************************/
1643 void threads_suspend_ack(u1* pc, u1* sp)
1645 threadobject *thread;
1647 thread = THREADOBJECT;
1649 assert(thread->suspend_reason != 0);
1651 /* TODO: remember dump memory size */
1653 #if defined(ENABLE_GC_CACAO)
1654 /* inform the GC about the suspension */
1655 if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD) {
1657 /* check if the GC wants to leave the thread running */
1658 if (!gc_suspend(thread, pc, sp)) {
1660 /* REMEMBER: we do not unlock the suspendmutex because the thread
1661 will suspend itself again at a later time */
1668 /* mark this thread as suspended and remember the PC */
1670 thread->suspended = true;
1672 /* if we are stopping the world, we should send a global ack */
1673 if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD) {
1674 threads_sem_post(&suspend_ack);
1677 /* release the suspension mutex and wait till we are resumed */
1678 pthread_cond_wait(&(thread->suspendcond), &(thread->suspendmutex));
1680 /* TODO: free dump memory */
1682 /* release the suspendmutex */
1683 pthread_mutex_unlock(&(thread->suspendmutex));
1687 /* threads_resume_thread *******************************************************
1689 Resumes the execution of the passed thread.
1691 *******************************************************************************/
1693 bool threads_resume_thread(threadobject *thread)
1695 /* acquire the suspendmutex */
1696 pthread_mutex_lock(&(thread->suspendmutex));
1698 if (!thread->suspended) {
1699 pthread_mutex_unlock(&(thread->suspendmutex));
1703 thread->suspended = false;
1705 /* tell everyone that the thread should resume */
1706 assert(thread != THREADOBJECT);
1707 pthread_cond_broadcast(&(thread->suspendcond));
1709 /* release the suspendmutex */
1710 pthread_mutex_unlock(&(thread->suspendmutex));
1715 /* threads_find_non_daemon_thread **********************************************
1717 Helper function used by threads_join_all_threads for finding
1718 non-daemon threads that are still running.
1720 *******************************************************************************/
1722 /* At the end of the program, we wait for all running non-daemon
1725 static threadobject *threads_find_non_daemon_thread(threadobject *thread)
1727 while (thread != mainthreadobj) {
1728 if (!(thread->flags & THREAD_FLAG_DAEMON))
1731 thread = thread->prev;
1738 /* threads_join_all_threads ****************************************************
1740 Join all non-daemon threads.
1742 *******************************************************************************/
1744 void threads_join_all_threads(void)
1746 threadobject *thread;
1748 pthread_mutex_lock(&threadlistlock);
1750 while ((thread = threads_find_non_daemon_thread(mainthreadobj->prev)) != NULL) {
1751 pthread_mutex_lock(&(thread->joinmutex));
1753 pthread_mutex_unlock(&threadlistlock);
1756 pthread_cond_wait(&(thread->joincond), &(thread->joinmutex));
1758 pthread_mutex_unlock(&(thread->joinmutex));
1760 pthread_mutex_lock(&threadlistlock);
1763 pthread_mutex_unlock(&threadlistlock);
1767 /* threads_timespec_earlier ****************************************************
1769 Return true if timespec tv1 is earlier than timespec tv2.
1772 tv1..........first timespec
1773 tv2..........second timespec
1776 true, if the first timespec is earlier
1778 *******************************************************************************/
1780 static inline bool threads_timespec_earlier(const struct timespec *tv1,
1781 const struct timespec *tv2)
1783 return (tv1->tv_sec < tv2->tv_sec)
1785 (tv1->tv_sec == tv2->tv_sec && tv1->tv_nsec < tv2->tv_nsec);
1789 /* threads_current_time_is_earlier_than ****************************************
1791 Check if the current time is earlier than the given timespec.
1794 tv...........the timespec to compare against
1797 true, if the current time is earlier
1799 *******************************************************************************/
1801 static bool threads_current_time_is_earlier_than(const struct timespec *tv)
1803 struct timeval tvnow;
1804 struct timespec tsnow;
1806 /* get current time */
1808 if (gettimeofday(&tvnow, NULL) != 0)
1809 vm_abort("gettimeofday failed: %s\n", strerror(errno));
1811 /* convert it to a timespec */
1813 tsnow.tv_sec = tvnow.tv_sec;
1814 tsnow.tv_nsec = tvnow.tv_usec * 1000;
1816 /* compare current time with the given timespec */
1818 return threads_timespec_earlier(&tsnow, tv);
1822 /* threads_wait_with_timeout ***************************************************
1824 Wait until the given point in time on a monitor until either
1825 we are notified, we are interrupted, or the time is up.
1828 t............the current thread
1829 wakeupTime...absolute (latest) wakeup time
1830 If both tv_sec and tv_nsec are zero, this function
1831 waits for an unlimited amount of time.
1834 true.........if the wait has been interrupted,
1835 false........if the wait was ended by notification or timeout
1837 *******************************************************************************/
1839 static bool threads_wait_with_timeout(threadobject *thread,
1840 struct timespec *wakeupTime)
1842 bool wasinterrupted;
1844 /* acquire the waitmutex */
1846 pthread_mutex_lock(&thread->waitmutex);
1848 /* mark us as sleeping */
1850 thread->sleeping = true;
1852 /* wait on waitcond */
1854 if (wakeupTime->tv_sec || wakeupTime->tv_nsec) {
1856 while (!thread->interrupted && !thread->signaled
1857 && threads_current_time_is_earlier_than(wakeupTime))
1859 thread->state = THREAD_STATE_TIMED_WAITING;
1861 pthread_cond_timedwait(&thread->waitcond, &thread->waitmutex,
1864 thread->state = THREAD_STATE_RUNNABLE;
1869 while (!thread->interrupted && !thread->signaled) {
1870 thread->state = THREAD_STATE_WAITING;
1872 pthread_cond_wait(&thread->waitcond, &thread->waitmutex);
1874 thread->state = THREAD_STATE_RUNNABLE;
1878 /* check if we were interrupted */
1880 wasinterrupted = thread->interrupted;
1882 /* reset all flags */
1884 thread->interrupted = false;
1885 thread->signaled = false;
1886 thread->sleeping = false;
1888 /* release the waitmutex */
1890 pthread_mutex_unlock(&thread->waitmutex);
1892 return wasinterrupted;
1896 /* threads_wait_with_timeout_relative ******************************************
1898 Wait for the given maximum amount of time on a monitor until either
1899 we are notified, we are interrupted, or the time is up.
1902 t............the current thread
1903 millis.......milliseconds to wait
1904 nanos........nanoseconds to wait
1907 true.........if the wait has been interrupted,
1908 false........if the wait was ended by notification or timeout
1910 *******************************************************************************/
1912 bool threads_wait_with_timeout_relative(threadobject *thread, s8 millis,
1915 struct timespec wakeupTime;
1917 /* calculate the the (latest) wakeup time */
1919 threads_calc_absolute_time(&wakeupTime, millis, nanos);
1923 return threads_wait_with_timeout(thread, &wakeupTime);
1927 /* threads_calc_absolute_time **************************************************
1929 Calculate the absolute point in time a given number of ms and ns from now.
1932 millis............milliseconds from now
1933 nanos.............nanoseconds from now
1936 *tm...............receives the timespec of the absolute point in time
1938 *******************************************************************************/
1940 static void threads_calc_absolute_time(struct timespec *tm, s8 millis, s4 nanos)
1942 if ((millis != 0x7fffffffffffffffLLU) && (millis || nanos)) {
1945 gettimeofday(&tv, NULL);
1946 tv.tv_sec += millis / 1000;
1948 nsec = tv.tv_usec * 1000 + (s4) millis * 1000000 + nanos;
1949 tm->tv_sec = tv.tv_sec + nsec / 1000000000;
1950 tm->tv_nsec = nsec % 1000000000;
1959 /* threads_thread_interrupt ****************************************************
1961 Interrupt the given thread.
1963 The thread gets the "waitcond" signal and
1964 its interrupted flag is set to true.
1967 thread............the thread to interrupt
1969 *******************************************************************************/
1971 void threads_thread_interrupt(threadobject *thread)
1973 /* Signal the thread a "waitcond" and tell it that it has been
1976 pthread_mutex_lock(&thread->waitmutex);
1978 /* Interrupt blocking system call using a signal. */
1980 pthread_kill(thread->tid, SIGHUP);
1982 if (thread->sleeping)
1983 pthread_cond_signal(&thread->waitcond);
1985 thread->interrupted = true;
1987 pthread_mutex_unlock(&thread->waitmutex);
1991 /* threads_check_if_interrupted_and_reset **************************************
1993 Check if the current thread has been interrupted and reset the
1997 true, if the current thread had been interrupted
1999 *******************************************************************************/
2001 bool threads_check_if_interrupted_and_reset(void)
2003 threadobject *thread;
2006 thread = THREADOBJECT;
2008 /* get interrupted flag */
2010 intr = thread->interrupted;
2012 /* reset interrupted flag */
2014 thread->interrupted = false;
2020 /* threads_thread_has_been_interrupted *****************************************
2022 Check if the given thread has been interrupted
2025 t............the thread to check
2028 true, if the given thread had been interrupted
2030 *******************************************************************************/
2032 bool threads_thread_has_been_interrupted(threadobject *thread)
2034 return thread->interrupted;
2038 /* threads_sleep ***************************************************************
2040 Sleep the current thread for the specified amount of time.
2042 *******************************************************************************/
2044 void threads_sleep(s8 millis, s4 nanos)
2046 threadobject *thread;
2047 struct timespec wakeupTime;
2048 bool wasinterrupted;
2050 thread = THREADOBJECT;
2052 threads_calc_absolute_time(&wakeupTime, millis, nanos);
2054 wasinterrupted = threads_wait_with_timeout(thread, &wakeupTime);
2057 exceptions_throw_interruptedexception();
2061 /* threads_yield ***************************************************************
2063 Yield to the scheduler.
2065 *******************************************************************************/
2067 void threads_yield(void)
2073 /* threads_table_dump *********************************************************
2075 Dump the threads table for debugging purposes.
2078 file..............stream to write to
2080 ******************************************************************************/
2082 #if !defined(NDEBUG) && 0
2083 static void threads_table_dump(FILE *file)
2089 pthread_mutex_lock(&threadlistlock);
2091 size = threads_table.size;
2093 fprintf(file, "======== THREADS TABLE (size %d) ========\n", size);
2095 for (i=0; i<size; ++i) {
2096 index = threads_table.table[i].nextfree;
2098 fprintf(file, "%4d: ", i);
2101 fprintf(file, "free, nextfree = %d\n", (int) index);
2104 fprintf(file, "thread %p\n", (void*) threads_table.table[i].thread);
2108 fprintf(file, "======== END OF THREADS TABLE ========\n");
2110 pthread_mutex_unlock(&threadlistlock);
2115 * These are local overrides for various environment variables in Emacs.
2116 * Please do not remove this and leave it at the end of the file, where
2117 * Emacs will automagically detect them.
2118 * ---------------------------------------------------------------------
2121 * indent-tabs-mode: t
2125 * vim:noexpandtab:sw=4:ts=4: