* src/threads/native/threads.c (threads_startup_thread): Allocate Java
[cacao.git] / src / threads / native / threads.c
1 /* src/threads/native/threads.c - native threads support
2
3    Copyright (C) 1996-2005, 2006 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
7
8    This file is part of CACAO.
9
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.
14
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.
19
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
23    02110-1301, USA.
24
25    Contact: cacao@cacaojvm.org
26
27    Authors: Stefan Ring
28
29    Changes: Christian Thalinger
30                         Edwin Steiner
31
32    $Id: threads.c 4948 2006-05-24 14:11:16Z twisti $
33
34 */
35
36
37 #include "config.h"
38
39 /* XXX cleanup these includes */
40
41 #include <stdlib.h>
42 #include <string.h>
43 #include <assert.h>
44 #include <sys/types.h>
45 #include <unistd.h>
46 #include <signal.h>
47 #include <sys/time.h>
48 #include <time.h>
49 #include <errno.h>
50
51 #include <pthread.h>
52
53 #include "vm/types.h"
54
55 #include "arch.h"
56
57 #if !defined(USE_FAKE_ATOMIC_INSTRUCTIONS)
58 # include "machine-instr.h"
59 #else
60 # include "threads/native/generic-primitives.h"
61 #endif
62
63 #include "mm/boehm.h"
64 #include "mm/memory.h"
65 #include "native/native.h"
66 #include "native/include/java_lang_Object.h"
67 #include "native/include/java_lang_Throwable.h"
68 #include "native/include/java_lang_Thread.h"
69 #include "native/include/java_lang_ThreadGroup.h"
70 #include "native/include/java_lang_VMThread.h"
71 #include "threads/native/threads.h"
72 #include "toolbox/avl.h"
73 #include "toolbox/logging.h"
74 #include "vm/builtin.h"
75 #include "vm/exceptions.h"
76 #include "vm/global.h"
77 #include "vm/loader.h"
78 #include "vm/options.h"
79 #include "vm/stringlocal.h"
80 #include "vm/vm.h"
81 #include "vm/jit/asmpart.h"
82
83 #if !defined(__DARWIN__)
84 # if defined(__LINUX__)
85 #  define GC_LINUX_THREADS
86 # elif defined(__MIPS__)
87 #  define GC_IRIX_THREADS
88 # endif
89 # include <semaphore.h>
90 # include "boehm-gc/include/gc.h"
91 #endif
92
93
94 #if defined(__DARWIN__)
95 /* Darwin has no working semaphore implementation.  This one is taken
96    from Boehm-GC. */
97
98 /*
99    This is a very simple semaphore implementation for darwin. It
100    is implemented in terms of pthreads calls so it isn't async signal
101    safe. This isn't a problem because signals aren't used to
102    suspend threads on darwin.
103 */
104    
105 static int sem_init(sem_t *sem, int pshared, int value)
106 {
107         if (pshared)
108                 assert(0);
109
110         sem->value = value;
111     
112         if (pthread_mutex_init(&sem->mutex, NULL) < 0)
113                 return -1;
114
115         if (pthread_cond_init(&sem->cond, NULL) < 0)
116                 return -1;
117
118         return 0;
119 }
120
121 static int sem_post(sem_t *sem)
122 {
123         if (pthread_mutex_lock(&sem->mutex) < 0)
124                 return -1;
125
126         sem->value++;
127
128         if (pthread_cond_signal(&sem->cond) < 0) {
129                 pthread_mutex_unlock(&sem->mutex);
130                 return -1;
131         }
132
133         if (pthread_mutex_unlock(&sem->mutex) < 0)
134                 return -1;
135
136         return 0;
137 }
138
139 static int sem_wait(sem_t *sem)
140 {
141         if (pthread_mutex_lock(&sem->mutex) < 0)
142                 return -1;
143
144         while (sem->value == 0) {
145                 pthread_cond_wait(&sem->cond, &sem->mutex);
146         }
147
148         sem->value--;
149
150         if (pthread_mutex_unlock(&sem->mutex) < 0)
151                 return -1;    
152
153         return 0;
154 }
155
156 static int sem_destroy(sem_t *sem)
157 {
158         if (pthread_cond_destroy(&sem->cond) < 0)
159                 return -1;
160
161         if (pthread_mutex_destroy(&sem->mutex) < 0)
162                 return -1;
163
164         return 0;
165 }
166 #endif /* defined(__DARWIN__) */
167
168
169 /* internally used constants **************************************************/
170
171 /* CAUTION: Do not change these values. Boehm GC code depends on them.        */
172 #define STOPWORLD_FROM_GC               1
173 #define STOPWORLD_FROM_CLASS_NUMBERING  2
174
175 #define THREADS_INITIAL_TABLE_SIZE      8
176
177
178 /* startupinfo *****************************************************************
179
180    Struct used to pass info from threads_start_thread to 
181    threads_startup_thread.
182
183 ******************************************************************************/
184
185 typedef struct {
186         threadobject *thread;      /* threadobject for this thread             */
187         functionptr   function;    /* function to run in the new thread        */
188         sem_t        *psem;        /* signals when thread has been entered     */
189                                    /* in the thread list                       */
190         sem_t        *psem_first;  /* signals when pthread_create has returned */
191 } startupinfo;
192
193
194 /* prototypes *****************************************************************/
195
196 static void threads_table_init(void);
197 static s4 threads_table_add(threadobject *thread);
198 static void threads_table_remove(threadobject *thread);
199 static void threads_calc_absolute_time(struct timespec *tm, s8 millis, s4 nanos);
200
201 #if !defined(NDEBUG)
202 static void threads_table_dump(FILE *file);
203 #endif
204
205 /******************************************************************************/
206 /* GLOBAL VARIABLES                                                           */
207 /******************************************************************************/
208
209 /* the main thread                                                            */
210 threadobject *mainthreadobj;
211
212 /* the thread object of the current thread                                    */
213 /* This is either a thread-local variable defined with __thread, or           */
214 /* a thread-specific value stored with key threads_current_threadobject_key.  */
215 #if defined(HAVE___THREAD)
216 __thread threadobject *threads_current_threadobject;
217 #else
218 pthread_key_t threads_current_threadobject_key;
219 #endif
220
221 /* global threads table                                                       */
222 static threads_table_t threads_table;
223
224 /* global compiler mutex                                                      */
225 static pthread_mutex_rec_t compiler_mutex;
226
227 /* global mutex for changing the thread list                                  */
228 static pthread_mutex_t threadlistlock;
229
230 /* global mutex for stop-the-world                                            */
231 static pthread_mutex_t stopworldlock;
232
233 /* this is one of the STOPWORLD_FROM_ constants, telling why the world is     */
234 /* being stopped                                                              */
235 static volatile int stopworldwhere;
236
237 /* semaphore used for acknowleding thread suspension                          */
238 static sem_t suspend_ack;
239 #if defined(__MIPS__)
240 static pthread_mutex_t suspend_ack_lock = PTHREAD_MUTEX_INITIALIZER;
241 static pthread_cond_t suspend_cond = PTHREAD_COND_INITIALIZER;
242 #endif
243
244 static pthread_attr_t threadattr;
245
246 /* mutexes used by the fake atomic instructions                               */
247 #if defined(USE_FAKE_ATOMIC_INSTRUCTIONS)
248 pthread_mutex_t _atomic_add_lock = PTHREAD_MUTEX_INITIALIZER;
249 pthread_mutex_t _cas_lock = PTHREAD_MUTEX_INITIALIZER;
250 pthread_mutex_t _mb_lock = PTHREAD_MUTEX_INITIALIZER;
251 #endif
252
253
254 /******************************************************************************/
255 /* Recursive Mutex Implementation for Darwin                                  */
256 /******************************************************************************/
257
258 #if defined(MUTEXSIM)
259
260 /* We need this for older MacOSX (10.1.x) */
261
262 void pthread_mutex_init_rec(pthread_mutex_rec_t *m)
263 {
264         pthread_mutex_init(&m->mutex, NULL);
265         m->count = 0;
266 }
267
268 void pthread_mutex_destroy_rec(pthread_mutex_rec_t *m)
269 {
270         pthread_mutex_destroy(&m->mutex);
271 }
272
273 void pthread_mutex_lock_rec(pthread_mutex_rec_t *m)
274 {
275         for (;;) {
276                 if (!m->count)
277                 {
278                         pthread_mutex_lock(&m->mutex);
279                         m->owner = pthread_self();
280                         m->count++;
281                         break;
282                 }
283                 else {
284                         if (m->owner != pthread_self()) {
285                                 pthread_mutex_lock(&m->mutex);
286                         }
287                         else {
288                                 m->count++;
289                                 break;
290                         }
291                 }
292         }
293 }
294
295 void pthread_mutex_unlock_rec(pthread_mutex_rec_t *m)
296 {
297         if (!--m->count)
298                 pthread_mutex_unlock(&m->mutex);
299 }
300
301 #endif /* defined(MUTEXSIM) */
302
303
304 /* threads_sem_init ************************************************************
305  
306    Initialize a semaphore. Checks against errors and interruptions.
307
308    IN:
309        sem..............the semaphore to initialize
310            shared...........true if this semaphore will be shared between processes
311            value............the initial value for the semaphore
312    
313 *******************************************************************************/
314
315 void threads_sem_init(sem_t *sem, bool shared, int value)
316 {
317         int r;
318
319         assert(sem);
320
321         do {
322                 r = sem_init(sem, shared, value);
323                 if (r == 0)
324                         return;
325         } while (errno == EINTR);
326
327         vm_abort("sem_init failed: %s", strerror(errno));
328 }
329
330
331 /* threads_sem_wait ************************************************************
332  
333    Wait for a semaphore, non-interruptible.
334
335    IMPORTANT: Always use this function instead of `sem_wait` directly, as
336               `sem_wait` may be interrupted by signals!
337   
338    IN:
339        sem..............the semaphore to wait on
340    
341 *******************************************************************************/
342
343 void threads_sem_wait(sem_t *sem)
344 {
345         int r;
346
347         assert(sem);
348
349         do {
350                 r = sem_wait(sem);
351                 if (r == 0)
352                         return;
353         } while (errno == EINTR);
354
355         vm_abort("sem_wait failed: %s", strerror(errno));
356 }
357
358
359 /* threads_sem_post ************************************************************
360  
361    Increase the count of a semaphore. Checks for errors.
362
363    IN:
364        sem..............the semaphore to increase the count of
365    
366 *******************************************************************************/
367
368 void threads_sem_post(sem_t *sem)
369 {
370         int r;
371
372         assert(sem);
373
374         /* unlike sem_wait, sem_post is not interruptible */
375
376         r = sem_post(sem);
377         if (r == 0)
378                 return;
379
380         vm_abort("sem_post failed: %s", strerror(errno));
381 }
382
383
384 /* threads_set_thread_priority *************************************************
385
386    Set the priority of the given thread.
387
388    IN:
389       tid..........thread id
390           priority.....priority to set
391
392 ******************************************************************************/
393
394 static void threads_set_thread_priority(pthread_t tid, int priority)
395 {
396         struct sched_param schedp;
397         int policy;
398
399         pthread_getschedparam(tid, &policy, &schedp);
400         schedp.sched_priority = priority;
401         pthread_setschedparam(tid, policy, &schedp);
402 }
403
404
405 /* compiler_lock ***************************************************************
406
407    Enter the compiler lock.
408
409 ******************************************************************************/
410
411 void compiler_lock(void)
412 {
413         pthread_mutex_lock_rec(&compiler_mutex);
414 }
415
416
417 /* compiler_unlock *************************************************************
418
419    Release the compiler lock.
420
421 ******************************************************************************/
422
423 void compiler_unlock(void)
424 {
425         pthread_mutex_unlock_rec(&compiler_mutex);
426 }
427
428
429 /* lock_stopworld **************************************************************
430
431    Enter the stopworld lock, specifying why the world shall be stopped.
432
433    IN:
434       where........ STOPWORLD_FROM_GC              (1) from within GC
435                     STOPWORLD_FROM_CLASS_NUMBERING (2) class numbering
436
437 ******************************************************************************/
438
439 void lock_stopworld(int where)
440 {
441         pthread_mutex_lock(&stopworldlock);
442         stopworldwhere = where;
443 }
444
445
446 /* unlock_stopworld ************************************************************
447
448    Release the stopworld lock.
449
450 ******************************************************************************/
451
452 void unlock_stopworld(void)
453 {
454         stopworldwhere = 0;
455         pthread_mutex_unlock(&stopworldlock);
456 }
457
458 #if !defined(__DARWIN__)
459 /* Caller must hold threadlistlock */
460 static int threads_cast_sendsignals(int sig, int count)
461 {
462         /* Count threads */
463         threadobject *tobj = mainthreadobj;
464         threadobject *self = THREADOBJECT;
465
466         if (count == 0) {
467                 do {
468                         count++;
469                         tobj = tobj->next;
470                 } while (tobj != mainthreadobj);
471         }
472
473         assert(tobj == mainthreadobj);
474
475         do {
476                 if (tobj != self)
477                         pthread_kill(tobj->tid, sig);
478                 tobj = tobj->next;
479         } while (tobj != mainthreadobj);
480
481         return count - 1;
482 }
483
484 #else
485
486 static void threads_cast_darwinstop(void)
487 {
488         threadobject *tobj = mainthreadobj;
489         threadobject *self = THREADOBJECT;
490
491         do {
492                 if (tobj != self)
493                 {
494                         thread_state_flavor_t flavor = PPC_THREAD_STATE;
495                         mach_msg_type_number_t thread_state_count = PPC_THREAD_STATE_COUNT;
496                         ppc_thread_state_t thread_state;
497                         mach_port_t thread = tobj->mach_thread;
498                         kern_return_t r;
499
500                         r = thread_suspend(thread);
501                         if (r != KERN_SUCCESS) {
502                                 log_text("thread_suspend failed");
503                                 assert(0);
504                         }
505
506                         r = thread_get_state(thread, flavor,
507                                 (natural_t*)&thread_state, &thread_state_count);
508                         if (r != KERN_SUCCESS) {
509                                 log_text("thread_get_state failed");
510                                 assert(0);
511                         }
512
513                         thread_restartcriticalsection(&thread_state);
514
515                         r = thread_set_state(thread, flavor,
516                                 (natural_t*)&thread_state, thread_state_count);
517                         if (r != KERN_SUCCESS) {
518                                 log_text("thread_set_state failed");
519                                 assert(0);
520                         }
521                 }
522                 tobj = tobj->next;
523         } while (tobj != mainthreadobj);
524 }
525
526 static void threads_cast_darwinresume(void)
527 {
528         threadobject *tobj = mainthreadobj;
529         threadobject *self = THREADOBJECT;
530
531         do {
532                 if (tobj != self)
533                 {
534                         mach_port_t thread = tobj->mach_thread;
535                         kern_return_t r;
536
537                         r = thread_resume(thread);
538                         if (r != KERN_SUCCESS) {
539                                 log_text("thread_resume failed");
540                                 assert(0);
541                         }
542                 }
543                 tobj = tobj->next;
544         } while (tobj != mainthreadobj);
545 }
546
547 #endif
548
549 #if defined(__MIPS__)
550 static void threads_cast_irixresume(void)
551 {
552         pthread_mutex_lock(&suspend_ack_lock);
553         pthread_cond_broadcast(&suspend_cond);
554         pthread_mutex_unlock(&suspend_ack_lock);
555 }
556 #endif
557
558 void threads_cast_stopworld(void)
559 {
560         int count, i;
561         lock_stopworld(STOPWORLD_FROM_CLASS_NUMBERING);
562         pthread_mutex_lock(&threadlistlock);
563 #if defined(__DARWIN__)
564         threads_cast_darwinstop();
565 #else
566         count = threads_cast_sendsignals(GC_signum1(), 0);
567         for (i=0; i<count; i++)
568                 threads_sem_wait(&suspend_ack);
569 #endif
570         pthread_mutex_unlock(&threadlistlock);
571 }
572
573 void threads_cast_startworld(void)
574 {
575         pthread_mutex_lock(&threadlistlock);
576 #if defined(__DARWIN__)
577         threads_cast_darwinresume();
578 #elif defined(__MIPS__)
579         threads_cast_irixresume();
580 #else
581         threads_cast_sendsignals(GC_signum2(), -1);
582 #endif
583         pthread_mutex_unlock(&threadlistlock);
584         unlock_stopworld();
585 }
586
587 #if !defined(__DARWIN__)
588 static void threads_sigsuspend_handler(ucontext_t *ctx)
589 {
590         int sig;
591         sigset_t sigs;
592
593         /* XXX TWISTI: this is just a quick hack */
594 #if defined(ENABLE_JIT)
595         thread_restartcriticalsection(ctx);
596 #endif
597
598         /* Do as Boehm does. On IRIX a condition variable is used for wake-up
599            (not POSIX async-safe). */
600 #if defined(__IRIX__)
601         pthread_mutex_lock(&suspend_ack_lock);
602         threads_sem_post(&suspend_ack);
603         pthread_cond_wait(&suspend_cond, &suspend_ack_lock);
604         pthread_mutex_unlock(&suspend_ack_lock);
605 #else
606         threads_sem_post(&suspend_ack);
607
608         sig = GC_signum2();
609         sigfillset(&sigs);
610         sigdelset(&sigs, sig);
611         sigsuspend(&sigs);
612 #endif
613 }
614
615 /* This function is called from Boehm GC code. */
616
617 int cacao_suspendhandler(ucontext_t *ctx)
618 {
619         if (stopworldwhere != STOPWORLD_FROM_CLASS_NUMBERING)
620                 return 0;
621
622         threads_sigsuspend_handler(ctx);
623         return 1;
624 }
625 #endif
626
627 /* threads_set_current_threadobject ********************************************
628
629    Set the current thread object.
630    
631    IN:
632       thread.......the thread object to set
633
634 *******************************************************************************/
635
636 static void threads_set_current_threadobject(threadobject *thread)
637 {
638 #if !defined(HAVE___THREAD)
639         pthread_setspecific(threads_current_threadobject_key, thread);
640 #else
641         threads_current_threadobject = thread;
642 #endif
643 }
644
645
646 /* threads_get_current_threadobject ********************************************
647
648    Return the threadobject of the current thread.
649    
650    RETURN VALUE:
651        the current threadobject * (an instance of java.lang.VMThread)
652
653 *******************************************************************************/
654
655 threadobject *threads_get_current_threadobject(void)
656 {
657         return THREADOBJECT;
658 }
659
660
661 /* threads_preinit *************************************************************
662
663    Do some early initialization of stuff required.
664
665 *******************************************************************************/
666
667 void threads_preinit(void)
668 {
669 #ifndef MUTEXSIM
670         pthread_mutexattr_t mutexattr;
671         pthread_mutexattr_init(&mutexattr);
672         pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
673         pthread_mutex_init(&compiler_mutex, &mutexattr);
674         pthread_mutexattr_destroy(&mutexattr);
675 #else
676         pthread_mutex_init_rec(&compiler_mutex);
677 #endif
678
679         pthread_mutex_init(&threadlistlock, NULL);
680         pthread_mutex_init(&stopworldlock, NULL);
681
682         /* Allocate something so the garbage collector's signal handlers
683            are installed. */
684         heap_allocate(1, false, NULL);
685
686         mainthreadobj = NEW(threadobject);
687         mainthreadobj->tid = pthread_self();
688         mainthreadobj->index = 1;
689         mainthreadobj->thinlock = lock_pre_compute_thinlock(mainthreadobj->index);
690         
691 #if !defined(HAVE___THREAD)
692         pthread_key_create(&threads_current_threadobject_key, NULL);
693 #endif
694         threads_set_current_threadobject(mainthreadobj);
695
696         threads_sem_init(&suspend_ack, 0, 0);
697
698         /* initialize the threads table */
699
700         threads_table_init();
701
702         /* initialize subsystems */
703
704         lock_init();
705
706         critical_init();
707 }
708
709
710 /* threads_init ****************************************************************
711
712    Initializes the threads required by the JVM: main, finalizer.
713
714 *******************************************************************************/
715
716 bool threads_init(void)
717 {
718         java_lang_String      *threadname;
719         java_lang_Thread      *mainthread;
720         java_lang_ThreadGroup *threadgroup;
721         threadobject          *tempthread;
722         methodinfo            *method;
723
724         tempthread = mainthreadobj;
725
726         /* XXX We have to find a new way to free lock records */
727         /*     with the new locking algorithm.                */
728         /* lock_record_free_pools(mainthreadobj->ee.lockrecordpools); */
729
730         /* This is kinda tricky, we grow the java.lang.Thread object so we
731            can keep the execution environment there. No Thread object must
732            have been created at an earlier time. */
733
734         class_java_lang_VMThread->instancesize = sizeof(threadobject);
735
736         /* create a VMThread */
737
738         mainthreadobj = (threadobject *) builtin_new(class_java_lang_VMThread);
739
740         if (mainthreadobj == NULL)
741                 return false;
742
743         FREE(tempthread, threadobject);
744
745         threads_init_threadobject(&mainthreadobj->o);
746
747         threads_set_current_threadobject(mainthreadobj);
748
749         lock_init_execution_env(mainthreadobj);
750
751         mainthreadobj->next = mainthreadobj;
752         mainthreadobj->prev = mainthreadobj;
753
754         threads_table_add(mainthreadobj);
755
756 #if defined(ENABLE_INTRP)
757         /* create interpreter stack */
758
759         if (opt_intrp) {
760                 MSET(intrp_main_stack, 0, u1, opt_stacksize);
761                 mainthreadobj->_global_sp = intrp_main_stack + opt_stacksize;
762         }
763 #endif
764
765         threadname = javastring_new(utf_new_char("main"));
766
767         /* allocate and init ThreadGroup */
768
769         threadgroup = (java_lang_ThreadGroup *)
770                 native_new_and_init(class_java_lang_ThreadGroup);
771
772         if (!threadgroup)
773                 throw_exception_exit();
774
775         /* create a Thread */
776
777         mainthread = (java_lang_Thread *) builtin_new(class_java_lang_Thread);
778
779         if (mainthread == NULL)
780                 throw_exception_exit();
781
782         mainthreadobj->o.thread = mainthread;
783
784         /* call Thread.<init>(Ljava/lang/VMThread;Ljava/lang/String;IZ)V */
785
786         method = class_resolveclassmethod(class_java_lang_Thread,
787                                                                           utf_init,
788                                                                           utf_new_char("(Ljava/lang/VMThread;Ljava/lang/String;IZ)V"),
789                                                                           class_java_lang_Thread,
790                                                                           true);
791
792         if (method == NULL)
793                 return false;
794
795         (void) vm_call_method(method, (java_objectheader *) mainthread,
796                                                   mainthreadobj, threadname, 5, false);
797
798         if (*exceptionptr)
799                 return false;
800
801         mainthread->group = threadgroup;
802
803         /* add mainthread to ThreadGroup */
804
805         method = class_resolveclassmethod(class_java_lang_ThreadGroup,
806                                                                           utf_new_char("addThread"),
807                                                                           utf_new_char("(Ljava/lang/Thread;)V"),
808                                                                           class_java_lang_ThreadGroup,
809                                                                           true);
810
811         if (method == NULL)
812                 return false;
813
814         (void) vm_call_method(method, (java_objectheader *) threadgroup,
815                                                   mainthread);
816
817         if (*exceptionptr)
818                 return false;
819
820         threads_set_thread_priority(pthread_self(), 5);
821
822         /* initialize the thread attribute object */
823
824         if (pthread_attr_init(&threadattr)) {
825                 log_println("pthread_attr_init failed: %s", strerror(errno));
826                 return false;
827         }
828
829         pthread_attr_setdetachstate(&threadattr, PTHREAD_CREATE_DETACHED);
830
831         /* everything's ok */
832
833         return true;
834 }
835
836
837 /* threads_table_init *********************************************************
838
839    Initialize the global threads table.
840
841 ******************************************************************************/
842
843 static void threads_table_init(void)
844 {
845         s4 size;
846         s4 i;
847
848         size = THREADS_INITIAL_TABLE_SIZE;
849
850         threads_table.size = size;
851         threads_table.table = MNEW(threads_table_entry_t, size);
852
853         /* link the entries in a freelist */
854
855         for (i=0; i<size; ++i) {
856                 threads_table.table[i].nextfree = i+1;
857         }
858
859         /* terminate the freelist */
860
861         threads_table.table[size-1].nextfree = 0; /* index 0 is never free */
862 }
863
864
865 /* threads_table_add **********************************************************
866
867    Add a thread to the global threads table. The index is entered in the
868    threadobject. The thinlock value for the thread is pre-computed.
869
870    IN:
871       thread............the thread to add
872
873    RETURN VALUE:
874       The table index for the newly added thread. This value has also been
875           entered in the threadobject.
876
877    PRE-CONDITION:
878       The caller must hold the threadlistlock!
879
880 ******************************************************************************/
881
882 static s4 threads_table_add(threadobject *thread)
883 {
884         s4 index;
885         s4 oldsize;
886         s4 newsize;
887         s4 i;
888
889         /* table[0] serves as the head of the freelist */
890
891         index = threads_table.table[0].nextfree;
892
893         /* if we got a free index, use it */
894
895         if (index) {
896 got_an_index:
897                 threads_table.table[0].nextfree = threads_table.table[index].nextfree;
898                 threads_table.table[index].thread = thread;
899                 thread->index = index;
900                 thread->thinlock = lock_pre_compute_thinlock(index);
901                 return index;
902         }
903
904         /* we must grow the table */
905
906         oldsize = threads_table.size;
907         newsize = oldsize * 2;
908
909         threads_table.table = MREALLOC(threads_table.table, threads_table_entry_t,
910                                                                    oldsize, newsize);
911         threads_table.size = newsize;
912
913         /* link the new entries to a free list */
914
915         for (i=oldsize; i<newsize; ++i) {
916                 threads_table.table[i].nextfree = i+1;
917         }
918
919         /* terminate the freelist */
920
921         threads_table.table[newsize-1].nextfree = 0; /* index 0 is never free */
922
923         /* use the first of the new entries */
924
925         index = oldsize;
926         goto got_an_index;
927 }
928
929
930 /* threads_table_remove *******************************************************
931
932    Remove a thread from the global threads table.
933
934    IN:
935       thread............the thread to remove
936
937    PRE-CONDITION:
938       The caller must hold the threadlistlock!
939
940 ******************************************************************************/
941
942 static void threads_table_remove(threadobject *thread)
943 {
944         s4 index;
945
946         index = thread->index;
947
948         /* put the index into the freelist */
949
950         threads_table.table[index] = threads_table.table[0];
951         threads_table.table[0].nextfree = index;
952
953         /* delete the index in the threadobject to discover bugs */
954 #if !defined(NDEBUG)
955         thread->index = 0;
956 #endif
957 }
958
959 /* threads_init_threadobject **************************************************
960
961    Initialize implementation fields of a java.lang.VMThread.
962
963    IN:
964       t............the java.lang.VMThread
965
966 ******************************************************************************/
967
968 void threads_init_threadobject(java_lang_VMThread *t)
969 {
970         threadobject *thread = (threadobject*) t;
971
972         thread->tid = pthread_self();
973
974         thread->index = 0;
975
976         /* TODO destroy all those things */
977         pthread_mutex_init(&(thread->joinmutex), NULL);
978         pthread_cond_init(&(thread->joincond), NULL);
979
980         pthread_mutex_init(&(thread->waitmutex), NULL);
981         pthread_cond_init(&(thread->waitcond), NULL);
982
983         thread->interrupted = false;
984         thread->signaled = false;
985         thread->sleeping = false;
986 }
987
988
989 /* threads_startup_thread ******************************************************
990
991    Thread startup function called by pthread_create.
992
993    NOTE: This function is not called directly by pthread_create. The Boehm GC
994          inserts its own GC_start_routine in between, which then calls
995                  threads_startup.
996
997    IN:
998       t............the argument passed to pthread_create, ie. a pointer to
999                        a startupinfo struct. CAUTION: When the `psem` semaphore
1000                                    is posted, the startupinfo struct becomes invalid! (It
1001                                    is allocated on the stack of threads_start_thread.)
1002
1003 ******************************************************************************/
1004
1005 static void *threads_startup_thread(void *t)
1006 {
1007         startupinfo  *startup;
1008         threadobject *thread;
1009         sem_t        *psem;
1010         threadobject *tnext;
1011         methodinfo   *method;
1012         functionptr   function;
1013
1014 #if defined(ENABLE_INTRP)
1015         u1 *intrp_thread_stack;
1016
1017         /* create interpreter stack */
1018
1019         if (opt_intrp) {
1020                 intrp_thread_stack = GCMNEW(u1, opt_stacksize);
1021                 MSET(intrp_thread_stack, 0, u1, opt_stacksize);
1022         }
1023         else
1024                 intrp_thread_stack = NULL;
1025 #endif
1026
1027         /* get passed startupinfo structure and the values in there */
1028
1029         startup = t;
1030         t = NULL; /* make sure it's not used wrongly */
1031
1032         thread   = startup->thread;
1033         function = startup->function;
1034         psem     = startup->psem;
1035
1036         /* Seems like we've encountered a situation where thread->tid was not set by
1037          * pthread_create. We alleviate this problem by waiting for pthread_create
1038          * to return. */
1039         threads_sem_wait(startup->psem_first);
1040
1041         /* set the thread object */
1042
1043 #if defined(__DARWIN__)
1044         thread->mach_thread = mach_thread_self();
1045 #endif
1046         threads_set_current_threadobject(thread);
1047
1048         /* insert the thread into the threadlist and the threads table */
1049
1050         pthread_mutex_lock(&threadlistlock);
1051
1052         thread->prev = mainthreadobj;
1053         thread->next = tnext = mainthreadobj->next;
1054         mainthreadobj->next = thread;
1055         tnext->prev = thread;
1056
1057         threads_table_add(thread);
1058
1059         pthread_mutex_unlock(&threadlistlock);
1060
1061         /* init data structures of this thread */
1062
1063         lock_init_execution_env(thread);
1064
1065         /* tell threads_startup_thread that we registered ourselves */
1066         /* CAUTION: *startup becomes invalid with this!             */
1067
1068         startup = NULL;
1069         threads_sem_post(psem);
1070
1071         /* set our priority */
1072
1073         threads_set_thread_priority(thread->tid, thread->o.thread->priority);
1074
1075 #if defined(ENABLE_INTRP)
1076         /* set interpreter stack */
1077
1078         if (opt_intrp)
1079                 thread->_global_sp = (void *) (intrp_thread_stack + opt_stacksize);
1080 #endif
1081
1082
1083
1084 #if defined(ENABLE_JVMTI)
1085         /* breakpoint for thread start event */
1086         __asm__("threadstart:");
1087 #endif
1088
1089
1090         /* find and run the Thread.run()V method if no other function was passed */
1091
1092         if (function == NULL) {
1093                 method = class_resolveclassmethod(thread->o.header.vftbl->class,
1094                                                                                   utf_run,
1095                                                                                   utf_void__void,
1096                                                                                   thread->o.header.vftbl->class,
1097                                                                                   true);
1098
1099                 if (!method)
1100                         throw_exception();
1101
1102                 (void) vm_call_method(method, (java_objectheader *) thread);
1103
1104         }
1105         else {
1106                 /* call passed function, e.g. finalizer_thread */
1107
1108                 (function)();
1109         }
1110
1111 #if defined(ENABLE_JVMTI)
1112         /* breakpoint for thread end event */
1113         __asm__("threadend:");
1114 #endif
1115
1116
1117         /* Allow lock record pools to be used by other threads. They
1118            cannot be deleted so we'd better not waste them. */
1119
1120         /* XXX We have to find a new way to free lock records */
1121         /*     with the new locking algorithm.                */
1122         /* lock_record_free_pools(thread->ee.lockrecordpools); */
1123
1124         /* remove thread from thread list and threads table, do this inside a lock */
1125
1126         pthread_mutex_lock(&threadlistlock);
1127
1128         thread->next->prev = thread->prev;
1129         thread->prev->next = thread->next;
1130
1131         threads_table_remove(thread);
1132
1133         pthread_mutex_unlock(&threadlistlock);
1134
1135         /* reset thread id (lock on joinmutex? TWISTI) */
1136
1137         pthread_mutex_lock(&thread->joinmutex);
1138         thread->tid = 0;
1139         pthread_mutex_unlock(&thread->joinmutex);
1140
1141         /* tell everyone that a thread has finished */
1142
1143         pthread_cond_broadcast(&thread->joincond);
1144
1145         return NULL;
1146 }
1147
1148
1149 /* threads_start_thread ********************************************************
1150
1151    Start a thread in the JVM.
1152
1153    IN:
1154       t............the java.lang.Thread object
1155           function.....function to run in the new thread. NULL means that the
1156                        "run" method of the object `t` should be called
1157
1158 ******************************************************************************/
1159
1160 void threads_start_thread(java_lang_Thread *t, functionptr function)
1161 {
1162         sem_t          sem;
1163         sem_t          sem_first;
1164         pthread_attr_t attr;
1165         startupinfo    startup;
1166         threadobject  *thread;
1167
1168         thread = (threadobject *) t->vmThread;
1169
1170         /* fill startupinfo structure passed by pthread_create to
1171          * threads_startup_thread */
1172
1173         startup.thread     = thread;
1174         startup.function   = function;       /* maybe we don't call Thread.run()V */
1175         startup.psem       = &sem;
1176         startup.psem_first = &sem_first;
1177
1178         threads_sem_init(&sem, 0, 0);
1179         threads_sem_init(&sem_first, 0, 0);
1180
1181         /* initialize thread attribute object */
1182
1183         if (pthread_attr_init(&attr))
1184                 vm_abort("pthread_attr_init failed: %s", strerror(errno));
1185
1186         /* initialize thread stacksize */
1187
1188         if (pthread_attr_setstacksize(&attr, opt_stacksize))
1189                 vm_abort("pthread_attr_setstacksize failed: %s", strerror(errno));
1190
1191         /* create the thread */
1192
1193         if (pthread_create(&thread->tid, &attr, threads_startup_thread, &startup))
1194                 vm_abort("pthread_create failed: %s", strerror(errno));
1195
1196         /* signal that pthread_create has returned, so thread->tid is valid */
1197
1198         threads_sem_post(&sem_first);
1199
1200         /* wait here until the thread has entered itself into the thread list */
1201
1202         threads_sem_wait(&sem);
1203
1204         /* cleanup */
1205
1206         sem_destroy(&sem);
1207         sem_destroy(&sem_first);
1208 }
1209
1210
1211 /* threads_find_non_daemon_thread **********************************************
1212
1213    Helper function used by threads_join_all_threads for finding non-daemon threads
1214    that are still running.
1215
1216 *******************************************************************************/
1217
1218 /* At the end of the program, we wait for all running non-daemon threads to die
1219  */
1220
1221 static threadobject *threads_find_non_daemon_thread(threadobject *thread)
1222 {
1223         while (thread != mainthreadobj) {
1224                 if (!thread->o.thread->daemon)
1225                         return thread;
1226                 thread = thread->prev;
1227         }
1228
1229         return NULL;
1230 }
1231
1232
1233 /* threads_join_all_threads ****************************************************
1234
1235    Join all non-daemon threads.
1236
1237 *******************************************************************************/
1238
1239 void threads_join_all_threads(void)
1240 {
1241         threadobject *thread;
1242
1243         pthread_mutex_lock(&threadlistlock);
1244
1245         while ((thread = threads_find_non_daemon_thread(mainthreadobj->prev)) != NULL) {
1246
1247                 pthread_mutex_lock(&thread->joinmutex);
1248
1249                 pthread_mutex_unlock(&threadlistlock);
1250
1251                 while (thread->tid)
1252                         pthread_cond_wait(&thread->joincond, &thread->joinmutex);
1253
1254                 pthread_mutex_unlock(&thread->joinmutex);
1255
1256                 pthread_mutex_lock(&threadlistlock);
1257         }
1258
1259         pthread_mutex_unlock(&threadlistlock);
1260 }
1261
1262
1263 /* threads_timespec_earlier ****************************************************
1264
1265    Return true if timespec tv1 is earlier than timespec tv2.
1266
1267    IN:
1268       tv1..........first timespec
1269           tv2..........second timespec
1270
1271    RETURN VALUE:
1272       true, if the first timespec is earlier
1273
1274 *******************************************************************************/
1275
1276 static inline bool threads_timespec_earlier(const struct timespec *tv1,
1277                                                                                         const struct timespec *tv2)
1278 {
1279         return (tv1->tv_sec < tv2->tv_sec)
1280                                 ||
1281                 (tv1->tv_sec == tv2->tv_sec && tv1->tv_nsec < tv2->tv_nsec);
1282 }
1283
1284
1285 /* threads_current_time_is_earlier_than ****************************************
1286
1287    Check if the current time is earlier than the given timespec.
1288
1289    IN:
1290       tv...........the timespec to compare against
1291
1292    RETURN VALUE:
1293       true, if the current time is earlier
1294
1295 *******************************************************************************/
1296
1297 static bool threads_current_time_is_earlier_than(const struct timespec *tv)
1298 {
1299         struct timeval tvnow;
1300         struct timespec tsnow;
1301
1302         /* get current time */
1303
1304         if (gettimeofday(&tvnow, NULL) != 0)
1305                 vm_abort("gettimeofday failed: %s\n", strerror(errno));
1306
1307         /* convert it to a timespec */
1308
1309         tsnow.tv_sec = tvnow.tv_sec;
1310         tsnow.tv_nsec = tvnow.tv_usec * 1000;
1311
1312         /* compare current time with the given timespec */
1313
1314         return threads_timespec_earlier(&tsnow, tv);
1315 }
1316
1317
1318 /* threads_wait_with_timeout ***************************************************
1319
1320    Wait until the given point in time on a monitor until either
1321    we are notified, we are interrupted, or the time is up.
1322
1323    IN:
1324       t............the current thread
1325           wakeupTime...absolute (latest) wakeup time
1326                            If both tv_sec and tv_nsec are zero, this function
1327                                            waits for an unlimited amount of time.
1328
1329    RETURN VALUE:
1330       true.........if the wait has been interrupted,
1331           false........if the wait was ended by notification or timeout
1332
1333 *******************************************************************************/
1334
1335 static bool threads_wait_with_timeout(threadobject *t,
1336                                                                           struct timespec *wakeupTime)
1337 {
1338         bool wasinterrupted;
1339
1340         /* acquire the waitmutex */
1341
1342         pthread_mutex_lock(&t->waitmutex);
1343
1344         /* mark us as sleeping */
1345
1346         t->sleeping = true;
1347
1348         /* wait on waitcond */
1349
1350         if (wakeupTime->tv_sec || wakeupTime->tv_nsec) {
1351                 /* with timeout */
1352                 while (!t->interrupted && !t->signaled
1353                            && threads_current_time_is_earlier_than(wakeupTime))
1354                 {
1355                         pthread_cond_timedwait(&t->waitcond, &t->waitmutex, wakeupTime);
1356                 }
1357         }
1358         else {
1359                 /* no timeout */
1360                 while (!t->interrupted && !t->signaled)
1361                         pthread_cond_wait(&t->waitcond, &t->waitmutex);
1362         }
1363
1364         /* check if we were interrupted */
1365
1366         wasinterrupted = t->interrupted;
1367
1368         /* reset all flags */
1369
1370         t->interrupted = false;
1371         t->signaled = false;
1372         t->sleeping = false;
1373
1374         /* release the waitmutex */
1375
1376         pthread_mutex_unlock(&t->waitmutex);
1377
1378         return wasinterrupted;
1379 }
1380
1381
1382 /* threads_wait_with_timeout_relative ******************************************
1383
1384    Wait for the given maximum amount of time on a monitor until either
1385    we are notified, we are interrupted, or the time is up.
1386
1387    IN:
1388       t............the current thread
1389           millis.......milliseconds to wait
1390           nanos........nanoseconds to wait
1391
1392    RETURN VALUE:
1393       true.........if the wait has been interrupted,
1394           false........if the wait was ended by notification or timeout
1395
1396 *******************************************************************************/
1397
1398 bool threads_wait_with_timeout_relative(threadobject *t,
1399                                                                                 s8 millis,
1400                                                                                 s4 nanos)
1401 {
1402         struct timespec wakeupTime;
1403
1404         /* calculate the the (latest) wakeup time */
1405
1406         threads_calc_absolute_time(&wakeupTime, millis, nanos);
1407
1408         /* wait */
1409
1410         return threads_wait_with_timeout(t, &wakeupTime);
1411 }
1412
1413
1414 /* threads_calc_absolute_time **************************************************
1415
1416    Calculate the absolute point in time a given number of ms and ns from now.
1417
1418    IN:
1419       millis............milliseconds from now
1420           nanos.............nanoseconds from now
1421
1422    OUT:
1423       *tm...............receives the timespec of the absolute point in time
1424
1425 *******************************************************************************/
1426
1427 static void threads_calc_absolute_time(struct timespec *tm, s8 millis, s4 nanos)
1428 {
1429         if ((millis != 0x7fffffffffffffffLLU) && (millis || nanos)) {
1430                 struct timeval tv;
1431                 long nsec;
1432                 gettimeofday(&tv, NULL);
1433                 tv.tv_sec += millis / 1000;
1434                 millis %= 1000;
1435                 nsec = tv.tv_usec * 1000 + (s4) millis * 1000000 + nanos;
1436                 tm->tv_sec = tv.tv_sec + nsec / 1000000000;
1437                 tm->tv_nsec = nsec % 1000000000;
1438         }
1439         else {
1440                 tm->tv_sec = 0;
1441                 tm->tv_nsec = 0;
1442         }
1443 }
1444
1445
1446 /* threads_interrupt_thread ****************************************************
1447
1448    Interrupt the given thread.
1449
1450    The thread gets the "waitcond" signal and 
1451    its interrupted flag is set to true.
1452
1453    IN:
1454       thread............the thread to interrupt
1455
1456 *******************************************************************************/
1457
1458 void threads_interrupt_thread(java_lang_VMThread *thread)
1459 {
1460         threadobject *t = (threadobject*) thread;
1461
1462         /* signal the thread a "waitcond" and tell it that it has been */
1463         /* interrupted                                                 */
1464
1465         pthread_mutex_lock(&t->waitmutex);
1466         if (t->sleeping)
1467                 pthread_cond_signal(&t->waitcond);
1468         t->interrupted = true;
1469         pthread_mutex_unlock(&t->waitmutex);
1470 }
1471
1472
1473 /* threads_check_if_interrupted_and_reset **************************************
1474
1475    Check if the current thread has been interrupted and reset the
1476    interruption flag.
1477
1478    RETURN VALUE:
1479       true, if the current thread had been interrupted
1480
1481 *******************************************************************************/
1482
1483 bool threads_check_if_interrupted_and_reset(void)
1484 {
1485         threadobject *t;
1486         bool intr;
1487
1488         t = (threadobject*) THREADOBJECT;
1489
1490         intr = t->interrupted;
1491
1492         t->interrupted = false;
1493
1494         return intr;
1495 }
1496
1497
1498 /* threads_thread_has_been_interrupted *********************************************************
1499
1500    Check if the given thread has been interrupted
1501
1502    IN:
1503       t............the thread to check
1504
1505    RETURN VALUE:
1506       true, if the given thread had been interrupted
1507
1508 *******************************************************************************/
1509
1510 bool threads_thread_has_been_interrupted(java_lang_VMThread *thread)
1511 {
1512         threadobject *t;
1513
1514         t = (threadobject*) thread;
1515
1516         return t->interrupted;
1517 }
1518
1519
1520 /* threads_sleep ***************************************************************
1521
1522    Sleep the current thread for the specified amount of time.
1523
1524 *******************************************************************************/
1525
1526 void threads_sleep(s8 millis, s4 nanos)
1527 {
1528         threadobject       *t;
1529         struct timespec    wakeupTime;
1530         bool               wasinterrupted;
1531
1532         t = (threadobject *) THREADOBJECT;
1533
1534         threads_calc_absolute_time(&wakeupTime, millis, nanos);
1535
1536         wasinterrupted = threads_wait_with_timeout(t, &wakeupTime);
1537
1538         if (wasinterrupted)
1539                 *exceptionptr = new_exception(string_java_lang_InterruptedException);
1540 }
1541
1542
1543 /* threads_yield *****************************************************************
1544
1545    Yield to the scheduler.
1546
1547 *******************************************************************************/
1548
1549 void threads_yield(void)
1550 {
1551         sched_yield();
1552 }
1553
1554
1555 /* threads_java_lang_Thread_set_priority ***********************************************************
1556
1557    Set the priority for the given java.lang.Thread.
1558
1559    IN:
1560       t............the java.lang.Thread
1561           priority.....the priority
1562
1563 *******************************************************************************/
1564
1565 void threads_java_lang_Thread_set_priority(java_lang_Thread *t, s4 priority)
1566 {
1567         threadobject *thread;
1568
1569         thread = (threadobject*) t->vmThread;
1570
1571         threads_set_thread_priority(thread->tid, priority);
1572 }
1573
1574
1575 /* threads_dump ****************************************************************
1576
1577    Dumps info for all threads running in the JVM. This function is
1578    called when SIGQUIT (<ctrl>-\) is sent to CACAO.
1579
1580 *******************************************************************************/
1581
1582 void threads_dump(void)
1583 {
1584         threadobject       *tobj;
1585         java_lang_VMThread *vmt;
1586         java_lang_Thread   *t;
1587         utf                *name;
1588
1589         tobj = mainthreadobj;
1590
1591         printf("Full thread dump CACAO "VERSION":\n");
1592
1593         /* iterate over all started threads */
1594
1595         do {
1596                 /* get thread objects */
1597
1598                 vmt = &tobj->o;
1599                 t   = vmt->thread;
1600
1601                 /* the thread may be currently in initalization, don't print it */
1602
1603                 if (t) {
1604                         /* get thread name */
1605
1606                         name = javastring_toutf(t->name, false);
1607
1608                         printf("\n\"");
1609                         utf_display_printable_ascii(name);
1610                         printf("\" ");
1611
1612                         if (t->daemon)
1613                                 printf("daemon ");
1614
1615 #if SIZEOF_VOID_P == 8
1616                         printf("prio=%d tid=0x%016lx\n", t->priority, tobj->tid);
1617 #else
1618                         printf("prio=%d tid=0x%08lx\n", t->priority, tobj->tid);
1619 #endif
1620
1621                         /* send SIGUSR1 to thread to print stacktrace */
1622
1623                         pthread_kill(tobj->tid, SIGUSR1);
1624
1625                         /* sleep this thread a bit, so the signal can reach the thread */
1626
1627                         threads_sleep(10, 0);
1628                 }
1629
1630                 tobj = tobj->next;
1631         } while (tobj && (tobj != mainthreadobj));
1632 }
1633
1634
1635 /* threads_table_dump *********************************************************
1636
1637    Dump the threads table for debugging purposes.
1638
1639    IN:
1640       file..............stream to write to
1641
1642 ******************************************************************************/
1643
1644 #if !defined(NDEBUG)
1645 static void threads_table_dump(FILE *file)
1646 {
1647         s4 i;
1648         s4 size;
1649         ptrint index;
1650
1651         pthread_mutex_lock(&threadlistlock);
1652
1653         size = threads_table.size;
1654
1655         fprintf(file, "======== THREADS TABLE (size %d) ========\n", size);
1656
1657         for (i=0; i<size; ++i) {
1658                 index = threads_table.table[i].nextfree;
1659
1660                 fprintf(file, "%4d: ", i);
1661
1662                 if (index < size) {
1663                         fprintf(file, "free, nextfree = %d\n", index);
1664                 }
1665                 else {
1666                         fprintf(file, "thread %p\n", (void*) threads_table.table[i].thread);
1667                 }
1668         }
1669
1670         fprintf(file, "======== END OF THREADS TABLE ========\n");
1671
1672         pthread_mutex_unlock(&threadlistlock);
1673 }
1674 #endif
1675
1676
1677 #if defined(ENABLE_JVMTI)
1678 /* jvmti_get_threads_breakpoints ***********************************************
1679
1680    gets all breakpoints from this file
1681
1682 *******************************************************************************/
1683
1684 void jvmti_get_threads_breakpoints(void **brks) {
1685         __asm__ ("movl $threadstart,%0;" :"=m"(brks[0]));
1686         __asm__ ("movl $threadend,%0;" :"=m"(brks[1]));
1687 }
1688 #endif
1689
1690 /*
1691  * These are local overrides for various environment variables in Emacs.
1692  * Please do not remove this and leave it at the end of the file, where
1693  * Emacs will automagically detect them.
1694  * ---------------------------------------------------------------------
1695  * Local variables:
1696  * mode: c
1697  * indent-tabs-mode: t
1698  * c-basic-offset: 4
1699  * tab-width: 4
1700  * End:
1701  * vim:noexpandtab:sw=4:ts=4:
1702  */