* This commit adds C++ wrapper classes for OpenJDK. Actually I'm done
[cacao.git] / src / threads / thread.cpp
1 /* src/threads/thread.cpp - machine independent thread functions
2
3    Copyright (C) 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <assert.h>
29 #include <stdint.h>
30 #include <unistd.h>
31
32 #include "vm/types.h"
33
34 #include "mm/memory.h"
35
36 #if defined(ENABLE_GC_BOEHM)
37 /* We need to include Boehm's gc.h here for GC_register_my_thread and
38    friends. */
39 # include "mm/boehm-gc/include/gc.h"
40 #endif
41
42 #include "native/jni.h"
43 #include "native/llni.h"
44 #include "native/native.h"
45
46 #include "threads/lock-common.h"
47 #include "threads/threadlist.h"
48 #include "threads/thread.hpp"
49
50 #include "vm/builtin.h"
51 #include "vm/exceptions.hpp"
52 #include "vm/string.hpp"
53 #include "vm/vm.hpp"
54
55 #include "vm/jit/stacktrace.hpp"
56
57 #include "vmcore/class.h"
58 #include "vmcore/globals.hpp"
59 #include "vmcore/javaobjects.hpp"
60 #include "vmcore/method.h"
61 #include "vmcore/options.h"
62
63 #if defined(ENABLE_STATISTICS)
64 # include "vmcore/statistics.h"
65 #endif
66
67 #include "vmcore/utf8.h"
68
69
70 // FIXME
71 extern "C" {
72
73 /* global variables ***********************************************************/
74
75 static methodinfo    *thread_method_init;
76 static java_handle_t *threadgroup_system;
77 static java_handle_t *threadgroup_main;
78
79 #if defined(__LINUX__)
80 /* XXX Remove for exact-GC. */
81 bool threads_pthreads_implementation_nptl;
82 #endif
83
84
85 /* static functions ***********************************************************/
86
87 static void          thread_create_initial_threadgroups(void);
88 static void          thread_create_initial_thread(void);
89 static threadobject *thread_new(void);
90
91
92 /* threads_preinit *************************************************************
93
94    Do some early initialization of stuff required.
95
96 *******************************************************************************/
97
98 void threads_preinit(void)
99 {
100         threadobject *mainthread;
101 #if defined(__LINUX__) && defined(_CS_GNU_LIBPTHREAD_VERSION)
102         char         *pathbuf;
103         size_t        len;
104 #endif
105
106         TRACESUBSYSTEMINITIALIZATION("threads_preinit");
107
108 #if defined(__LINUX__)
109         /* XXX Remove for exact-GC. */
110
111         /* On Linux we need to check the pthread implementation. */
112
113         /* _CS_GNU_LIBPTHREAD_VERSION (GNU C library only; since glibc 2.3.2) */
114         /* If the glibc is a pre-2.3.2 version, we fall back to
115            linuxthreads. */
116
117 # if defined(_CS_GNU_LIBPTHREAD_VERSION)
118         len = confstr(_CS_GNU_LIBPTHREAD_VERSION, NULL, (size_t) 0);
119
120         /* Some systems return as length 0 (maybe cross-compilation
121            related).  In this case we also fall back to linuxthreads. */
122
123         if (len > 0) {
124                 pathbuf = MNEW(char, len);
125
126                 (void) confstr(_CS_GNU_LIBPTHREAD_VERSION, pathbuf, len);
127
128                 if (strstr(pathbuf, "NPTL") != NULL)
129                         threads_pthreads_implementation_nptl = true;
130                 else
131                         threads_pthreads_implementation_nptl = false;
132         }
133         else
134                 threads_pthreads_implementation_nptl = false;
135 # else
136         threads_pthreads_implementation_nptl = false;
137 # endif
138 #endif
139
140         /* Initialize the threads implementation (sets the thinlock on the
141            main thread). */
142
143         threads_impl_preinit();
144
145         /* Create internal thread data-structure for the main thread. */
146
147         mainthread = thread_new();
148
149         /* The main thread should always have index 1. */
150
151         if (mainthread->index != 1)
152                 vm_abort("threads_preinit: main thread index not 1: %d != 1",
153                                  mainthread->index);
154
155         /* thread is a Java thread and running */
156
157         mainthread->flags |= THREAD_FLAG_JAVA;
158         mainthread->state = THREAD_STATE_RUNNABLE;
159
160         /* Store the internal thread data-structure in the TSD. */
161
162         thread_set_current(mainthread);
163 }
164
165
166 /* threads_init ****************************************************************
167
168    Initialize the main thread.
169
170 *******************************************************************************/
171
172 void threads_init(void)
173 {
174         TRACESUBSYSTEMINITIALIZATION("threads_init");
175
176         /* Create the system and main thread groups. */
177
178         thread_create_initial_threadgroups();
179
180         /* Cache the java.lang.Thread initialization method. */
181
182 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
183
184         thread_method_init =
185                 class_resolveclassmethod(class_java_lang_Thread,
186                                                                  utf_init,
187                                                                  utf_new_char("(Ljava/lang/VMThread;Ljava/lang/String;IZ)V"),
188                                                                  class_java_lang_Thread,
189                                                                  true);
190
191 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
192
193         thread_method_init =
194                 class_resolveclassmethod(class_java_lang_Thread,
195                                                                  utf_init,
196                                                                  utf_new_char("(Ljava/lang/ThreadGroup;Ljava/lang/String;)V"),
197                                                                  class_java_lang_Thread,
198                                                                  true);
199
200 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
201
202         thread_method_init =
203                 class_resolveclassmethod(class_java_lang_Thread,
204                                                                  utf_init,
205                                                                  utf_java_lang_String__void,
206                                                                  class_java_lang_Thread,
207                                                                  true);
208
209 #else
210 # error unknown classpath configuration
211 #endif
212
213         if (thread_method_init == NULL)
214                 vm_abort("threads_init: failed to resolve thread init method");
215
216         thread_create_initial_thread();
217 }
218
219
220 /* thread_create_object ********************************************************
221
222    Create a Java thread object for the given thread data-structure,
223    initializes it and adds the thread to the threadgroup.
224
225    ARGUMENTS:
226
227        t ....... thread
228        name .... thread name
229        group ... threadgroup
230
231    RETURN:
232
233 *******************************************************************************/
234
235 static bool thread_create_object(threadobject *t, java_handle_t *name, java_handle_t *group)
236 {
237         /* Create a java.lang.Thread Java object. */
238
239         java_handle_t* h = builtin_new(class_java_lang_Thread);
240
241         if (h == NULL)
242                 return false;
243
244         java_lang_Thread jlt(h);
245
246         // Set the Java object in the thread data-structure.  This
247         // indicates that the thread is attached to the VM.
248         thread_set_object(t, jlt.get_handle());
249
250 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
251
252         h = builtin_new(class_java_lang_VMThread);
253
254         if (h == NULL)
255                 return false;
256
257         // Create and initialize a java.lang.VMThread object.
258         java_lang_VMThread jlvmt(h, jlt.get_handle(), t);
259
260         /* Call:
261            java.lang.Thread.<init>(Ljava/lang/VMThread;Ljava/lang/String;IZ)V */
262
263         bool isdaemon = thread_is_daemon(t);
264
265         (void) vm_call_method(thread_method_init, jlt.get_handle(), jlvmt.get_handle(),
266                                                   name, NORM_PRIORITY, isdaemon);
267
268         if (exceptions_get_exception())
269                 return false;
270
271         // Set the ThreadGroup in the Java thread object.
272         jlt.set_group(group);
273
274         /* Add thread to the threadgroup. */
275
276         classinfo* c;
277         LLNI_class_get(group, c);
278
279         methodinfo* m = class_resolveclassmethod(c,
280                                                                                          utf_addThread,
281                                                                                          utf_java_lang_Thread__V,
282                                                                                          class_java_lang_ThreadGroup,
283                                                                                          true);
284
285         if (m == NULL)
286                 return false;
287
288         (void) vm_call_method(m, group, jlt.get_handle());
289
290         if (exceptions_get_exception())
291                 return false;
292
293 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
294
295         /* Set the priority.  java.lang.Thread.<init> requires it because
296            it sets the priority of the current thread to the parent's one
297            (which is the current thread in this case). */
298         jlt.set_priority(NORM_PRIORITY);
299
300         // Call: java.lang.Thread.<init>(Ljava/lang/ThreadGroup;Ljava/lang/String;)V
301
302         (void) vm_call_method(thread_method_init, jlt.get_handle(), group, name);
303
304         if (exceptions_get_exception())
305                 return false;
306
307 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
308
309         // Set the thread data-structure in the Java thread object.
310         jlt.set_vm_thread(t);
311
312         // Call: public Thread(Ljava/lang/String;)V
313         (void) vm_call_method(thread_method_init, jlt.get_handle(), name);
314
315         if (exceptions_get_exception())
316                 return false;
317
318 #else
319 # error unknown classpath configuration
320 #endif
321
322         return true;
323 }
324
325
326 /* thread_create_initial_threadgroups ******************************************
327
328    Create the initial threadgroups.
329
330    GNU Classpath:
331        Create the main threadgroup only and set the system
332        threadgroup to the main threadgroup.
333
334    SUN:
335        Create the system and main threadgroup.
336
337    CLDC:
338        This function is a no-op.
339
340 *******************************************************************************/
341
342 static void thread_create_initial_threadgroups(void)
343 {
344 #if defined(ENABLE_JAVASE)
345 # if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
346
347         /* Allocate and initialize the main thread group. */
348
349         threadgroup_main = native_new_and_init(class_java_lang_ThreadGroup);
350
351         if (threadgroup_main == NULL)
352                 vm_abort("thread_create_initial_threadgroups: failed to allocate main threadgroup");
353
354         /* Use the same threadgroup for system as for main. */
355
356         threadgroup_system = threadgroup_main;
357
358 # elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
359
360         java_handle_t *name;
361         methodinfo    *m;
362
363         /* Allocate and initialize the system thread group. */
364
365         threadgroup_system = native_new_and_init(class_java_lang_ThreadGroup);
366
367         if (threadgroup_system == NULL)
368                 vm_abort("thread_create_initial_threadgroups: failed to allocate system threadgroup");
369
370         /* Allocate and initialize the main thread group. */
371
372         threadgroup_main = builtin_new(class_java_lang_ThreadGroup);
373
374         if (threadgroup_main == NULL)
375                 vm_abort("thread_create_initial_threadgroups: failed to allocate main threadgroup");
376
377         name = javastring_new(utf_main);
378
379         m = class_resolveclassmethod(class_java_lang_ThreadGroup,
380                                                                  utf_init,
381                                                                  utf_Ljava_lang_ThreadGroup_Ljava_lang_String__V,
382                                                                  class_java_lang_ThreadGroup,
383                                                                  true);
384
385         if (m == NULL)
386                 vm_abort("thread_create_initial_threadgroups: failed to resolve threadgroup init method");
387
388         (void) vm_call_method(m, threadgroup_main, threadgroup_system, name);
389
390         if (exceptions_get_exception())
391                 vm_abort("thread_create_initial_threadgroups: exception while initializing main threadgroup");
392
393 # else
394 #  error unknown classpath configuration
395 # endif
396 #endif
397 }
398
399
400 /* thread_create_initial_thread ***********************************************
401
402    Create the initial thread: main
403
404 *******************************************************************************/
405
406 static void thread_create_initial_thread(void)
407 {
408         threadobject  *t;
409         java_handle_t *name;
410
411         /* Get the main-thread (NOTE: The main thread is always the first
412            thread in the list). */
413
414         t = threadlist_first();
415
416         /* The thread name. */
417
418         name = javastring_new(utf_main);
419
420 #if defined(ENABLE_INTRP)
421         /* create interpreter stack */
422
423         if (opt_intrp) {
424                 MSET(intrp_main_stack, 0, u1, opt_stacksize);
425                 mainthread->_global_sp = (Cell*) (intrp_main_stack + opt_stacksize);
426         }
427 #endif
428
429         /* Create the Java thread object. */
430
431         if (!thread_create_object(t, name, threadgroup_main))
432                 vm_abort("thread_create_initial_thread: failed to create Java object");
433
434         /* Initialize the implementation specific bits. */
435
436         threads_impl_init();
437
438         DEBUGTHREADS("starting (main)", t);
439 }
440
441
442 /* thread_new ******************************************************************
443
444    Allocates and initializes an internal thread data-structure and
445    adds it to the threads list.
446
447 *******************************************************************************/
448
449 static threadobject *thread_new(void)
450 {
451         int32_t       index;
452         threadobject *t;
453         
454         /* Lock the thread lists */
455
456         threadlist_lock();
457
458         index = threadlist_get_free_index();
459
460         /* Allocate a thread data structure. */
461
462         /* First, try to get one from the free-list. */
463
464         t = threadlist_free_first();
465
466         if (t != NULL) {
467                 /* Remove from free list. */
468
469                 threadlist_free_remove(t);
470
471                 /* Equivalent of MZERO on the else path */
472
473                 threads_impl_thread_clear(t);
474         }
475         else {
476 #if defined(ENABLE_GC_BOEHM)
477                 t = GCNEW_UNCOLLECTABLE(threadobject, 1);
478 #else
479                 t = NEW(threadobject);
480 #endif
481
482 #if defined(ENABLE_STATISTICS)
483                 if (opt_stat)
484                         size_threadobject += sizeof(threadobject);
485 #endif
486
487                 /* Clear memory. */
488
489                 MZERO(t, threadobject, 1);
490
491 #if defined(ENABLE_GC_CACAO)
492                 /* Register reference to java.lang.Thread with the GC. */
493                 /* FIXME is it ok to do this only once? */
494
495                 gc_reference_register(&(t->object), GC_REFTYPE_THREADOBJECT);
496                 gc_reference_register(&(t->_exceptionptr), GC_REFTYPE_THREADOBJECT);
497 #endif
498
499                 /* Initialize the implementation-specific bits. */
500
501                 threads_impl_thread_init(t);
502         }
503
504         /* Pre-compute the thinlock-word. */
505
506         assert(index != 0);
507
508         t->index     = index;
509         t->thinlock  = lock_pre_compute_thinlock(t->index);
510         t->flags     = 0;
511         t->state     = THREAD_STATE_NEW;
512
513 #if defined(ENABLE_GC_CACAO)
514         t->flags    |= THREAD_FLAG_IN_NATIVE; 
515 #endif
516
517         /* Initialize the implementation-specific bits. */
518
519         threads_impl_thread_reuse(t);
520
521         /* Add the thread to the thread list. */
522
523         threadlist_add(t);
524
525         /* Unlock the thread lists. */
526
527         threadlist_unlock();
528
529         return t;
530 }
531
532
533 /* thread_free *****************************************************************
534
535    Remove the thread from the threads-list and free the internal
536    thread data structure.  The thread index is added to the
537    thread-index free-list.
538
539    IN:
540        t ... thread data structure
541
542 *******************************************************************************/
543
544 void thread_free(threadobject *t)
545 {
546         /* Lock the thread lists. */
547
548         threadlist_lock();
549
550         /* Remove the thread from the thread-list. */
551
552         threadlist_remove(t);
553
554         /* Add the thread index to the free list. */
555
556         threadlist_index_add(t->index);
557
558         /* Set the reference to the Java object to NULL. */
559
560         thread_set_object(t, NULL);
561
562         /* Add the thread data structure to the free list. */
563
564         threadlist_free_add(t);
565
566         /* Unlock the thread lists. */
567
568         threadlist_unlock();
569 }
570
571
572 /* threads_thread_start_internal ***********************************************
573
574    Start an internal thread in the JVM.  No Java thread objects exists
575    so far.
576
577    IN:
578       name.......UTF-8 name of the thread
579       f..........function pointer to C function to start
580
581 *******************************************************************************/
582
583 bool threads_thread_start_internal(utf *name, functionptr f)
584 {
585         threadobject *t;
586
587         /* Enter the join-mutex, so if the main-thread is currently
588            waiting to join all threads, the number of non-daemon threads
589            is correct. */
590
591         threads_mutex_join_lock();
592
593         /* Create internal thread data-structure. */
594
595         t = thread_new();
596
597         t->flags |= THREAD_FLAG_INTERNAL | THREAD_FLAG_DAEMON;
598
599         /* The thread is flagged as (non-)daemon thread, we can leave the
600            mutex. */
601
602         threads_mutex_join_unlock();
603
604         /* Create the Java thread object. */
605
606         if (!thread_create_object(t, javastring_new(name), threadgroup_system))
607                 return false;
608
609         /* Start the thread. */
610
611         threads_impl_thread_start(t, f);
612
613         /* everything's ok */
614
615         return true;
616 }
617
618
619 /* threads_thread_start ********************************************************
620
621    Start a Java thread in the JVM.  Only the java thread object exists
622    so far.
623
624    IN:
625       object.....the java thread object java.lang.Thread
626
627 *******************************************************************************/
628
629 void threads_thread_start(java_handle_t *object)
630 {
631         java_lang_Thread jlt(object);
632
633         /* Enter the join-mutex, so if the main-thread is currently
634            waiting to join all threads, the number of non-daemon threads
635            is correct. */
636
637         threads_mutex_join_lock();
638
639         /* Create internal thread data-structure. */
640
641         threadobject* t = thread_new();
642
643         /* this is a normal Java thread */
644
645         t->flags |= THREAD_FLAG_JAVA;
646
647 #if defined(ENABLE_JAVASE)
648         /* Is this a daemon thread? */
649
650         if (jlt.get_daemon() == true)
651                 t->flags |= THREAD_FLAG_DAEMON;
652 #endif
653
654         /* The thread is flagged and (non-)daemon thread, we can leave the
655            mutex. */
656
657         threads_mutex_join_unlock();
658
659         /* Link the two objects together. */
660
661         thread_set_object(t, object);
662
663 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
664
665         /* Get the java.lang.VMThread object and do some sanity checks. */
666         java_lang_VMThread jlvmt(jlt.get_vmThread());
667
668         assert(jlvmt.get_handle() != NULL);
669         assert(jlvmt.get_vmdata() == NULL);
670
671         jlvmt.set_vmdata(t);
672
673 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
674
675         // Nothing to do.
676
677 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
678
679         jlt.set_vm_thread(t);
680
681 #else
682 # error unknown classpath configuration
683 #endif
684
685         /* Start the thread.  Don't pass a function pointer (NULL) since
686            we want Thread.run()V here. */
687
688         threads_impl_thread_start(t, NULL);
689 }
690
691
692 /**
693  * Attaches the current thread to the VM.
694  *
695  * @param vm_aargs Attach arguments.
696  * @param isdaemon true if the attached thread should be a daemon
697  *                 thread.
698  *
699  * @return true on success, false otherwise.
700  */
701 bool thread_attach_current_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon)
702 {
703         bool           result;
704         threadobject  *t;
705         utf           *u;
706         java_handle_t *name;
707         java_handle_t *group;
708
709     /* If the current thread has already been attached, this operation
710            is a no-op. */
711
712         result = thread_current_is_attached();
713
714         if (result == true)
715                 return true;
716
717         /* Enter the join-mutex, so if the main-thread is currently
718            waiting to join all threads, the number of non-daemon threads
719            is correct. */
720
721         threads_mutex_join_lock();
722
723         /* Create internal thread data structure. */
724
725         t = thread_new();
726
727         /* Thread is a Java thread and running. */
728
729         t->flags = THREAD_FLAG_JAVA;
730
731         if (isdaemon)
732                 t->flags |= THREAD_FLAG_DAEMON;
733
734         /* Store the internal thread data-structure in the TSD. */
735
736         thread_set_current(t);
737
738         /* The thread is flagged and (non-)daemon thread, we can leave the
739            mutex. */
740
741         threads_mutex_join_unlock();
742
743         DEBUGTHREADS("attaching", t);
744
745         /* Get the thread name. */
746
747         if (vm_aargs != NULL) {
748                 u = utf_new_char(vm_aargs->name);
749         }
750         else {
751                 u = utf_null;
752         }
753
754         name = javastring_new(u);
755
756 #if defined(ENABLE_JAVASE)
757         /* Get the threadgroup. */
758
759         if (vm_aargs != NULL)
760                 group = (java_handle_t *) vm_aargs->group;
761         else
762                 group = NULL;
763
764         /* If no threadgroup was given, use the main threadgroup. */
765
766         if (group == NULL)
767                 group = threadgroup_main;
768 #endif
769
770 #if defined(ENABLE_INTRP)
771         /* create interpreter stack */
772
773         if (opt_intrp) {
774                 MSET(intrp_main_stack, 0, u1, opt_stacksize);
775                 thread->_global_sp = (Cell *) (intrp_main_stack + opt_stacksize);
776         }
777 #endif
778
779         /* Create the Java thread object. */
780
781         if (!thread_create_object(t, name, group))
782                 return false;
783
784         /* The thread is completely initialized. */
785
786         thread_set_state_runnable(t);
787
788         return true;
789 }
790
791
792 /**
793  * Attaches the current external thread to the VM.  This function is
794  * called by JNI's AttachCurrentThread.
795  *
796  * @param vm_aargs Attach arguments.
797  * @param isdaemon true if the attached thread should be a daemon
798  *                 thread.
799  *
800  * @return true on success, false otherwise.
801  */
802 bool thread_attach_current_external_thread(JavaVMAttachArgs *vm_aargs, bool isdaemon)
803 {
804         int result;
805
806 #if defined(ENABLE_GC_BOEHM)
807         struct GC_stack_base sb;
808 #endif
809
810 #if defined(ENABLE_GC_BOEHM)
811         /* Register the thread with Boehm-GC.  This must happen before the
812            thread allocates any memory from the GC heap.*/
813
814         result = GC_get_stack_base(&sb);
815
816         if (result != GC_SUCCESS)
817                 vm_abort("threads_attach_current_thread: GC_get_stack_base failed");
818
819         GC_register_my_thread(&sb);
820 #endif
821
822         result = thread_attach_current_thread(vm_aargs, isdaemon);
823
824         if (result == false) {
825 #if defined(ENABLE_GC_BOEHM)
826                 /* Unregister the thread. */
827
828                 GC_unregister_my_thread();
829 #endif
830
831                 return false;
832         }
833
834         return true;
835 }
836
837
838 /**
839  * Detaches the current external thread from the VM.  This function is
840  * called by JNI's DetachCurrentThread.
841  *
842  * @return true on success, false otherwise.
843  */
844 bool thread_detach_current_external_thread(void)
845 {
846         int result;
847
848         result = thread_detach_current_thread();
849
850         if (result == false)
851                 return false;
852
853 #if defined(ENABLE_GC_BOEHM)
854         /* Unregister the thread with Boehm-GC.  This must happen after
855            the thread allocates any memory from the GC heap. */
856
857         /* Don't detach the main thread.  This is a workaround for
858            OpenJDK's java binary. */
859         if (thread_get_current()->index != 1)
860                 GC_unregister_my_thread();
861 #endif
862
863         return true;
864 }
865
866
867 /* thread_fprint_name **********************************************************
868
869    Print the name of the given thread to the given stream.
870
871    ARGUMENTS:
872        t ........ thread data-structure
873        stream ... stream to print to
874
875 *******************************************************************************/
876
877 void thread_fprint_name(threadobject *t, FILE *stream)
878 {
879         if (thread_get_object(t) == NULL)
880                 vm_abort("");
881
882         java_lang_Thread jlt(thread_get_object(t));
883
884 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
885
886         java_handle_t* name = jlt.get_name();
887         javastring_fprint(name, stream);
888
889 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK) || defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
890
891         /* FIXME: In OpenJDK and CLDC the name is a char[]. */
892         java_chararray_t *name;
893
894         /* FIXME This prints to stdout. */
895         utf_display_printable_ascii(utf_null);
896
897 #else
898 # error unknown classpath configuration
899 #endif
900 }
901
902
903 /* thread_print_info ***********************************************************
904
905    Print information of the passed thread.
906
907    ARGUMENTS:
908        t ... thread data-structure.
909
910 *******************************************************************************/
911
912 void thread_print_info(threadobject *t)
913 {
914         java_lang_Thread jlt(thread_get_object(t));
915
916         /* Print as much as we can when we are in state NEW. */
917
918         if (jlt.get_handle() != NULL) {
919                 /* Print thread name. */
920
921                 printf("\"");
922                 thread_fprint_name(t, stdout);
923                 printf("\"");
924         }
925         else {
926         }
927
928         if (thread_is_daemon(t))
929                 printf(" daemon");
930
931         if (jlt.get_handle() != NULL) {
932                 printf(" prio=%d", jlt.get_priority());
933         }
934
935 #if SIZEOF_VOID_P == 8
936         printf(" t=0x%016lx tid=0x%016lx (%ld)",
937                    (ptrint) t, (ptrint) t->tid, (ptrint) t->tid);
938 #else
939         printf(" t=0x%08x tid=0x%08x (%d)",
940                    (ptrint) t, (ptrint) t->tid, (ptrint) t->tid);
941 #endif
942
943         printf(" index=%d", t->index);
944
945         /* Print thread state. */
946
947         int state = cacaothread_get_state(t);
948
949         switch (state) {
950         case THREAD_STATE_NEW:
951                 printf(" new");
952                 break;
953         case THREAD_STATE_RUNNABLE:
954                 printf(" runnable");
955                 break;
956         case THREAD_STATE_BLOCKED:
957                 printf(" blocked");
958                 break;
959         case THREAD_STATE_WAITING:
960                 printf(" waiting");
961                 break;
962         case THREAD_STATE_TIMED_WAITING:
963                 printf(" waiting on condition");
964                 break;
965         case THREAD_STATE_TERMINATED:
966                 printf(" terminated");
967                 break;
968         default:
969                 vm_abort("thread_print_info: unknown thread state %d", state);
970         }
971 }
972
973
974 /* threads_get_current_tid *****************************************************
975
976    Return the tid of the current thread.
977    
978    RETURN VALUE:
979        the current tid
980
981 *******************************************************************************/
982
983 intptr_t threads_get_current_tid(void)
984 {
985         threadobject *thread;
986
987         thread = THREADOBJECT;
988
989         /* this may happen during bootstrap */
990
991         if (thread == NULL)
992                 return 0;
993
994         return (intptr_t) thread->tid;
995 }
996
997
998 /* thread_set_state_runnable ***************************************************
999
1000    Set the current state of the given thread to THREAD_STATE_RUNNABLE.
1001
1002    NOTE: If the thread has already terminated, don't set the state.
1003          This is important for threads_detach_thread.
1004
1005 *******************************************************************************/
1006
1007 void thread_set_state_runnable(threadobject *t)
1008 {
1009         /* Set the state inside a lock. */
1010
1011         threadlist_lock();
1012
1013         if (t->state != THREAD_STATE_TERMINATED) {
1014                 t->state = THREAD_STATE_RUNNABLE;
1015
1016                 DEBUGTHREADS("is RUNNABLE", t);
1017         }
1018
1019         threadlist_unlock();
1020 }
1021
1022
1023 /* thread_set_state_waiting ****************************************************
1024
1025    Set the current state of the given thread to THREAD_STATE_WAITING.
1026
1027    NOTE: If the thread has already terminated, don't set the state.
1028          This is important for threads_detach_thread.
1029
1030 *******************************************************************************/
1031
1032 void thread_set_state_waiting(threadobject *t)
1033 {
1034         /* Set the state inside a lock. */
1035
1036         threadlist_lock();
1037
1038         if (t->state != THREAD_STATE_TERMINATED) {
1039                 t->state = THREAD_STATE_WAITING;
1040
1041                 DEBUGTHREADS("is WAITING", t);
1042         }
1043
1044         threadlist_unlock();
1045 }
1046
1047
1048 /* thread_set_state_timed_waiting **********************************************
1049
1050    Set the current state of the given thread to
1051    THREAD_STATE_TIMED_WAITING.
1052
1053    NOTE: If the thread has already terminated, don't set the state.
1054          This is important for threads_detach_thread.
1055
1056 *******************************************************************************/
1057
1058 void thread_set_state_timed_waiting(threadobject *t)
1059 {
1060         /* Set the state inside a lock. */
1061
1062         threadlist_lock();
1063
1064         if (t->state != THREAD_STATE_TERMINATED) {
1065                 t->state = THREAD_STATE_TIMED_WAITING;
1066
1067                 DEBUGTHREADS("is TIMED_WAITING", t);
1068         }
1069
1070         threadlist_unlock();
1071 }
1072
1073
1074 /* thread_set_state_terminated *************************************************
1075
1076    Set the current state of the given thread to
1077    THREAD_STATE_TERMINATED.
1078
1079 *******************************************************************************/
1080
1081 void thread_set_state_terminated(threadobject *t)
1082 {
1083         /* Set the state inside a lock. */
1084
1085         threadlist_lock();
1086
1087         t->state = THREAD_STATE_TERMINATED;
1088
1089         DEBUGTHREADS("is TERMINATED", t);
1090
1091         threadlist_unlock();
1092 }
1093
1094
1095 /* thread_get_thread **********************************************************
1096
1097    Return the thread data structure of the given Java thread object.
1098
1099    ARGUMENTS:
1100        h ... java.lang.{VM}Thread object
1101
1102    RETURN VALUE:
1103        the thread object
1104
1105 *******************************************************************************/
1106
1107 threadobject *thread_get_thread(java_handle_t *h)
1108 {
1109 #if defined(WITH_JAVA_RUNTIME_LIBRARY_GNU_CLASSPATH)
1110
1111         java_lang_VMThread jlvmt(h);
1112         threadobject* t = jlvmt.get_vmdata();
1113
1114 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_OPENJDK)
1115
1116         /* XXX This is just a quick hack. */
1117         threadobject* t;
1118         bool          equal;
1119
1120         threadlist_lock();
1121
1122         for (t = threadlist_first(); t != NULL; t = threadlist_next(t)) {
1123                 LLNI_equals(t->object, h, equal);
1124
1125                 if (equal == true)
1126                         break;
1127         }
1128
1129         threadlist_unlock();
1130
1131 #elif defined(WITH_JAVA_RUNTIME_LIBRARY_CLDC1_1)
1132
1133         log_println("threads_get_thread: IMPLEMENT ME!");
1134         threadobject* t = NULL;
1135
1136 #else
1137 # error unknown classpath configuration
1138 #endif
1139
1140         return t;
1141 }
1142
1143
1144 /* threads_thread_is_alive *****************************************************
1145
1146    Returns if the give thread is alive.
1147
1148 *******************************************************************************/
1149
1150 bool threads_thread_is_alive(threadobject *t)
1151 {
1152         int state;
1153
1154         state = cacaothread_get_state(t);
1155
1156         switch (state) {
1157         case THREAD_STATE_NEW:
1158         case THREAD_STATE_TERMINATED:
1159                 return false;
1160
1161         case THREAD_STATE_RUNNABLE:
1162         case THREAD_STATE_BLOCKED:
1163         case THREAD_STATE_WAITING:
1164         case THREAD_STATE_TIMED_WAITING:
1165                 return true;
1166
1167         default:
1168                 vm_abort("threads_thread_is_alive: unknown thread state %d", state);
1169         }
1170
1171         /* keep compiler happy */
1172
1173         return false;
1174 }
1175
1176
1177 /* threads_dump ****************************************************************
1178
1179    Dumps info for all threads running in the JVM.  This function is
1180    called when SIGQUIT (<ctrl>-\) is sent to CACAO.
1181
1182 *******************************************************************************/
1183
1184 void threads_dump(void)
1185 {
1186         threadobject *t;
1187
1188         /* XXX we should stop the world here */
1189
1190         /* Lock the thread lists. */
1191
1192         threadlist_lock();
1193
1194         printf("Full thread dump CACAO "VERSION":\n");
1195
1196         /* iterate over all started threads */
1197
1198         for (t = threadlist_first(); t != NULL; t = threadlist_next(t)) {
1199                 /* ignore threads which are in state NEW */
1200                 if (t->state == THREAD_STATE_NEW)
1201                         continue;
1202
1203 #if defined(ENABLE_GC_CACAO)
1204                 /* Suspend the thread. */
1205                 /* XXX Is the suspend reason correct? */
1206
1207                 if (threads_suspend_thread(t, SUSPEND_REASON_JNI) == false)
1208                         vm_abort("threads_dump: threads_suspend_thread failed");
1209 #endif
1210
1211                 /* Print thread info. */
1212
1213                 printf("\n");
1214                 thread_print_info(t);
1215                 printf("\n");
1216
1217                 /* Print trace of thread. */
1218
1219                 stacktrace_print_of_thread(t);
1220
1221 #if defined(ENABLE_GC_CACAO)
1222                 /* Resume the thread. */
1223
1224                 if (threads_resume_thread(t) == false)
1225                         vm_abort("threads_dump: threads_resume_thread failed");
1226 #endif
1227         }
1228
1229         /* Unlock the thread lists. */
1230
1231         threadlist_unlock();
1232 }
1233
1234 } // extern "C"
1235
1236
1237 /*
1238  * These are local overrides for various environment variables in Emacs.
1239  * Please do not remove this and leave it at the end of the file, where
1240  * Emacs will automagically detect them.
1241  * ---------------------------------------------------------------------
1242  * Local variables:
1243  * mode: c++
1244  * indent-tabs-mode: t
1245  * c-basic-offset: 4
1246  * tab-width: 4
1247  * End:
1248  * vim:noexpandtab:sw=4:ts=4:
1249  */