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