jamvm
view src/thread.c @ 409:8d1dc4195148
Fix errors introduced by move to Mercurial.
2008-08-04 Andrew John Hughes <gnu_andrew@member.fsf.org>
* src/symbol.h:
Remove #ifdefs in #define.
* src/thread.c:
Add missing semicolon and move system_group
definition up.
2008-08-04 Andrew John Hughes <gnu_andrew@member.fsf.org>
* src/symbol.h:
Remove #ifdefs in #define.
* src/thread.c:
Add missing semicolon and move system_group
definition up.
| author | andrew |
|---|---|
| date | Tue Aug 05 08:20:38 2008 +0100 (2008-08-05) |
| parents | f5ea446164a8 |
| children |
line source
1 /*
2 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
3 * Robert Lougher <rob@lougher.org.uk>.
4 *
5 * This file is part of JamVM.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2,
10 * or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <signal.h>
26 #include <sched.h>
28 #include "jam.h"
29 #include "thread.h"
30 #include "lock.h"
31 #include "hash.h"
32 #include "symbol.h"
33 #include "excep.h"
35 #ifdef TRACETHREAD
36 #define TRACE(fmt, ...) jam_printf(fmt, ## __VA_ARGS__)
37 #else
38 #define TRACE(fmt, ...)
39 #endif
41 #define HASHTABSZE 1<<4
42 HashTable thread_id_map;
44 /* Size of Java stack to use if no size is given */
45 static int dflt_stack_size;
47 /* Thread create/destroy lock and condvar */
48 static pthread_mutex_t lock;
49 static pthread_cond_t cv;
51 /* lock and condvar used by main thread to wait for
52 * all non-daemon threads to die */
53 static pthread_mutex_t exit_lock;
54 static pthread_cond_t exit_cv;
56 /* Monitor for sleeping threads to do a timed-wait against */
57 static Monitor sleep_mon;
59 /* Thread specific key holding thread's Thread pntr */
60 static pthread_key_t threadKey;
62 /* Attributes for spawned threads */
63 static pthread_attr_t attributes;
65 /* The main thread info - head of the thread list */
66 static Thread main_thread;
68 /* Main thread ExecEnv */
69 static ExecEnv main_ee;
71 /* Various field offsets into java.lang.Thread &
72 java.lang.VMThread - cached at startup and used
73 in thread creation */
74 static int vmData_offset;
75 static int daemon_offset;
76 static int group_offset;
77 static int priority_offset;
78 static int name_offset;
79 static int vmthread_offset;
80 static int thread_offset;
81 static int threadId_offset;
83 /* Method table indexes of Thread.run method and
84 * ThreadGroup.removeThread - cached at startup */
85 static int run_mtbl_idx;
86 static int rmveThrd_mtbl_idx;
88 static MethodBlock *addThread_mb;
89 static MethodBlock *init_mb;
91 /* Cached java.lang.Thread class */
92 static Class *thread_class;
93 /* VMDIFF: For OpenJDK, we need ThreadGroup. For
94 Classpath, VMThread. */
95 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
96 static Class *vmthread_class;
97 #elif WITH_JAVA_RUNTIME_LIBRARY_OPENJDK
98 static Class *thrdGrp_class;
99 #endif
101 /* Count of non-daemon threads still running in VM */
102 static int non_daemon_thrds = 0;
104 /* Counts used in the ThreadMXBean management API. The
105 counts start from one to include the main thread */
106 static int threads_count = 1;
107 static int peak_threads_count = 1;
108 static long long total_started_threads_count = 1;
110 /* Guards against threads starting while the "world is stopped" */
111 static int all_threads_suspended = FALSE;
112 static int threads_waiting_to_start = 0;
114 static int main_exited = FALSE;
116 /* Bitmap - used for generating unique thread ID's */
117 #define MAP_INC 32
118 static unsigned int *tidBitmap = NULL;
119 static int tidBitmapSize = 0;
121 /* Mark a threadID value as no longer used */
122 #define freeThreadID(n) tidBitmap[(n-1)>>5] &= ~(1<<((n-1)&0x1f))
124 /* Generate a new thread ID - assumes the thread queue
125 * lock is held */
127 static int genThreadID() {
128 int i = 0;
130 retry:
131 for(; i < tidBitmapSize; i++) {
132 if(tidBitmap[i] != 0xffffffff) {
133 int n = ffs(~tidBitmap[i]);
134 tidBitmap[i] |= 1 << (n-1);
135 return (i<<5) + n;
136 }
137 }
139 tidBitmap = (unsigned int *)sysRealloc(tidBitmap,
140 (tidBitmapSize + MAP_INC) * sizeof(unsigned int));
141 memset(tidBitmap + tidBitmapSize, 0, MAP_INC * sizeof(unsigned int));
142 tidBitmapSize += MAP_INC;
143 goto retry;
144 }
146 int threadIsAlive(Thread *thread) {
147 return thread->state != 0;
148 }
150 int threadInterrupted(Thread *thread) {
151 int r = thread->interrupted;
152 thread->interrupted = FALSE;
153 return r;
154 }
156 int threadIsInterrupted(Thread *thread) {
157 return thread->interrupted;
158 }
160 void threadSleep(Thread *thread, long long ms, int ns) {
162 /* A sleep of zero should just yield, but a wait
163 of zero is "forever". Therefore wait for a tiny
164 amount -- this should yield and we also get the
165 interrupted checks. */
166 if(ms == 0 && ns == 0)
167 ns = 1;
169 monitorLock(&sleep_mon, thread);
170 monitorWait(&sleep_mon, thread, ms, ns);
171 monitorUnlock(&sleep_mon, thread);
172 }
174 void threadYield(Thread *thread) {
175 sched_yield();
176 }
178 void threadInterrupt(Thread *thread) {
179 Monitor *mon;
180 Thread *self = threadSelf();
182 /* monitorWait sets wait_mon _before_ checking interrupted status. Therefore,
183 if wait_mon is null, interrupted status will be noticed. This guards
184 against a race-condition leading to an interrupt being missed. The memory
185 barrier ensures correct ordering on SMP systems. */
186 thread->interrupted = TRUE;
187 MBARRIER();
189 if((mon = thread->wait_mon) != NULL && thread->wait_next != NULL) {
190 int locked;
191 thread->interrupting = TRUE;
193 /* Ensure the thread has actually entered the wait
194 (else the signal will be lost) */
196 while(!(locked = !pthread_mutex_trylock(&mon->lock)) && mon->owner == NULL)
197 sched_yield();
199 pthread_cond_signal(&thread->wait_cv);
201 if(locked)
202 pthread_mutex_unlock(&mon->lock);
203 }
205 /* Handle the case where the thread is blocked in a system call.
206 This will knock it out with an EINTR. The suspend signal
207 handler will just return (as in the user doing a kill), and do
208 nothing otherwise. */
210 /* Note, under Linuxthreads pthread_kill obtains a lock on the thread
211 being signalled. If another thread is suspending all threads,
212 and the interrupting thread is earlier in the thread list than the
213 thread being interrupted, it can be suspended holding the lock.
214 When the suspending thread tries to signal the interrupted thread
215 it will deadlock. To prevent this, disable suspension. */
217 fastDisableSuspend(self);
218 pthread_kill(thread->tid, SIGUSR1);
219 fastEnableSuspend(self);
220 }
222 void *getStackTop(Thread *thread) {
223 return thread->stack_top;
224 }
226 void *getStackBase(Thread *thread) {
227 return thread->stack_base;
228 }
230 Thread *threadSelf0(Object *vmThread) {
231 return (Thread*)(INST_DATA(vmThread)[vmData_offset]);
232 }
234 Thread *threadSelf() {
235 return (Thread*)pthread_getspecific(threadKey);
236 }
238 void setThreadSelf(Thread *thread) {
239 pthread_setspecific(threadKey, thread);
240 pthread_cond_init(&thread->wait_cv, NULL);
241 }
243 ExecEnv *getExecEnv() {
244 return threadSelf()->ee;
245 }
247 char *getThreadStateString(Thread *thread) {
248 switch(thread->state) {
249 case CREATING:
250 case STARTED:
251 return "NEW";
252 case RUNNING:
253 case SUSPENDED:
254 return "RUNNABLE";
255 case WAITING:
256 return "WAITING";
257 case TIMED_WAITING:
258 return "TIMED_WAITING";
259 case BLOCKED:
260 return "BLOCKED";
261 }
262 return "INVALID";
263 }
265 int getThreadsCount() {
266 return threads_count;
267 }
269 int getPeakThreadsCount() {
270 return peak_threads_count;
271 }
273 long long getTotalStartedThreadsCount() {
274 return total_started_threads_count;
275 }
277 void resetPeakThreadsCount() {
278 Thread *self = threadSelf();
280 /* Grab the thread lock to protect against
281 concurrent update by threads starting/dying */
282 disableSuspend(self);
283 pthread_mutex_lock(&lock);
284 peak_threads_count = threads_count;
285 pthread_mutex_unlock(&lock);
286 enableSuspend(self);
287 }
289 void initialiseJavaStack(ExecEnv *ee) {
290 int stack_size = ee->stack_size ?
291 (ee->stack_size > MIN_STACK ? ee->stack_size : MIN_STACK) : dflt_stack_size;
292 char *stack = sysMalloc(stack_size);
293 MethodBlock *mb = (MethodBlock *) stack;
294 Frame *top = (Frame *) (mb+1);
296 top->ostack = (uintptr_t*)(top+1);
297 top->lvars = (uintptr_t*)top;
298 mb->max_stack = 0;
299 top->prev = NULL;
300 top->mb = mb;
302 ee->stack = stack;
303 ee->last_frame = top;
304 ee->stack_size = stack_size;
305 ee->stack_end = stack + stack_size-STACK_RED_ZONE_SIZE;
306 }
308 long long javaThreadId(Thread *thread) {
309 return *(long long*)&(INST_DATA(thread->ee->thread)[threadId_offset]);
310 }
312 Thread *findHashedThread(Thread *thread, long long id) {
314 #define FOUND(ptr) ptr
315 #define DELETED ((void*)-1)
316 #define PREPARE(thread_id) thread
317 #define SCAVENGE(ptr) ptr == DELETED
318 #define HASH(thread_id) (int)thread_id
319 #define COMPARE(thread_id, ptr, hash1, hash2) ptr != DELETED && \
320 (hash1 == hash2 && thread_id == javaThreadId(ptr))
322 Thread *ptr;
324 /* Add if absent, scavenge, locked */
325 findHashEntry(thread_id_map, id, ptr, (thread != NULL), TRUE, TRUE);
327 return ptr;
328 }
330 void addThreadToHash(Thread *thread) {
331 findHashedThread(thread, javaThreadId(thread));
332 }
334 Thread *findThreadById(long long id) {
335 return findHashedThread(NULL, id);
336 }
338 void deleteThreadFromHash(Thread *thread) {
340 #undef HASH
341 #undef COMPARE
342 #define HASH(ptr) (int)javaThreadId(ptr)
343 #define COMPARE(ptr1, ptr2, hash1, hash2) ptr1 == ptr2
345 deleteHashEntry(thread_id_map, thread, TRUE);
346 }
348 /* VMDIFF: OpenJDK does not need a VMThread but
349 does need a thread group. */
350 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
351 Object *initJavaThread(Thread *thread, char is_daemon, char *name) {
352 Object *vmthread, *jlthread, *thread_name = NULL;
353 /* Create the java.lang.Thread object and the VMThread */
354 if((vmthread = allocObject(vmthread_class)) == NULL ||
355 (jlthread = allocObject(thread_class)) == NULL)
356 return NULL;
358 INST_DATA(vmthread)[vmData_offset] = (uintptr_t)thread;
359 INST_DATA(vmthread)[thread_offset] = (uintptr_t)jlthread;
360 #elif WITH_JAVA_RUNTIME_LIBRARY_OPENJDK
361 Object *initJavaThread(Thread *thread, char is_daemon, Object *thrdgrp, char *name) {
362 Object *jlthread, *thread_name = NULL;
364 /* Create the java.lang.Thread object */
365 if((jlthread = allocObject(thread_class)) == NULL)
366 return NULL;
367 #endif
369 thread->ee->thread = jlthread;
371 /* Create the string for the thread name. If null is specified
372 the initialiser method will generate a name of the form Thread-X */
373 if(name != NULL && (thread_name = Cstr2String(name)) == NULL)
374 return NULL;
376 /* Call the initialiser method -- this is for use by threads
377 created or attached by the VM "outside" of Java */
378 /* VMDIFF: The daemon status and priority are not arguments
379 for OpenJDK's java.lang.Thread, so we poke them into place instead. */
380 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
381 executeMethod(jlthread, init_mb, vmthread, thread_name, NORM_PRIORITY, is_daemon);
382 #elif WITH_JAVA_RUNTIME_LIBRARY_OPENJDK
383 executeMethod(jlthread, init_mb, thrdgrp, thread_name);
384 INST_DATA(jlthread)[daemon_offset] = is_daemon;
385 INST_DATA(jlthread)[priority_offset] = NORM_PRIORITY;
386 #endif
388 /* Add thread to thread ID map hash table. */
389 addThreadToHash(thread);
391 return jlthread;
392 }
394 void initThread(Thread *thread, char is_daemon, void *stack_base) {
396 /* Create the thread stack and store the thread structure in
397 thread-specific memory */
398 initialiseJavaStack(thread->ee);
399 setThreadSelf(thread);
401 /* Record the thread's stack base */
402 thread->stack_base = stack_base;
404 /* Grab thread list lock. This also stops suspension */
405 pthread_mutex_lock(&lock);
407 /* If all threads are suspended (i.e. GC in progress) we cannot start
408 until the threads are resumed. Record we're waiting and wait until
409 the world is restarted... */
411 threads_waiting_to_start++;
413 while(all_threads_suspended)
414 pthread_cond_wait(&cv, &lock);
416 threads_waiting_to_start--;
418 /* add to thread list... After this point (once we release the lock)
419 we are suspendable */
420 if((thread->next = main_thread.next))
421 main_thread.next->prev = thread;
422 thread->prev = &main_thread;
423 main_thread.next = thread;
425 /* Keep track of threads counts */
426 if(++threads_count > peak_threads_count)
427 peak_threads_count = threads_count;
428 total_started_threads_count++;
430 /* If we're not a deamon thread the main thread must
431 wait until we exit */
432 if(!is_daemon)
433 non_daemon_thrds++;
435 /* Get a thread ID (used in thin locking) and
436 record we're now running */
437 thread->id = genThreadID();
438 thread->state = RUNNING;
440 pthread_cond_broadcast(&cv);
441 pthread_mutex_unlock(&lock);
442 }
444 Thread *attachThread(char *name, char is_daemon, void *stack_base, Thread *thread, Object *group) {
445 Object *java_thread;
447 /* Create the ExecEnv for the thread */
448 ExecEnv *ee = sysMalloc(sizeof(ExecEnv));
449 memset(ee, 0, sizeof(ExecEnv));
451 thread->tid = pthread_self();
452 thread->ee = ee;
454 /* Complete initialisation of the thread structure, create the thread
455 stack and add the thread to the thread list */
456 initThread(thread, is_daemon, stack_base);
458 /* Initialise the Java-level thread objects representing this thread */
459 /* VMDIFF: The thread group needs to be poked into place for Classpath */
460 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
461 if((java_thread = initJavaThread(thread, is_daemon, name)) == NULL)
462 #elif WITH_JAVA_RUNTIME_LIBRARY_OPENJDK
463 if((java_thread = initJavaThread(thread, is_daemon, group, name)) == NULL)
464 #endif
465 return NULL;
467 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
468 /* Initialiser doesn't handle the thread group */
469 INST_DATA(java_thread)[group_offset] = (uintptr_t)group;
470 #endif
471 executeMethod(group, addThread_mb, java_thread);
473 /* We're now attached to the VM...*/
474 TRACE("Thread 0x%x id: %d attached\n", thread, thread->id);
475 return thread;
476 }
478 void detachThread(Thread *thread) {
479 Object *group, *excep;
480 ExecEnv *ee = thread->ee;
481 Object *jThread = ee->thread;
482 Object *vmthread = (Object*)INST_DATA(jThread)[vmthread_offset];
484 /* Get the thread's group */
485 group = (Object *)INST_DATA(jThread)[group_offset];
487 /* If there's an uncaught exception, call uncaughtException on the thread's
488 exception handler, or the thread's group if this is unset */
489 if((excep = exceptionOccurred())) {
490 FieldBlock *fb = findField(thread_class, SYMBOL(exceptionHandler),
491 SYMBOL(sig_java_lang_Thread_UncaughtExceptionHandler));
492 Object *thread_handler = fb == NULL ? NULL : (Object *)INST_DATA(jThread)[fb->offset];
493 Object *handler = thread_handler == NULL ? group : thread_handler;
495 MethodBlock *uncaught_exp = lookupMethod(handler->class, SYMBOL(uncaughtException),
496 SYMBOL(_java_lang_Thread_java_lang_Throwable__V));
498 if(uncaught_exp) {
499 clearException();
500 executeMethod(handler, uncaught_exp, jThread, excep);
501 } else
502 printException();
503 }
505 /* remove thread from thread group */
506 executeMethod(group, (CLASS_CB(group->class))->method_table[rmveThrd_mtbl_idx], jThread);
508 /* set VMThread ref in Thread object to null - operations after this
509 point will result in an IllegalThreadStateException */
510 INST_DATA(jThread)[vmthread_offset] = 0;
512 /* Remove thread from the ID map hash table */
513 deleteThreadFromHash(thread);
515 /* Disable suspend to protect lock operation */
516 disableSuspend(thread);
518 /* Grab global lock, and update thread structures protected by
519 it (thread list, thread ID and number of daemon threads) */
520 pthread_mutex_lock(&lock);
522 /* remove from thread list... */
523 if((thread->prev->next = thread->next))
524 thread->next->prev = thread->prev;
526 /* One less live thread */
527 threads_count--;
529 /* Recycle the thread's thread ID */
530 freeThreadID(thread->id);
532 /* Handle daemon thread status */
533 if(!INST_DATA(jThread)[daemon_offset])
534 non_daemon_thrds--;
536 pthread_mutex_unlock(&lock);
538 /* notify any threads waiting on VMThread object -
539 these are joining this thread */
540 objectLock(vmthread);
541 objectNotifyAll(vmthread);
542 objectUnlock(vmthread);
544 /* It is safe to free the thread's ExecEnv and stack now as these are
545 only used within the thread. It is _not_ safe to free the native
546 thread structure as another thread may be concurrently accessing it.
547 However, they must have a reference to the VMThread -- therefore, it
548 is safe to free during GC when the VMThread is determined to be no
549 longer reachable. */
550 sysFree(ee->stack);
551 sysFree(ee);
553 /* If no more daemon threads notify the main thread (which
554 may be waiting to exit VM). Note, this is not protected
555 by lock, but main thread checks again */
557 if(non_daemon_thrds == 0) {
558 /* No need to bother with disabling suspension
559 * around lock, as we're no longer on thread list */
560 pthread_mutex_lock(&exit_lock);
561 pthread_cond_signal(&exit_cv);
562 pthread_mutex_unlock(&exit_lock);
563 }
565 TRACE("Thread 0x%x id: %d detached from VM\n", thread, thread->id);
566 }
568 void *threadStart(void *arg) {
569 Thread *thread = (Thread *)arg;
570 Object *jThread = thread->ee->thread;
572 /* Parent thread created thread with suspension disabled.
573 This is inherited so we need to enable */
574 enableSuspend(thread);
576 /* Complete initialisation of the thread structure, create the thread
577 stack and add the thread to the thread list */
578 initThread(thread, INST_DATA(jThread)[daemon_offset], &thread);
580 /* Add thread to thread ID map hash table. */
581 addThreadToHash(thread);
583 /* Execute the thread's run method */
584 executeMethod(jThread, CLASS_CB(jThread->class)->method_table[run_mtbl_idx]);
586 /* Run has completed. Detach the thread from the VM and exit */
587 detachThread(thread);
589 TRACE("Thread 0x%x id: %d exited\n", thread, thread->id);
590 return NULL;
591 }
593 void createJavaThread(Object *jThread, long long stack_size) {
594 ExecEnv *ee;
595 Thread *thread;
596 Thread *self = threadSelf();
597 /* VMDIFF: No VMThread in OpenJDK */
598 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
599 Object *vmthread = allocObject(vmthread_class);
601 if(vmthread == NULL)
602 return;
603 #endif
605 disableSuspend(self);
607 pthread_mutex_lock(&lock);
608 if(INST_DATA(jThread)[vmthread_offset]) {
609 pthread_mutex_unlock(&lock);
610 enableSuspend(self);
611 signalException(java_lang_IllegalThreadStateException, "thread already started");
612 return;
613 }
615 ee = (ExecEnv*)sysMalloc(sizeof(ExecEnv));
616 thread = (Thread*)sysMalloc(sizeof(Thread));
617 memset(ee, 0, sizeof(ExecEnv));
618 memset(thread, 0, sizeof(Thread));
620 thread->ee = ee;
621 ee->thread = jThread;
622 ee->stack_size = stack_size;
624 /* VMDIFF: No VMThread in OpenJDK */
625 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
626 INST_DATA(vmthread)[vmData_offset] = (uintptr_t)thread;
627 INST_DATA(vmthread)[thread_offset] = (uintptr_t)jThread;
628 INST_DATA(jThread)[vmthread_offset] = (uintptr_t)vmthread;
629 #endif
631 pthread_mutex_unlock(&lock);
633 if(pthread_create(&thread->tid, &attributes, threadStart, thread)) {
634 INST_DATA(jThread)[vmthread_offset] = 0;
635 sysFree(ee);
636 enableSuspend(self);
637 signalException(java_lang_OutOfMemoryError, "can't create thread");
638 return;
639 }
641 pthread_mutex_lock(&lock);
643 /* Wait for thread to start */
644 while(thread->state == 0)
645 pthread_cond_wait(&cv, &lock);
647 pthread_mutex_unlock(&lock);
648 enableSuspend(self);
649 }
651 static void initialiseSignals();
653 Thread *attachJNIThread(char *name, char is_daemon, Object *group) {
654 Thread *thread = sysMalloc(sizeof(Thread));
655 void *stack_base = nativeStackBase();
657 /* If no group is given add it to the main group */
658 if(group == NULL)
659 group = (Object*)INST_DATA(main_ee.thread)[group_offset];
661 /* Initialise internal thread structure */
662 memset(thread, 0, sizeof(Thread));
664 /* Externally created threads will not inherit signal state */
665 initialiseSignals();
667 /* Initialise the thread and add it to the VM thread list */
668 return attachThread(name, is_daemon, stack_base, thread, group);
669 }
671 void detachJNIThread(Thread *thread) {
672 /* The JNI spec says we should release all locks held by this thread.
673 We don't do this (yet), and only remove the thread from the VM. */
674 detachThread(thread);
675 }
677 static void *shell(void *args) {
678 void *start = ((void**)args)[1];
679 Thread *self = ((Thread**)args)[2];
681 if(main_exited)
682 return NULL;
684 /* VM helper threads should be added to the system group, but this doesn't
685 exist. As the root group is main, we add it to that for now... */
686 attachThread(((char**)args)[0], TRUE, &self, self,
687 (Object*)INST_DATA(main_ee.thread)[group_offset]);
689 sysFree(args);
690 (*(void(*)(Thread*))start)(self);
691 return NULL;
692 }
694 void createVMThread(char *name, void (*start)(Thread*)) {
695 Thread *thread = (Thread*)sysMalloc(sizeof(Thread));
696 void **args = sysMalloc(3 * sizeof(void*));
697 pthread_t tid;
699 args[0] = name;
700 args[1] = start;
701 args[2] = thread;
703 memset(thread, 0, sizeof(Thread));
704 pthread_create(&tid, &attributes, shell, args);
706 /* Wait for thread to start */
708 pthread_mutex_lock(&lock);
709 while(thread->state == 0)
710 pthread_cond_wait(&cv, &lock);
711 pthread_mutex_unlock(&lock);
712 }
714 void suspendThread(Thread *thread) {
715 thread->suspend = TRUE;
716 MBARRIER();
718 if(!thread->blocking) {
719 TRACE("Sending suspend signal to thread 0x%x id: %d\n", thread, thread->id);
720 pthread_kill(thread->tid, SIGUSR1);
721 }
723 while(thread->blocking != SUSP_BLOCKING && thread->state != SUSPENDED) {
724 TRACE("Waiting for thread 0x%x id: %d to suspend\n", thread, thread->id);
725 sched_yield();
726 }
727 }
729 void resumeThread(Thread *thread) {
730 thread->suspend = FALSE;
731 MBARRIER();
733 if(!thread->blocking) {
734 TRACE("Sending resume signal to thread 0x%x id: %d\n", thread, thread->id);
735 pthread_kill(thread->tid, SIGUSR1);
736 }
738 while(thread->state == SUSPENDED) {
739 TRACE("Waiting for thread 0x%x id: %d to resume\n", thread, thread->id);
740 sched_yield();
741 }
742 }
744 void suspendAllThreads(Thread *self) {
745 Thread *thread;
747 TRACE("Thread 0x%x id: %d is suspending all threads\n", self, self->id);
748 pthread_mutex_lock(&lock);
750 for(thread = &main_thread; thread != NULL; thread = thread->next) {
751 if(thread == self)
752 continue;
754 thread->suspend = TRUE;
755 MBARRIER();
757 if(!thread->blocking) {
758 TRACE("Sending suspend signal to thread 0x%x id: %d\n", thread, thread->id);
759 pthread_kill(thread->tid, SIGUSR1);
760 }
761 }
763 for(thread = &main_thread; thread != NULL; thread = thread->next) {
764 if(thread == self)
765 continue;
767 while(thread->blocking != SUSP_BLOCKING && thread->state != SUSPENDED) {
768 TRACE("Waiting for thread 0x%x id: %d to suspend\n", thread, thread->id);
769 sched_yield();
770 }
771 }
773 all_threads_suspended = TRUE;
775 TRACE("All threads suspended...\n");
776 pthread_mutex_unlock(&lock);
777 }
779 void resumeAllThreads(Thread *self) {
780 Thread *thread;
782 TRACE("Thread 0x%x id: %d is resuming all threads\n", self, self->id);
783 pthread_mutex_lock(&lock);
785 for(thread = &main_thread; thread != NULL; thread = thread->next) {
786 if(thread == self)
787 continue;
789 thread->suspend = FALSE;
790 MBARRIER();
792 if(!thread->blocking) {
793 TRACE("Sending resume signal to thread 0x%x id: %d\n", thread, thread->id);
794 pthread_kill(thread->tid, SIGUSR1);
795 }
796 }
798 for(thread = &main_thread; thread != NULL; thread = thread->next) {
799 while(thread->state == SUSPENDED) {
800 TRACE("Waiting for thread 0x%x id: %d to resume\n", thread, thread->id);
801 sched_yield();
802 }
803 }
805 all_threads_suspended = FALSE;
806 if(threads_waiting_to_start) {
807 TRACE("%d threads waiting to start...\n", threads_waiting_to_start);
808 pthread_cond_broadcast(&cv);
809 }
811 TRACE("All threads resumed...\n");
812 pthread_mutex_unlock(&lock);
813 }
815 static void suspendLoop(Thread *thread) {
816 char old_state = thread->state;
817 sigjmp_buf env;
818 sigset_t mask;
820 sigsetjmp(env, FALSE);
822 thread->stack_top = &env;
823 thread->state = SUSPENDED;
824 MBARRIER();
826 sigfillset(&mask);
827 sigdelset(&mask, SIGUSR1);
828 sigdelset(&mask, SIGTERM);
830 while(thread->suspend && !thread->blocking)
831 sigsuspend(&mask);
833 thread->state = old_state;
834 MBARRIER();
835 }
837 static void suspendHandler(int sig) {
838 Thread *thread = threadSelf();
839 suspendLoop(thread);
840 }
842 /* The "slow" disable. Normally used when a thread enters
843 a blocking code section, such as waiting on a lock. */
845 void disableSuspend0(Thread *thread, void *stack_top) {
846 sigset_t mask;
848 thread->stack_top = stack_top;
849 thread->blocking = SUSP_BLOCKING;
850 MBARRIER();
852 sigemptyset(&mask);
853 sigaddset(&mask, SIGUSR1);
854 pthread_sigmask(SIG_BLOCK, &mask, NULL);
855 }
857 void enableSuspend(Thread *thread) {
858 sigset_t mask;
860 thread->blocking = FALSE;
861 MBARRIER();
863 if(thread->suspend) {
864 TRACE("Thread 0x%x id: %d is self suspending\n", thread, thread->id);
865 suspendLoop(thread);
866 TRACE("Thread 0x%x id: %d resumed\n", thread, thread->id);
867 }
869 sigemptyset(&mask);
870 sigaddset(&mask, SIGUSR1);
871 pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
872 }
874 /* Fast disable/enable suspend doesn't modify the signal mask
875 or save the thread context. It's used in critical code
876 sections where the thread cannot be suspended (such as
877 modifying the loaded classes hash table). Thread supension
878 blocks until the thread self-suspends. */
880 void fastEnableSuspend(Thread *thread) {
882 thread->blocking = FALSE;
883 MBARRIER();
885 if(thread->suspend) {
886 sigset_t mask;
888 sigemptyset(&mask);
889 sigaddset(&mask, SIGUSR1);
890 pthread_sigmask(SIG_BLOCK, &mask, NULL);
892 TRACE("Thread 0x%x id: %d is fast self suspending\n", thread, thread->id);
893 suspendLoop(thread);
894 TRACE("Thread 0x%x id: %d resumed\n", thread, thread->id);
896 pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
897 }
898 }
900 void dumpThreadsLoop(Thread *self) {
901 char buffer[256];
902 Thread *thread;
903 sigset_t mask;
904 int sig;
906 sigemptyset(&mask);
907 sigaddset(&mask, SIGQUIT);
908 sigaddset(&mask, SIGINT);
910 disableSuspend0(self, &self);
911 for(;;) {
912 sigwait(&mask, &sig);
914 /* If it was an interrupt (e.g. Ctrl-C) terminate the VM */
915 if(sig == SIGINT)
916 exitVM(0);
918 /* It must be a SIGQUIT. Do a thread dump */
920 suspendAllThreads(self);
921 jam_printf("\n------ JamVM version %s Full Thread Dump -------\n", VERSION);
923 for(thread = &main_thread; thread != NULL; thread = thread->next) {
924 uintptr_t *thr_data = INST_DATA(thread->ee->thread);
925 int priority = thr_data[priority_offset];
926 int daemon = thr_data[daemon_offset];
927 Frame *last = thread->ee->last_frame;
929 /* Get thread name; we don't use String2Cstr(), as this mallocs memory
930 and may deadlock with a thread suspended in malloc/realloc/free */
931 String2Buff((Object*)thr_data[name_offset], buffer, sizeof(buffer));
933 jam_printf("\n\"%s\"%s %p priority: %d tid: %p id: %d state: %s (%d)\n",
934 buffer, daemon ? " (daemon)" : "", thread, priority, thread->tid,
935 thread->id, getThreadStateString(thread), thread->state);
937 while(last->prev != NULL) {
938 for(; last->mb != NULL; last = last->prev) {
939 MethodBlock *mb = last->mb;
940 ClassBlock *cb = CLASS_CB(mb->class);
942 /* Convert slashes in class name to dots. Similar to above,
943 we don't use slash2dots(), as this mallocs memory */
944 slash2dots2buff(cb->name, buffer, sizeof(buffer));
945 jam_printf("\tat %s.%s(", buffer, mb->name);
947 if(mb->access_flags & ACC_NATIVE)
948 jam_printf("Native method");
949 else
950 if(cb->source_file_name == NULL)
951 jam_printf("Unknown source");
952 else {
953 int line = mapPC2LineNo(mb, last->last_pc);
954 jam_printf("%s", cb->source_file_name);
955 if(line != -1)
956 jam_printf(":%d", line);
957 }
958 jam_printf(")\n");
959 }
960 last = last->prev;
961 }
962 }
963 resumeAllThreads(self);
964 }
965 }
967 static void initialiseSignals() {
968 struct sigaction act;
969 sigset_t mask;
971 act.sa_handler = suspendHandler;
972 sigemptyset(&act.sa_mask);
973 act.sa_flags = 0;
974 sigaction(SIGUSR1, &act, NULL);
976 sigemptyset(&mask);
977 sigaddset(&mask, SIGQUIT);
978 sigaddset(&mask, SIGINT);
979 sigaddset(&mask, SIGPIPE);
980 sigprocmask(SIG_BLOCK, &mask, NULL);
981 }
983 /* garbage collection support */
985 extern void scanThread(Thread *thread);
987 void scanThreads() {
988 Thread *thread;
990 pthread_mutex_lock(&lock);
991 for(thread = &main_thread; thread != NULL; thread = thread->next)
992 scanThread(thread);
993 pthread_mutex_unlock(&lock);
994 }
996 int systemIdle(Thread *self) {
997 Thread *thread;
999 for(thread = &main_thread; thread != NULL; thread = thread->next)
1000 if(thread != self && thread->state < WAITING)
1001 return FALSE;
1003 return TRUE;
1004 }
1006 void exitVM(int status) {
1007 main_exited = TRUE;
1009 /* Execute System.exit() to run any registered shutdown hooks.
1010 In the unlikely event that System.exit() can't be found, or
1011 it returns, fall through and exit. */
1013 if(!VMInitialising()) {
1014 Class *system = findSystemClass(SYMBOL(java_lang_System));
1015 if(system) {
1016 MethodBlock *exit = findMethod(system, SYMBOL(exit), SYMBOL(_I__V));
1017 if(exit)
1018 executeStaticMethod(system, exit, status);
1019 }
1020 }
1022 jamvm_exit(status);
1023 }
1025 void mainThreadWaitToExitVM() {
1026 Thread *self = threadSelf();
1027 TRACE("Waiting for %d non-daemon threads to exit\n", non_daemon_thrds);
1029 disableSuspend(self);
1030 pthread_mutex_lock(&exit_lock);
1032 self->state = WAITING;
1033 while(non_daemon_thrds)
1034 pthread_cond_wait(&exit_cv, &exit_lock);
1036 pthread_mutex_unlock(&exit_lock);
1037 enableSuspend(self);
1038 }
1040 void mainThreadSetContextClassLoader(Object *loader) {
1041 FieldBlock *fb = findField(thread_class, SYMBOL(contextClassLoader),
1042 SYMBOL(sig_java_lang_ClassLoader));
1043 if(fb != NULL)
1044 INST_DATA(main_ee.thread)[fb->offset] = (uintptr_t)loader;
1045 }
1047 void initialiseThreadStage1(InitArgs *args) {
1048 size_t size;
1050 /* Set the default size of the Java stack for each _new_ thread */
1051 dflt_stack_size = args->java_stack;
1053 /* Initialise internal locks and pthread state */
1054 pthread_key_create(&threadKey, NULL);
1056 pthread_mutex_init(&lock, NULL);
1057 pthread_cond_init(&cv, NULL);
1059 pthread_mutex_init(&exit_lock, NULL);
1060 pthread_cond_init(&exit_cv, NULL);
1062 pthread_attr_init(&attributes);
1063 pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
1065 /* Ensure the thread stacks are at least 1 megabyte in size */
1066 pthread_attr_getstacksize(&attributes, &size);
1067 if(size < 1*MB)
1068 pthread_attr_setstacksize(&attributes, 1*MB);
1070 monitorInit(&sleep_mon);
1071 initHashTable(thread_id_map, HASHTABSZE, TRUE);
1073 /* We need to cache field and method offsets to create and initialise
1074 threads. However, the class loading component requires a valid
1075 thread and ExecEnv. To get round this we initialise the main thread
1076 in two parts. First part is sufficient to _load_ classes, but it
1077 is still not fully setup so we don't allow initialisers to run */
1079 main_thread.stack_base = args->main_stack_base;
1080 main_thread.tid = pthread_self();
1081 main_thread.id = genThreadID();
1082 main_thread.state = RUNNING;
1083 main_thread.ee = &main_ee;
1085 initialiseJavaStack(&main_ee);
1086 setThreadSelf(&main_thread);
1087 }
1089 /* VMDIFF: GNU Classpath needs a VMThread which connects to
1090 java.lang.Thread. OpenJDK needs two thread groups, "system"
1091 and "main", the latter being sent to the Thread constructor.
1092 GNU Classpath only has a "main" thread group, which is stored
1093 in a variable called "root" and created by the class
1094 initialiser. */
1095 void initialiseThreadStage2(InitArgs *args) {
1096 Object *java_thread;
1097 MethodBlock *run, *remove_thread;
1098 FieldBlock *group, *priority, *root, *threadId;
1099 FieldBlock *vmThread = NULL, *thread = NULL;
1100 FieldBlock *vmData, *daemon, *name;
1101 /* VMDIFF: OpenJDK needs to create two thread groups */
1102 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
1103 Class *thrdGrp_class;
1104 #elif WITH_JAVA_RUNTIME_LIBRARY_OPENJDK
1105 Object *main_group, *system_group;
1106 MethodBlock *tginit_mb, *tginit_mb2;
1107 #endif
1109 /* Load thread class and register reference for compaction threading */
1110 thread_class = findSystemClass0(SYMBOL(java_lang_Thread));
1111 registerStaticClassRef(&thread_class);
1113 if(thread_class != NULL) {
1114 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
1115 vmThread = findField(thread_class, SYMBOL(vmThread), SYMBOL(sig_java_lang_VMThread));
1116 threadId = findField(thread_class, SYMBOL(threadId), SYMBOL(J));
1117 init_mb = findMethod(thread_class, SYMBOL(object_init),
1118 SYMBOL(_java_lang_VMThread_java_lang_String_I_Z__V));
1119 #elif WITH_JAVA_RUNTIME_LIBRARY_OPENJDK
1120 init_mb = findMethod(thread_class, SYMBOL(object_init),
1121 SYMBOL(_java_lang_ThreadGroup_java_lang_String__V));
1122 #endif
1123 daemon = findField(thread_class, SYMBOL(daemon), SYMBOL(Z));
1124 name = findField(thread_class, SYMBOL(name), SYMBOL(sig_java_lang_String));
1125 group = findField(thread_class, SYMBOL(group), SYMBOL(sig_java_lang_ThreadGroup));
1126 priority = findField(thread_class, SYMBOL(priority), SYMBOL(I));
1127 run = findMethod(thread_class, SYMBOL(run), SYMBOL(___V));
1129 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
1130 vmthread_class = findSystemClass0(SYMBOL(java_lang_VMThread));
1131 CLASS_CB(vmthread_class)->flags |= VMTHREAD;
1133 /* Register class reference for compaction threading */
1134 registerStaticClassRef(&vmthread_class);
1135 #elif WITH_JAVA_RUNTIME_LIBRARY_OPENJDK
1136 thrdGrp_class = findSystemClass0(SYMBOL(java_lang_ThreadGroup));
1137 registerStaticClassRef(&thrdGrp_class);
1138 tginit_mb = findMethod(thrdGrp_class, SYMBOL(object_init),
1139 SYMBOL(___V));
1140 tginit_mb2 = findMethod(thrdGrp_class, SYMBOL(object_init),
1141 SYMBOL(_java_lang_ThreadGroup_java_lang_String__V));
1142 #endif
1145 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
1146 if(vmthread_class != NULL) {
1147 thread = findField(vmthread_class, SYMBOL(thread), SYMBOL(sig_java_lang_Thread));
1148 vmData = findField(vmthread_class, SYMBOL(vmData), SYMBOL(I));
1149 }
1150 #elif WITH_JAVA_RUNTIME_LIBRARY_OPENJDK
1151 if (thrdGrp_class != NULL) {
1152 system_group = allocObject(thrdGrp_class);
1153 executeMethod(system_group, tginit_mb);
1154 main_group = allocObject(thrdGrp_class);
1155 executeMethod(main_group, tginit_mb2, system_group,
1156 Cstr2String("main"));
1157 }
1158 #endif
1159 }
1161 /* findField and findMethod do not throw an exception... */
1162 if((init_mb == NULL) || (run == NULL) || (daemon == NULL) ||
1163 (name == NULL) || (group == NULL) || (priority == NULL))
1164 goto error;
1165 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
1166 if((vmData == NULL) || (vmThread == NULL) ||
1167 (thread == NULL) || (threadId == NULL))
1168 goto error;
1169 #elif WITH_JAVA_RUNTIME_LIBRARY_OPENJDK
1170 if((thrdGrp_class == NULL) || (tginit_mb == NULL) || (tginit_mb2 == NULL) ||
1171 (system_group == NULL) || (main_group == NULL))
1172 goto error;
1173 #endif
1175 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
1176 vmthread_offset = vmThread->offset;
1177 threadId_offset = threadId->offset;
1178 #endif
1179 thread_offset = thread->offset;
1180 vmData_offset = vmData->offset;
1181 daemon_offset = daemon->offset;
1182 group_offset = group->offset;
1183 priority_offset = priority->offset;
1184 name_offset = name->offset;
1185 run_mtbl_idx = run->method_table_index;
1187 /* Initialise the Java-level thread objects for the main thread */
1188 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
1189 java_thread = initJavaThread(&main_thread, FALSE, "main");
1190 #elif WITH_JAVA_RUNTIME_LIBRARY_OPENJDK
1191 java_thread = initJavaThread(&main_thread, FALSE, main_group, "main");
1192 #endif
1194 /* Main thread is now sufficiently setup to be able to run the thread group
1195 initialiser. This is essential to create the root thread group */
1196 #ifdef WITH_JAVA_RUNTIME_LIBRARY_CLASSPATH
1197 thrdGrp_class = findSystemClass(SYMBOL(java_lang_ThreadGroup));
1199 root = findField(thrdGrp_class, SYMBOL(root), SYMBOL(sig_java_lang_ThreadGroup));
1201 addThread_mb = findMethod(thrdGrp_class, SYMBOL(addThread),
1202 SYMBOL(_java_lang_Thread_args__void));
1204 remove_thread = findMethod(thrdGrp_class, SYMBOL(removeThread),
1205 SYMBOL(_java_lang_Thread_args__void));
1207 /* findField and findMethod do not throw an exception... */
1208 if((root == NULL) || (addThread_mb == NULL) || (remove_thread == NULL))
1209 goto error;
1211 /* Add the main thread to the root thread group */
1212 INST_DATA(java_thread)[group_offset] = root->static_value;
1213 executeMethod(((Object*)root->static_value), addThread_mb, java_thread);
1214 #elif WITH_JAVA_RUNTIME_LIBRARY_OPENJDK
1215 addThread_mb = findMethod(thrdGrp_class, SYMBOL(add),
1216 SYMBOL(_java_lang_Thread_args__void));
1217 remove_thread = findMethod(thrdGrp_class, SYMBOL(remove),
1218 SYMBOL(_java_lang_Thread_args__void));
1219 if((addThread_mb == NULL) || (remove_thread == NULL))
1220 goto error;
1221 executeMethod(main_group, addThread_mb, java_thread);
1222 #endif
1224 rmveThrd_mtbl_idx = remove_thread->method_table_index;
1226 /* Setup signal handling. This will be inherited by all
1227 threads created within Java */
1228 initialiseSignals();
1230 /* Create the signal handler thread. It is responsible for
1231 catching and handling SIGQUIT (thread dump) and SIGINT
1232 (user-termination of the VM, e.g. via Ctrl-C). Note it
1233 must be a valid Java-level thread as it needs to run the
1234 shutdown hooks in the event of user-termination */
1235 createVMThread("Signal Handler", dumpThreadsLoop);
1237 return;
1239 error:
1240 jam_fprintf(stderr, "Error initialising VM (initialiseMainThread)\nCheck "
1241 "the README for compatible versions of GNU Classpath\n");
1242 printException();
1243 exitVM(1);
1244 }
