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
30 /* XXX cleanup these includes */
35 #include <sys/types.h>
48 #if !defined(USE_FAKE_ATOMIC_INSTRUCTIONS)
49 # include "machine-instr.h"
51 # include "threads/native/generic-primitives.h"
54 #include "mm/gc-common.h"
55 #include "mm/memory.h"
57 #if defined(ENABLE_GC_CACAO)
58 # include "mm/cacao-gc/gc.h"
61 #include "native/jni.h"
62 #include "native/llni.h"
63 #include "native/native.h"
64 #include "native/include/java_lang_Object.h"
65 #include "native/include/java_lang_String.h"
66 #include "native/include/java_lang_Throwable.h"
67 #include "native/include/java_lang_Thread.h"
69 #if defined(ENABLE_JAVASE)
70 # include "native/include/java_lang_ThreadGroup.h"
73 #if defined(WITH_CLASSPATH_GNU)
74 # include "native/include/java_lang_VMThread.h"
77 #include "threads/lock-common.h"
78 #include "threads/threads-common.h"
80 #include "threads/native/threads.h"
82 #include "toolbox/logging.h"
84 #include "vm/builtin.h"
85 #include "vm/exceptions.h"
86 #include "vm/global.h"
87 #include "vm/stringlocal.h"
90 #include "vm/jit/asmpart.h"
92 #include "vmcore/options.h"
94 #if defined(ENABLE_STATISTICS)
95 # include "vmcore/statistics.h"
98 #if !defined(__DARWIN__)
99 # if defined(__LINUX__)
100 # define GC_LINUX_THREADS
101 # elif defined(__IRIX__)
102 # define GC_IRIX_THREADS
104 # include <semaphore.h>
105 # if defined(ENABLE_GC_BOEHM)
106 # include "mm/boehm-gc/include/gc.h"
110 #if defined(ENABLE_JVMTI)
111 #include "native/jvmti/cacaodbg.h"
114 #if defined(__DARWIN__)
115 /* Darwin has no working semaphore implementation. This one is taken
119 This is a very simple semaphore implementation for darwin. It
120 is implemented in terms of pthreads calls so it isn't async signal
121 safe. This isn't a problem because signals aren't used to
122 suspend threads on darwin.
125 static int sem_init(sem_t *sem, int pshared, int value)
132 if (pthread_mutex_init(&sem->mutex, NULL) < 0)
135 if (pthread_cond_init(&sem->cond, NULL) < 0)
141 static int sem_post(sem_t *sem)
143 if (pthread_mutex_lock(&sem->mutex) < 0)
148 if (pthread_cond_signal(&sem->cond) < 0) {
149 pthread_mutex_unlock(&sem->mutex);
153 if (pthread_mutex_unlock(&sem->mutex) < 0)
159 static int sem_wait(sem_t *sem)
161 if (pthread_mutex_lock(&sem->mutex) < 0)
164 while (sem->value == 0) {
165 pthread_cond_wait(&sem->cond, &sem->mutex);
170 if (pthread_mutex_unlock(&sem->mutex) < 0)
176 static int sem_destroy(sem_t *sem)
178 if (pthread_cond_destroy(&sem->cond) < 0)
181 if (pthread_mutex_destroy(&sem->mutex) < 0)
186 #endif /* defined(__DARWIN__) */
189 /* internally used constants **************************************************/
191 /* CAUTION: Do not change these values. Boehm GC code depends on them. */
192 #define STOPWORLD_FROM_GC 1
193 #define STOPWORLD_FROM_CLASS_NUMBERING 2
196 /* startupinfo *****************************************************************
198 Struct used to pass info from threads_start_thread to
199 threads_startup_thread.
201 ******************************************************************************/
204 threadobject *thread; /* threadobject for this thread */
205 functionptr function; /* function to run in the new thread */
206 sem_t *psem; /* signals when thread has been entered */
207 /* in the thread list */
208 sem_t *psem_first; /* signals when pthread_create has returned */
212 /* prototypes *****************************************************************/
214 static void threads_calc_absolute_time(struct timespec *tm, s8 millis, s4 nanos);
217 /******************************************************************************/
218 /* GLOBAL VARIABLES */
219 /******************************************************************************/
221 static methodinfo *method_thread_init;
223 /* the thread object of the current thread */
224 /* This is either a thread-local variable defined with __thread, or */
225 /* a thread-specific value stored with key threads_current_threadobject_key. */
226 #if defined(HAVE___THREAD)
227 __thread threadobject *threads_current_threadobject;
229 pthread_key_t threads_current_threadobject_key;
232 /* global mutex for the threads table */
233 static pthread_mutex_t mutex_threads_list;
235 /* global mutex for stop-the-world */
236 static pthread_mutex_t stopworldlock;
238 /* global mutex and condition for joining threads on exit */
239 static pthread_mutex_t mutex_join;
240 static pthread_cond_t cond_join;
242 /* XXX We disable that whole bunch of code until we have the exact-GC
247 /* this is one of the STOPWORLD_FROM_ constants, telling why the world is */
249 static volatile int stopworldwhere;
251 /* semaphore used for acknowleding thread suspension */
252 static sem_t suspend_ack;
253 #if defined(__IRIX__)
254 static pthread_mutex_t suspend_ack_lock = PTHREAD_MUTEX_INITIALIZER;
255 static pthread_cond_t suspend_cond = PTHREAD_COND_INITIALIZER;
260 /* mutexes used by the fake atomic instructions */
261 #if defined(USE_FAKE_ATOMIC_INSTRUCTIONS)
262 pthread_mutex_t _atomic_add_lock = PTHREAD_MUTEX_INITIALIZER;
263 pthread_mutex_t _cas_lock = PTHREAD_MUTEX_INITIALIZER;
264 pthread_mutex_t _mb_lock = PTHREAD_MUTEX_INITIALIZER;
268 /* threads_sem_init ************************************************************
270 Initialize a semaphore. Checks against errors and interruptions.
273 sem..............the semaphore to initialize
274 shared...........true if this semaphore will be shared between processes
275 value............the initial value for the semaphore
277 *******************************************************************************/
279 void threads_sem_init(sem_t *sem, bool shared, int value)
286 r = sem_init(sem, shared, value);
289 } while (errno == EINTR);
291 vm_abort("sem_init failed: %s", strerror(errno));
295 /* threads_sem_wait ************************************************************
297 Wait for a semaphore, non-interruptible.
299 IMPORTANT: Always use this function instead of `sem_wait` directly, as
300 `sem_wait` may be interrupted by signals!
303 sem..............the semaphore to wait on
305 *******************************************************************************/
307 void threads_sem_wait(sem_t *sem)
317 } while (errno == EINTR);
319 vm_abort("sem_wait failed: %s", strerror(errno));
323 /* threads_sem_post ************************************************************
325 Increase the count of a semaphore. Checks for errors.
328 sem..............the semaphore to increase the count of
330 *******************************************************************************/
332 void threads_sem_post(sem_t *sem)
338 /* unlike sem_wait, sem_post is not interruptible */
344 vm_abort("sem_post failed: %s", strerror(errno));
348 /* lock_stopworld **************************************************************
350 Enter the stopworld lock, specifying why the world shall be stopped.
353 where........ STOPWORLD_FROM_GC (1) from within GC
354 STOPWORLD_FROM_CLASS_NUMBERING (2) class numbering
356 ******************************************************************************/
358 void lock_stopworld(int where)
360 pthread_mutex_lock(&stopworldlock);
361 /* stopworldwhere = where; */
365 /* unlock_stopworld ************************************************************
367 Release the stopworld lock.
369 ******************************************************************************/
371 void unlock_stopworld(void)
373 /* stopworldwhere = 0; */
374 pthread_mutex_unlock(&stopworldlock);
377 /* XXX We disable that whole bunch of code until we have the exact-GC
382 #if !defined(__DARWIN__)
383 /* Caller must hold threadlistlock */
384 static s4 threads_cast_sendsignals(s4 sig)
392 /* iterate over all started threads */
396 for (t = threads_list_first(); t != NULL; t = threads_list_next(t)) {
397 /* don't send the signal to ourself */
402 /* don't send the signal to NEW threads (because they are not
403 completely initialized) */
405 if (t->state == THREAD_STATE_NEW)
408 /* send the signal */
410 pthread_kill(t->tid, sig);
412 /* increase threads count */
422 static void threads_cast_darwinstop(void)
424 threadobject *tobj = mainthreadobj;
425 threadobject *self = THREADOBJECT;
430 thread_state_flavor_t flavor = MACHINE_THREAD_STATE;
431 mach_msg_type_number_t thread_state_count = MACHINE_THREAD_STATE_COUNT;
432 #if defined(__I386__)
433 i386_thread_state_t thread_state;
435 ppc_thread_state_t thread_state;
437 mach_port_t thread = tobj->mach_thread;
440 r = thread_suspend(thread);
442 if (r != KERN_SUCCESS)
443 vm_abort("thread_suspend failed");
445 r = thread_get_state(thread, flavor, (natural_t *) &thread_state,
446 &thread_state_count);
448 if (r != KERN_SUCCESS)
449 vm_abort("thread_get_state failed");
451 md_critical_section_restart((ucontext_t *) &thread_state);
453 r = thread_set_state(thread, flavor, (natural_t *) &thread_state,
456 if (r != KERN_SUCCESS)
457 vm_abort("thread_set_state failed");
461 } while (tobj != mainthreadobj);
464 static void threads_cast_darwinresume(void)
466 threadobject *tobj = mainthreadobj;
467 threadobject *self = THREADOBJECT;
472 mach_port_t thread = tobj->mach_thread;
475 r = thread_resume(thread);
477 if (r != KERN_SUCCESS)
478 vm_abort("thread_resume failed");
482 } while (tobj != mainthreadobj);
487 #if defined(__IRIX__)
488 static void threads_cast_irixresume(void)
490 pthread_mutex_lock(&suspend_ack_lock);
491 pthread_cond_broadcast(&suspend_cond);
492 pthread_mutex_unlock(&suspend_ack_lock);
497 #if defined(ENABLE_GC_BOEHM) && !defined(__DARWIN__)
498 static void threads_sigsuspend_handler(ucontext_t *_uc)
503 /* XXX TWISTI: this is just a quick hack */
504 #if defined(ENABLE_JIT)
505 md_critical_section_restart(_uc);
508 /* Do as Boehm does. On IRIX a condition variable is used for wake-up
509 (not POSIX async-safe). */
510 #if defined(__IRIX__)
511 pthread_mutex_lock(&suspend_ack_lock);
512 threads_sem_post(&suspend_ack);
513 pthread_cond_wait(&suspend_cond, &suspend_ack_lock);
514 pthread_mutex_unlock(&suspend_ack_lock);
515 #elif defined(__CYGWIN__)
522 sigdelset(&sigs, sig);
528 /* threads_stopworld ***********************************************************
530 Stops the world from turning. All threads except the calling one
531 are suspended. The function returns as soon as all threads have
532 acknowledged their suspension.
534 *******************************************************************************/
536 #if !defined(DISABLE_GC)
537 void threads_stopworld(void)
539 #if !defined(__DARWIN__) && !defined(__CYGWIN__)
546 lock_stopworld(STOPWORLD_FROM_CLASS_NUMBERING);
548 /* lock the threads lists */
552 #if defined(__DARWIN__)
553 /*threads_cast_darwinstop();*/
555 #elif defined(__CYGWIN__)
561 DEBUGTHREADS("stops World", self);
565 /* suspend all running threads */
566 for (t = threads_list_first(); t != NULL; t = threads_list_next(t)) {
567 /* don't send the signal to ourself */
572 /* don't send the signal to NEW threads (because they are not
573 completely initialized) */
575 if (t->state == THREAD_STATE_NEW)
578 /* send the signal */
580 result = threads_suspend_thread(t, SUSPEND_REASON_STOPWORLD);
583 /* increase threads count */
588 /* wait for all threads signaled to suspend */
589 for (i = 0; i < count; i++)
590 threads_sem_wait(&suspend_ack);
593 /* ATTENTION: Don't unlock the threads-lists here so that
594 non-signaled NEW threads can't change their state and execute
597 #endif /* !defined(DISABLE_GC) */
600 /* threads_startworld **********************************************************
602 Starts the world again after it has previously been stopped.
604 *******************************************************************************/
606 #if !defined(DISABLE_GC)
607 void threads_startworld(void)
609 #if !defined(__DARWIN__) && !defined(__CYGWIN__)
616 #if defined(__DARWIN__)
617 /*threads_cast_darwinresume();*/
619 #elif defined(__IRIX__)
620 threads_cast_irixresume();
621 #elif defined(__CYGWIN__)
627 DEBUGTHREADS("starts World", self);
631 /* resume all thread we haltet */
632 for (t = threads_list_first(); t != NULL; t = threads_list_next(t)) {
633 /* don't send the signal to ourself */
638 /* don't send the signal to NEW threads (because they are not
639 completely initialized) */
641 if (t->state == THREAD_STATE_NEW)
644 /* send the signal */
646 result = threads_resume_thread(t);
649 /* increase threads count */
654 /* wait for all threads signaled to suspend */
655 for (i = 0; i < count; i++)
656 threads_sem_wait(&suspend_ack);
660 /* unlock the threads lists */
662 threads_list_unlock();
669 /* threads_set_current_threadobject ********************************************
671 Set the current thread object.
674 thread.......the thread object to set
676 *******************************************************************************/
678 void threads_set_current_threadobject(threadobject *thread)
680 #if !defined(HAVE___THREAD)
681 if (pthread_setspecific(threads_current_threadobject_key, thread) != 0)
682 vm_abort("threads_set_current_threadobject: pthread_setspecific failed: %s", strerror(errno));
684 threads_current_threadobject = thread;
689 /* threads_impl_thread_new *****************************************************
691 Initialize implementation fields of a threadobject.
694 t....the threadobject
696 *******************************************************************************/
698 void threads_impl_thread_new(threadobject *t)
700 /* get the pthread id */
702 t->tid = pthread_self();
704 /* initialize the mutex and the condition */
706 pthread_mutex_init(&(t->waitmutex), NULL);
707 pthread_cond_init(&(t->waitcond), NULL);
708 pthread_mutex_init(&(t->suspendmutex), NULL);
709 pthread_cond_init(&(t->suspendcond), NULL);
711 #if defined(ENABLE_DEBUG_FILTER)
712 /* Initialize filter counters */
713 t->filterverbosecallctr[0] = 0;
714 t->filterverbosecallctr[1] = 0;
718 t->tracejavacallindent = 0;
719 t->tracejavacallcount = 0;
724 /* threads_impl_thread_free ****************************************************
726 Cleanup thread stuff.
729 t....the threadobject
731 *******************************************************************************/
733 void threads_impl_thread_free(threadobject *t)
735 /* destroy the mutex and the condition */
737 if (pthread_mutex_destroy(&(t->waitmutex)) != 0)
738 vm_abort("threads_impl_thread_free: pthread_mutex_destroy failed: %s",
741 if (pthread_cond_destroy(&(t->waitcond)) != 0)
742 vm_abort("threads_impl_thread_free: pthread_cond_destroy failed: %s",
745 if (pthread_mutex_destroy(&(t->suspendmutex)) != 0)
746 vm_abort("threads_impl_thread_free: pthread_mutex_destroy failed: %s",
749 if (pthread_cond_destroy(&(t->suspendcond)) != 0)
750 vm_abort("threads_impl_thread_free: pthread_cond_destroy failed: %s",
755 /* threads_get_current_threadobject ********************************************
757 Return the threadobject of the current thread.
760 the current threadobject *
762 *******************************************************************************/
764 threadobject *threads_get_current_threadobject(void)
770 /* threads_impl_preinit ********************************************************
772 Do some early initialization of stuff required.
774 ATTENTION: Do NOT use any Java heap allocation here, as gc_init()
775 is called AFTER this function!
777 *******************************************************************************/
779 void threads_impl_preinit(void)
781 pthread_mutex_init(&stopworldlock, NULL);
783 /* initialize exit mutex and condition (on exit we join all
786 pthread_mutex_init(&mutex_join, NULL);
787 pthread_cond_init(&cond_join, NULL);
789 /* initialize the threads-list mutex */
791 pthread_mutex_init(&mutex_threads_list, NULL);
793 #if !defined(HAVE___THREAD)
794 pthread_key_create(&threads_current_threadobject_key, NULL);
797 threads_sem_init(&suspend_ack, 0, 0);
801 /* threads_list_lock ***********************************************************
803 Enter the threads table mutex.
805 NOTE: We need this function as we can't use an internal lock for
806 the threads lists because the thread's lock is initialized in
807 threads_table_add (when we have the thread index), but we
808 already need the lock at the entry of the function.
810 *******************************************************************************/
812 void threads_list_lock(void)
814 if (pthread_mutex_lock(&mutex_threads_list) != 0)
815 vm_abort("threads_list_lock: pthread_mutex_lock failed: %s",
820 /* threads_list_unlock *********************************************************
822 Leave the threads list mutex.
824 *******************************************************************************/
826 void threads_list_unlock(void)
828 if (pthread_mutex_unlock(&mutex_threads_list) != 0)
829 vm_abort("threads_list_unlock: pthread_mutex_unlock failed: %s",
834 /* threads_mutex_join_lock *****************************************************
836 Enter the join mutex.
838 *******************************************************************************/
840 void threads_mutex_join_lock(void)
842 if (pthread_mutex_lock(&mutex_join) != 0)
843 vm_abort("threads_mutex_join_lock: pthread_mutex_lock failed: %s",
848 /* threads_mutex_join_unlock ***************************************************
850 Leave the join mutex.
852 *******************************************************************************/
854 void threads_mutex_join_unlock(void)
856 if (pthread_mutex_unlock(&mutex_join) != 0)
857 vm_abort("threads_mutex_join_unlock: pthread_mutex_unlock failed: %s",
862 /* threads_init ****************************************************************
864 Initializes the threads required by the JVM: main, finalizer.
866 *******************************************************************************/
868 bool threads_init(void)
870 threadobject *mainthread;
871 java_handle_t *threadname;
875 #if defined(ENABLE_JAVASE)
876 java_lang_ThreadGroup *threadgroup;
880 #if defined(WITH_CLASSPATH_GNU)
881 java_lang_VMThread *vmt;
886 /* get methods we need in this file */
888 #if defined(WITH_CLASSPATH_GNU)
890 class_resolveclassmethod(class_java_lang_Thread,
892 utf_new_char("(Ljava/lang/VMThread;Ljava/lang/String;IZ)V"),
893 class_java_lang_Thread,
895 #elif defined(WITH_CLASSPATH_SUN)
897 class_resolveclassmethod(class_java_lang_Thread,
899 utf_new_char("(Ljava/lang/String;)V"),
900 class_java_lang_Thread,
902 #elif defined(WITH_CLASSPATH_CLDC1_1)
904 class_resolveclassmethod(class_java_lang_Thread,
906 utf_new_char("(Ljava/lang/String;)V"),
907 class_java_lang_Thread,
910 # error unknown classpath configuration
913 if (method_thread_init == NULL)
916 /* Get the main-thread (NOTE: The main threads is always the first
917 thread in the list). */
919 mainthread = threads_list_first();
921 /* create a java.lang.Thread for the main thread */
923 t = (java_lang_Thread *) builtin_new(class_java_lang_Thread);
928 /* set the object in the internal data structure */
930 mainthread->object = LLNI_DIRECT(t);
932 #if defined(ENABLE_INTRP)
933 /* create interpreter stack */
936 MSET(intrp_main_stack, 0, u1, opt_stacksize);
937 mainthread->_global_sp = (Cell*) (intrp_main_stack + opt_stacksize);
941 threadname = javastring_new(utf_new_char("main"));
943 #if defined(ENABLE_JAVASE)
944 /* allocate and init ThreadGroup */
946 threadgroup = (java_lang_ThreadGroup *)
947 native_new_and_init(class_java_lang_ThreadGroup);
949 if (threadgroup == NULL)
953 #if defined(WITH_CLASSPATH_GNU)
954 /* create a java.lang.VMThread for the main thread */
956 vmt = (java_lang_VMThread *) builtin_new(class_java_lang_VMThread);
963 LLNI_field_set_ref(vmt, thread, t);
964 LLNI_field_set_val(vmt, vmdata, (java_lang_Object *) mainthread);
966 /* call java.lang.Thread.<init>(Ljava/lang/VMThread;Ljava/lang/String;IZ)V */
967 o = (java_handle_t *) t;
969 (void) vm_call_method(method_thread_init, o, vmt, threadname, NORM_PRIORITY,
972 #elif defined(WITH_CLASSPATH_SUN)
974 /* We trick java.lang.Thread.<init>, which sets the priority of
975 the current thread to the parent's one. */
977 t->priority = NORM_PRIORITY;
979 /* Call java.lang.Thread.<init>(Ljava/lang/String;)V */
981 o = (java_object_t *) t;
983 (void) vm_call_method(method_thread_init, o, threadname);
985 #elif defined(WITH_CLASSPATH_CLDC1_1)
989 t->vm_thread = (java_lang_Object *) mainthread;
991 /* call public Thread(String name) */
993 o = (java_handle_t *) t;
995 (void) vm_call_method(method_thread_init, o, threadname);
997 # error unknown classpath configuration
1000 if (exceptions_get_exception())
1003 #if defined(ENABLE_JAVASE)
1004 LLNI_field_set_ref(t, group, threadgroup);
1006 # if defined(WITH_CLASSPATH_GNU)
1007 /* add main thread to java.lang.ThreadGroup */
1009 m = class_resolveclassmethod(class_java_lang_ThreadGroup,
1011 utf_java_lang_Thread__V,
1012 class_java_lang_ThreadGroup,
1015 o = (java_handle_t *) threadgroup;
1017 (void) vm_call_method(m, o, t);
1019 if (exceptions_get_exception())
1022 # warning Do not know what to do here
1026 threads_set_thread_priority(pthread_self(), NORM_PRIORITY);
1028 /* initialize the thread attribute object */
1030 if (pthread_attr_init(&attr) != 0)
1031 vm_abort("threads_init: pthread_attr_init failed: %s", strerror(errno));
1033 if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
1034 vm_abort("threads_init: pthread_attr_setdetachstate failed: %s",
1037 DEBUGTHREADS("starting (main)", mainthread);
1039 /* everything's ok */
1045 /* threads_startup_thread ******************************************************
1047 Thread startup function called by pthread_create.
1049 Thread which have a startup.function != NULL are marked as internal
1050 threads. All other threads are threated as normal Java threads.
1052 NOTE: This function is not called directly by pthread_create. The Boehm GC
1053 inserts its own GC_start_routine in between, which then calls
1057 arg..........the argument passed to pthread_create, ie. a pointer to
1058 a startupinfo struct. CAUTION: When the `psem` semaphore
1059 is posted, the startupinfo struct becomes invalid! (It
1060 is allocated on the stack of threads_start_thread.)
1062 ******************************************************************************/
1064 static void *threads_startup_thread(void *arg)
1066 startupinfo *startup;
1067 threadobject *thread;
1068 java_lang_Thread *object;
1069 #if defined(WITH_CLASSPATH_GNU)
1070 java_lang_VMThread *vmt;
1076 functionptr function;
1078 #if defined(ENABLE_INTRP)
1079 u1 *intrp_thread_stack;
1081 /* create interpreter stack */
1084 intrp_thread_stack = GCMNEW(u1, opt_stacksize);
1085 MSET(intrp_thread_stack, 0, u1, opt_stacksize);
1088 intrp_thread_stack = NULL;
1091 /* get passed startupinfo structure and the values in there */
1095 thread = startup->thread;
1096 function = startup->function;
1097 psem = startup->psem;
1099 /* Seems like we've encountered a situation where thread->tid was
1100 not set by pthread_create. We alleviate this problem by waiting
1101 for pthread_create to return. */
1103 threads_sem_wait(startup->psem_first);
1105 #if defined(__DARWIN__)
1106 thread->mach_thread = mach_thread_self();
1109 /* store the internal thread data-structure in the TSD */
1111 threads_set_current_threadobject(thread);
1113 /* get the java.lang.Thread object for this thread */
1115 object = (java_lang_Thread *) LLNI_WRAP(thread->object);
1117 /* set our priority */
1119 threads_set_thread_priority(thread->tid, LLNI_field_direct(object, priority));
1121 /* thread is completely initialized */
1123 threads_thread_state_runnable(thread);
1125 /* tell threads_startup_thread that we registered ourselves */
1126 /* CAUTION: *startup becomes invalid with this! */
1129 threads_sem_post(psem);
1131 #if defined(ENABLE_INTRP)
1132 /* set interpreter stack */
1135 thread->_global_sp = (Cell *) (intrp_thread_stack + opt_stacksize);
1138 #if defined(ENABLE_JVMTI)
1139 /* fire thread start event */
1142 jvmti_ThreadStartEnd(JVMTI_EVENT_THREAD_START);
1145 DEBUGTHREADS("starting", thread);
1147 /* find and run the Thread.run()V method if no other function was passed */
1149 if (function == NULL) {
1150 #if defined(WITH_CLASSPATH_GNU)
1151 /* We need to start the run method of
1152 java.lang.VMThread. Since this is a final class, we can use
1153 the class object directly. */
1155 c = class_java_lang_VMThread;
1156 #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
1157 LLNI_class_get(object, c);
1159 # error unknown classpath configuration
1162 m = class_resolveclassmethod(c, utf_run, utf_void__void, c, true);
1165 vm_abort("threads_startup_thread: run() method not found in class");
1167 /* set ThreadMXBean variables */
1169 _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount++;
1170 _Jv_jvm->java_lang_management_ThreadMXBean_TotalStartedThreadCount++;
1172 if (_Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount >
1173 _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount)
1174 _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount =
1175 _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount;
1177 #if defined(WITH_CLASSPATH_GNU)
1178 /* we need to start the run method of java.lang.VMThread */
1180 LLNI_field_get_ref(object, vmThread, vmt);
1181 o = (java_handle_t *) vmt;
1183 #elif defined(WITH_CLASSPATH_SUN) || defined(WITH_CLASSPATH_CLDC1_1)
1184 o = (java_handle_t *) object;
1186 # error unknown classpath configuration
1189 /* run the thread */
1191 (void) vm_call_method(m, o);
1194 /* set ThreadMXBean variables */
1196 _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount++;
1197 _Jv_jvm->java_lang_management_ThreadMXBean_TotalStartedThreadCount++;
1199 if (_Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount >
1200 _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount)
1201 _Jv_jvm->java_lang_management_ThreadMXBean_PeakThreadCount =
1202 _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount;
1204 /* call passed function, e.g. finalizer_thread */
1209 DEBUGTHREADS("stopping", thread);
1211 #if defined(ENABLE_JVMTI)
1212 /* fire thread end event */
1215 jvmti_ThreadStartEnd(JVMTI_EVENT_THREAD_END);
1218 /* We ignore the return value. */
1220 (void) threads_detach_thread(thread);
1222 /* set ThreadMXBean variables */
1224 _Jv_jvm->java_lang_management_ThreadMXBean_ThreadCount--;
1230 /* threads_impl_thread_start ***************************************************
1232 Start a thread in the JVM. Both (vm internal and java) thread
1236 thread....the thread object
1237 f.........function to run in the new thread. NULL means that the
1238 "run" method of the object `t` should be called
1240 ******************************************************************************/
1242 void threads_impl_thread_start(threadobject *thread, functionptr f)
1246 pthread_attr_t attr;
1247 startupinfo startup;
1250 /* fill startupinfo structure passed by pthread_create to
1251 * threads_startup_thread */
1253 startup.thread = thread;
1254 startup.function = f; /* maybe we don't call Thread.run()V */
1255 startup.psem = &sem;
1256 startup.psem_first = &sem_first;
1258 threads_sem_init(&sem, 0, 0);
1259 threads_sem_init(&sem_first, 0, 0);
1261 /* Initialize thread attributes. */
1263 result = pthread_attr_init(&attr);
1266 vm_abort("threads_impl_thread_start: pthread_attr_init failed: %s",
1269 result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1272 vm_abort("threads_impl_thread_start: pthread_attr_setdetachstate failed: %s",
1275 /* initialize thread stacksize */
1277 result = pthread_attr_setstacksize(&attr, opt_stacksize);
1280 vm_abort("threads_impl_thread_start: pthread_attr_setstacksize failed: %s",
1283 /* create the thread */
1285 result = pthread_create(&(thread->tid), &attr, threads_startup_thread, &startup);
1288 vm_abort("threads_impl_thread_start: pthread_create failed: %s",
1291 /* destroy the thread attributes */
1293 result = pthread_attr_destroy(&attr);
1296 vm_abort("threads_impl_thread_start: pthread_attr_destroy failed: %s",
1299 /* signal that pthread_create has returned, so thread->tid is valid */
1301 threads_sem_post(&sem_first);
1303 /* wait here until the thread has entered itself into the thread list */
1305 threads_sem_wait(&sem);
1310 sem_destroy(&sem_first);
1314 /* threads_set_thread_priority *************************************************
1316 Set the priority of the given thread.
1319 tid..........thread id
1320 priority.....priority to set
1322 ******************************************************************************/
1324 void threads_set_thread_priority(pthread_t tid, int priority)
1326 struct sched_param schedp;
1329 pthread_getschedparam(tid, &policy, &schedp);
1330 schedp.sched_priority = priority;
1331 pthread_setschedparam(tid, policy, &schedp);
1335 /* threads_attach_current_thread ***********************************************
1337 Attaches the current thread to the VM. Used in JNI.
1339 *******************************************************************************/
1341 bool threads_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon)
1343 threadobject *thread;
1347 java_lang_Thread *t;
1349 #if defined(ENABLE_JAVASE)
1350 java_lang_ThreadGroup *group;
1351 threadobject *mainthread;
1352 java_lang_Thread *mainthreado;
1357 #if defined(WITH_CLASSPATH_GNU)
1358 java_lang_VMThread *vmt;
1361 /* Enter the join-mutex, so if the main-thread is currently
1362 waiting to join all threads, the number of non-daemon threads
1365 threads_mutex_join_lock();
1367 /* create internal thread data-structure */
1369 thread = threads_thread_new();
1371 /* thread is a Java thread and running */
1373 thread->flags = THREAD_FLAG_JAVA;
1376 thread->flags |= THREAD_FLAG_DAEMON;
1378 /* The thread is flagged and (non-)daemon thread, we can leave the
1381 threads_mutex_join_unlock();
1383 /* create a java.lang.Thread object */
1385 t = (java_lang_Thread *) builtin_new(class_java_lang_Thread);
1387 /* XXX memory leak!!! */
1391 thread->object = LLNI_DIRECT(t);
1393 /* thread is completely initialized */
1395 threads_thread_state_runnable(thread);
1397 DEBUGTHREADS("attaching", thread);
1399 #if defined(ENABLE_INTRP)
1400 /* create interpreter stack */
1403 MSET(intrp_main_stack, 0, u1, opt_stacksize);
1404 thread->_global_sp = (Cell *) (intrp_main_stack + opt_stacksize);
1408 #if defined(WITH_CLASSPATH_GNU)
1410 /* create a java.lang.VMThread object */
1412 vmt = (java_lang_VMThread *) builtin_new(class_java_lang_VMThread);
1414 /* XXX memory leak!!! */
1418 /* set the thread */
1420 LLNI_field_set_ref(vmt, thread, t);
1421 LLNI_field_set_val(vmt, vmdata, (java_lang_Object *) thread);
1423 #elif defined(WITH_CLASSPATH_SUN)
1425 vm_abort("threads_attach_current_thread: IMPLEMENT ME!");
1427 #elif defined(WITH_CLASSPATH_CLDC1_1)
1429 LLNI_field_set_val(t, vm_thread, (java_lang_Object *) thread);
1432 # error unknown classpath configuration
1435 if (vm_aargs != NULL) {
1436 u = utf_new_char(vm_aargs->name);
1437 #if defined(ENABLE_JAVASE)
1438 group = (java_lang_ThreadGroup *) vm_aargs->group;
1443 #if defined(ENABLE_JAVASE)
1444 /* get the main thread */
1446 mainthread = threads_list_first();
1447 mainthreado = (java_lang_Thread *) LLNI_WRAP(mainthread->object);
1448 group = LLNI_field_direct(mainthreado, group);
1452 /* the the thread name */
1454 s = javastring_new(u);
1456 /* for convenience */
1458 o = (java_handle_t *) t;
1460 #if defined(WITH_CLASSPATH_GNU)
1461 (void) vm_call_method(method_thread_init, o, vmt, s, NORM_PRIORITY,
1463 #elif defined(WITH_CLASSPATH_CLDC1_1)
1464 (void) vm_call_method(method_thread_init, o, s);
1467 if (exceptions_get_exception())
1470 #if defined(ENABLE_JAVASE)
1471 /* store the thread group in the object */
1473 LLNI_field_set_ref(t, group, group);
1475 /* add thread to given thread-group */
1477 LLNI_class_get(group, c);
1479 m = class_resolveclassmethod(c,
1481 utf_java_lang_Thread__V,
1482 class_java_lang_ThreadGroup,
1485 o = (java_handle_t *) group;
1487 (void) vm_call_method(m, o, t);
1489 if (exceptions_get_exception())
1497 /* threads_detach_thread *******************************************************
1499 Detaches the passed thread from the VM. Used in JNI.
1501 *******************************************************************************/
1503 bool threads_detach_thread(threadobject *t)
1505 #if defined(ENABLE_JAVASE)
1506 java_lang_Thread *object;
1507 java_lang_ThreadGroup *group;
1509 java_lang_Object *handler;
1515 #if defined(ENABLE_JAVASE)
1516 object = (java_lang_Thread *) LLNI_WRAP(t->object);
1518 LLNI_field_get_ref(object, group, group);
1520 /* If there's an uncaught exception, call uncaughtException on the
1521 thread's exception handler, or the thread's group if this is
1524 e = exceptions_get_and_clear_exception();
1527 /* We use a java_lang_Object here, as it's not trivial to
1528 build the java_lang_Thread_UncaughtExceptionHandler header
1531 # if defined(WITH_CLASSPATH_GNU)
1532 LLNI_field_get_ref(object, exceptionHandler, handler);
1533 # elif defined(WITH_CLASSPATH_SUN)
1534 LLNI_field_get_ref(object, uncaughtExceptionHandler, handler);
1537 if (handler != NULL) {
1538 LLNI_class_get(handler, c);
1539 o = (java_handle_t *) handler;
1542 LLNI_class_get(group, c);
1543 o = (java_handle_t *) group;
1546 m = class_resolveclassmethod(c,
1547 utf_uncaughtException,
1548 utf_java_lang_Thread_java_lang_Throwable__V,
1555 (void) vm_call_method(m, o, object, e);
1557 if (exceptions_get_exception())
1561 /* XXX TWISTI: should all threads be in a ThreadGroup? */
1563 /* Remove thread from the thread group. */
1565 if (group != NULL) {
1566 LLNI_class_get(group, c);
1568 # if defined(WITH_CLASSPATH_GNU)
1569 m = class_resolveclassmethod(c,
1571 utf_java_lang_Thread__V,
1572 class_java_lang_ThreadGroup,
1574 # elif defined(WITH_CLASSPATH_SUN)
1575 m = class_resolveclassmethod(c,
1577 utf_java_lang_Thread__V,
1578 class_java_lang_ThreadGroup,
1581 # error unknown classpath configuration
1587 o = (java_handle_t *) group;
1589 (void) vm_call_method(m, o, object);
1591 if (exceptions_get_exception())
1596 /* Thread has terminated. */
1598 threads_thread_state_terminated(t);
1600 DEBUGTHREADS("detaching", t);
1602 /* Notify all threads waiting on this thread. These are joining
1605 o = (java_object_t *) object;
1607 /* XXX Care about exceptions? */
1608 (void) lock_monitor_enter(o);
1610 lock_notify_all_object(o);
1612 /* XXX Care about exceptions? */
1613 (void) lock_monitor_exit(o);
1615 /* Enter the join-mutex before calling threads_thread_free, so
1616 threads_join_all_threads gets the correct number of non-daemon
1619 threads_mutex_join_lock();
1621 /* free the vm internal thread object */
1623 threads_thread_free(t);
1625 /* Signal that this thread has finished and leave the mutex. */
1627 pthread_cond_signal(&cond_join);
1628 threads_mutex_join_unlock();
1634 /* threads_suspend_thread ******************************************************
1636 Suspend the passed thread. Execution stops until the thread
1637 is explicitly resumend again.
1640 reason.....Reason for suspending this thread.
1642 *******************************************************************************/
1644 bool threads_suspend_thread(threadobject *thread, s4 reason)
1646 /* acquire the suspendmutex */
1647 if (pthread_mutex_lock(&(thread->suspendmutex)) != 0)
1648 vm_abort("threads_suspend_thread: pthread_mutex_lock failed: %s",
1651 if (thread->suspended) {
1652 pthread_mutex_unlock(&(thread->suspendmutex));
1656 /* set the reason for the suspension */
1657 thread->suspend_reason = reason;
1659 /* send the suspend signal to the thread */
1660 assert(thread != THREADOBJECT);
1661 if (pthread_kill(thread->tid, SIGUSR1) != 0)
1662 vm_abort("threads_suspend_thread: pthread_kill failed: %s",
1665 /* REMEMBER: do not release the suspendmutex, this is done
1666 by the thread itself in threads_suspend_ack(). */
1672 /* threads_suspend_ack *********************************************************
1674 Acknowledges the suspension of the current thread.
1677 pc.....The PC where the thread suspended its execution.
1678 sp.....The SP before the thread suspended its execution.
1680 *******************************************************************************/
1682 void threads_suspend_ack(u1* pc, u1* sp)
1684 threadobject *thread;
1686 thread = THREADOBJECT;
1688 assert(thread->suspend_reason != 0);
1690 /* TODO: remember dump memory size */
1692 #if defined(ENABLE_GC_CACAO)
1693 /* inform the GC about the suspension */
1694 if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD && gc_pending) {
1696 /* check if the GC wants to leave the thread running */
1697 if (!gc_suspend(thread, pc, sp)) {
1699 /* REMEMBER: we do not unlock the suspendmutex because the thread
1700 will suspend itself again at a later time */
1707 /* mark this thread as suspended and remember the PC */
1709 thread->suspended = true;
1711 /* if we are stopping the world, we should send a global ack */
1712 if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD) {
1713 threads_sem_post(&suspend_ack);
1716 DEBUGTHREADS("suspending", thread);
1718 /* release the suspension mutex and wait till we are resumed */
1719 pthread_cond_wait(&(thread->suspendcond), &(thread->suspendmutex));
1721 DEBUGTHREADS("resuming", thread);
1723 /* if we are stopping the world, we should send a global ack */
1724 if (thread->suspend_reason == SUSPEND_REASON_STOPWORLD) {
1725 threads_sem_post(&suspend_ack);
1728 /* TODO: free dump memory */
1730 /* release the suspendmutex */
1731 if (pthread_mutex_unlock(&(thread->suspendmutex)) != 0)
1732 vm_abort("threads_suspend_ack: pthread_mutex_unlock failed: %s",
1737 /* threads_resume_thread *******************************************************
1739 Resumes the execution of the passed thread.
1741 *******************************************************************************/
1743 bool threads_resume_thread(threadobject *thread)
1745 /* acquire the suspendmutex */
1746 if (pthread_mutex_lock(&(thread->suspendmutex)) != 0)
1747 vm_abort("threads_resume_ack: pthread_mutex_unlock failed: %s",
1750 if (!thread->suspended) {
1751 pthread_mutex_unlock(&(thread->suspendmutex));
1755 thread->suspended = false;
1757 /* tell everyone that the thread should resume */
1758 assert(thread != THREADOBJECT);
1759 pthread_cond_broadcast(&(thread->suspendcond));
1761 /* release the suspendmutex */
1762 pthread_mutex_unlock(&(thread->suspendmutex));
1768 /* threads_join_all_threads ****************************************************
1770 Join all non-daemon threads.
1772 *******************************************************************************/
1774 void threads_join_all_threads(void)
1778 /* get current thread */
1782 /* this thread is waiting for all non-daemon threads to exit */
1784 threads_thread_state_waiting(t);
1786 /* enter join mutex */
1788 threads_mutex_join_lock();
1790 /* Wait for condition as long as we have non-daemon threads. We
1791 compare against 1 because the current (main thread) is also a
1792 non-daemon thread. */
1794 while (threads_list_get_non_daemons() > 1)
1795 pthread_cond_wait(&cond_join, &mutex_join);
1797 /* leave join mutex */
1799 threads_mutex_join_unlock();
1803 /* threads_timespec_earlier ****************************************************
1805 Return true if timespec tv1 is earlier than timespec tv2.
1808 tv1..........first timespec
1809 tv2..........second timespec
1812 true, if the first timespec is earlier
1814 *******************************************************************************/
1816 static inline bool threads_timespec_earlier(const struct timespec *tv1,
1817 const struct timespec *tv2)
1819 return (tv1->tv_sec < tv2->tv_sec)
1821 (tv1->tv_sec == tv2->tv_sec && tv1->tv_nsec < tv2->tv_nsec);
1825 /* threads_current_time_is_earlier_than ****************************************
1827 Check if the current time is earlier than the given timespec.
1830 tv...........the timespec to compare against
1833 true, if the current time is earlier
1835 *******************************************************************************/
1837 static bool threads_current_time_is_earlier_than(const struct timespec *tv)
1839 struct timeval tvnow;
1840 struct timespec tsnow;
1842 /* get current time */
1844 if (gettimeofday(&tvnow, NULL) != 0)
1845 vm_abort("gettimeofday failed: %s\n", strerror(errno));
1847 /* convert it to a timespec */
1849 tsnow.tv_sec = tvnow.tv_sec;
1850 tsnow.tv_nsec = tvnow.tv_usec * 1000;
1852 /* compare current time with the given timespec */
1854 return threads_timespec_earlier(&tsnow, tv);
1858 /* threads_wait_with_timeout ***************************************************
1860 Wait until the given point in time on a monitor until either
1861 we are notified, we are interrupted, or the time is up.
1864 t............the current thread
1865 wakeupTime...absolute (latest) wakeup time
1866 If both tv_sec and tv_nsec are zero, this function
1867 waits for an unlimited amount of time.
1870 true.........if the wait has been interrupted,
1871 false........if the wait was ended by notification or timeout
1873 *******************************************************************************/
1875 static bool threads_wait_with_timeout(threadobject *t, struct timespec *wakeupTime)
1877 bool wasinterrupted;
1879 /* acquire the waitmutex */
1881 pthread_mutex_lock(&t->waitmutex);
1883 /* mark us as sleeping */
1887 /* wait on waitcond */
1889 if (wakeupTime->tv_sec || wakeupTime->tv_nsec) {
1891 while (!t->interrupted && !t->signaled
1892 && threads_current_time_is_earlier_than(wakeupTime))
1894 threads_thread_state_timed_waiting(t);
1896 pthread_cond_timedwait(&t->waitcond, &t->waitmutex,
1899 threads_thread_state_runnable(t);
1904 while (!t->interrupted && !t->signaled) {
1905 threads_thread_state_waiting(t);
1907 pthread_cond_wait(&t->waitcond, &t->waitmutex);
1909 threads_thread_state_runnable(t);
1913 /* check if we were interrupted */
1915 wasinterrupted = t->interrupted;
1917 /* reset all flags */
1919 t->interrupted = false;
1920 t->signaled = false;
1921 t->sleeping = false;
1923 /* release the waitmutex */
1925 pthread_mutex_unlock(&t->waitmutex);
1927 return wasinterrupted;
1931 /* threads_wait_with_timeout_relative ******************************************
1933 Wait for the given maximum amount of time on a monitor until either
1934 we are notified, we are interrupted, or the time is up.
1937 t............the current thread
1938 millis.......milliseconds to wait
1939 nanos........nanoseconds to wait
1942 true.........if the wait has been interrupted,
1943 false........if the wait was ended by notification or timeout
1945 *******************************************************************************/
1947 bool threads_wait_with_timeout_relative(threadobject *thread, s8 millis,
1950 struct timespec wakeupTime;
1952 /* calculate the the (latest) wakeup time */
1954 threads_calc_absolute_time(&wakeupTime, millis, nanos);
1958 return threads_wait_with_timeout(thread, &wakeupTime);
1962 /* threads_calc_absolute_time **************************************************
1964 Calculate the absolute point in time a given number of ms and ns from now.
1967 millis............milliseconds from now
1968 nanos.............nanoseconds from now
1971 *tm...............receives the timespec of the absolute point in time
1973 *******************************************************************************/
1975 static void threads_calc_absolute_time(struct timespec *tm, s8 millis, s4 nanos)
1977 if ((millis != 0x7fffffffffffffffLLU) && (millis || nanos)) {
1980 gettimeofday(&tv, NULL);
1981 tv.tv_sec += millis / 1000;
1983 nsec = tv.tv_usec * 1000 + (s4) millis * 1000000 + nanos;
1984 tm->tv_sec = tv.tv_sec + nsec / 1000000000;
1985 tm->tv_nsec = nsec % 1000000000;
1994 /* threads_thread_interrupt ****************************************************
1996 Interrupt the given thread.
1998 The thread gets the "waitcond" signal and
1999 its interrupted flag is set to true.
2002 thread............the thread to interrupt
2004 *******************************************************************************/
2006 void threads_thread_interrupt(threadobject *thread)
2008 /* Signal the thread a "waitcond" and tell it that it has been
2011 pthread_mutex_lock(&thread->waitmutex);
2013 DEBUGTHREADS("interrupted", thread);
2015 /* Interrupt blocking system call using a signal. */
2017 pthread_kill(thread->tid, SIGHUP);
2019 if (thread->sleeping)
2020 pthread_cond_signal(&thread->waitcond);
2022 thread->interrupted = true;
2024 pthread_mutex_unlock(&thread->waitmutex);
2028 /* threads_check_if_interrupted_and_reset **************************************
2030 Check if the current thread has been interrupted and reset the
2034 true, if the current thread had been interrupted
2036 *******************************************************************************/
2038 bool threads_check_if_interrupted_and_reset(void)
2040 threadobject *thread;
2043 thread = THREADOBJECT;
2045 /* get interrupted flag */
2047 intr = thread->interrupted;
2049 /* reset interrupted flag */
2051 thread->interrupted = false;
2057 /* threads_thread_has_been_interrupted *****************************************
2059 Check if the given thread has been interrupted
2062 t............the thread to check
2065 true, if the given thread had been interrupted
2067 *******************************************************************************/
2069 bool threads_thread_has_been_interrupted(threadobject *thread)
2071 return thread->interrupted;
2075 /* threads_sleep ***************************************************************
2077 Sleep the current thread for the specified amount of time.
2079 *******************************************************************************/
2081 void threads_sleep(s8 millis, s4 nanos)
2083 threadobject *thread;
2084 struct timespec wakeupTime;
2085 bool wasinterrupted;
2087 thread = THREADOBJECT;
2089 threads_calc_absolute_time(&wakeupTime, millis, nanos);
2091 wasinterrupted = threads_wait_with_timeout(thread, &wakeupTime);
2094 exceptions_throw_interruptedexception();
2098 /* threads_yield ***************************************************************
2100 Yield to the scheduler.
2102 *******************************************************************************/
2104 void threads_yield(void)
2111 * These are local overrides for various environment variables in Emacs.
2112 * Please do not remove this and leave it at the end of the file, where
2113 * Emacs will automagically detect them.
2114 * ---------------------------------------------------------------------
2117 * indent-tabs-mode: t
2121 * vim:noexpandtab:sw=4:ts=4: