1 /* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */
6 * Copyright (c) 1996 T. J. Wilkinson & Associates, London, UK.
8 * See the file "license.terms" for information on usage and redistribution
9 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 * Written by Tim Wilkinson <tim@tjwassoc.demon.co.uk>, 1996.
16 #if !defined(NATIVE_THREADS)
21 #include <sys/types.h>
22 #include <sys/mman.h> /* for mprotect */
37 #include "toolbox/logging.h"
38 #include "toolbox/memory.h"
39 #include "toolbox/avl.h"
41 static classinfo *class_java_lang_ThreadDeath;
43 thread* currentThread = NULL;
45 thread* threadQhead[MAX_THREAD_PRIO + 1];
46 thread* threadQtail[MAX_THREAD_PRIO + 1];
48 thread* liveThreads = NULL;
49 thread* sleepThreads = NULL;
54 vmthread *contexts[MAXTHREADS];
56 /* Number of threads alive, also counting daemons */
59 /* Number of daemon threads alive */
62 static void firstStartThread(void);
64 void reschedule(void);
66 /* Setup default thread stack size - this can be overwritten if required */
67 int threadStackSize = THREADSTACKSIZE;
69 /* Pointer to the stack of the last killed thread. The free is delayed. */
70 void *stack_to_be_freed = 0;
72 static thread* startDaemon(void* func, char* nm, int stackSize);
76 java_objectheader *init_vmthread(void *thr)
80 classinfo *c=class_new(utf_new_char("java/lang/VMThread"));
85 o = builtin_new(c); /* create object */
90 /* find initializer */
92 m = class_findmethod(c,
93 utf_new_char("<init>"),
94 utf_new_char("(Ljava/lang/Thread;)V"));
96 if (!m) { /* initializer not found */
98 char logtext[MAXLOGTEXT];
99 sprintf(logtext, "Warning: class has no instance-initializer: ");
100 utf_sprint_classname(logtext + strlen(logtext), c->name);
106 /* call initializer */
108 asm_calljavafunction(m, o, thr, NULL, NULL);
116 * Allocate the stack for a thread
119 allocThreadStack (thread *tid, int size)
121 int pageSize = getpagesize();
122 unsigned long pageBegin;
124 assert(stack_to_be_freed == 0);
126 CONTEXT(tid).stackMem = GCNEW(u1, size + 4 * pageSize);
127 assert(CONTEXT(tid).stackMem != 0);
128 CONTEXT(tid).stackEnd = CONTEXT(tid).stackMem + size + 2 * pageSize;
130 pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
131 pageBegin = pageBegin - pageBegin % pageSize;
133 CONTEXT(tid).stackBase = (u1*)pageBegin + pageSize;
137 * Mark the stack for a thread to be freed. We cannot free the stack
138 * immediately because it is still in use!
141 freeThreadStack (vmthread *vmtid)
143 if (!(vmtid->flags & THREAD_FLAGS_NOSTACKALLOC))
145 int pageSize = getpagesize();
146 unsigned long pageBegin;
148 pageBegin = (unsigned long)(vmtid->stackMem) + pageSize - 1;
149 pageBegin = pageBegin - pageBegin % pageSize;
151 assert(stack_to_be_freed == 0);
153 stack_to_be_freed = vmtid->stackMem;
156 vmtid->stackBase = 0;
161 * Initialize threads.
164 initThreads(u1 *stackbottom)
166 thread *the_main_thread;
168 char mainname[] = "main";
169 /*int len = strlen(mainname);*/
171 signal(SIGPIPE, SIG_IGN);
175 for (i = 0; i < MAXTHREADS; ++i) {
179 /* Allocate a thread to be the main thread */
180 liveThreads = the_main_thread =
181 (thread *) builtin_new(class_new(utf_new_char("java/lang/Thread")));
182 the_main_thread->vmThread=init_vmthread(the_main_thread);
183 assert(the_main_thread != 0);
185 /* the_main_thread->PrivateInfo = 1;
186 CONTEXT(the_main_thread).free = false;*/
192 m = class_fetchmethod(
193 class_java_lang_String,
194 utf_new_char ("toCharArray"),
195 utf_new_char ("()[C")
197 printf("DEADCODE LIVES ?????????\n");fflush(stdout);
198 the_main_thread->name = asm_calljavafunction (m, javastring_new(utf_new_char("main")), 0, 0, 0);
201 the_main_thread->name=javastring_new(utf_new_char(mainname));
202 /* the_main_thread->name = builtin_newarray_char(len);
203 { u2 *d = the_main_thread->name->data;
204 for (i=0; i<len; i++)
208 the_main_thread->priority = NORM_THREAD_PRIO;
209 CONTEXT(the_main_thread).priority = (u1)the_main_thread->priority;
210 CONTEXT(the_main_thread).texceptionptr = 0;
211 the_main_thread->vmThread->next = 0;
212 CONTEXT(the_main_thread).status = THREAD_SUSPENDED;
213 CONTEXT(the_main_thread).stackBase = CONTEXT(the_main_thread).stackEnd = stackbottom;
214 THREADINFO(&CONTEXT(the_main_thread));
216 DBG( printf("main thread %p base %p end %p\n",
218 CONTEXT(the_main_thread).stackBase,
219 CONTEXT(the_main_thread).stackEnd); );
221 CONTEXT(the_main_thread).flags = THREAD_FLAGS_NOSTACKALLOC;
222 CONTEXT(the_main_thread).nextlive = 0;
223 /*CONTEXT(the_main_thread).thread = the_main_thread;*/
224 /*the_main_thread->single_step = 0;*/
225 the_main_thread->daemon = 0;
226 /*the_main_thread->stillborn = 0;*/
227 /*the_main_thread->target = 0;*/
229 the_main_thread->contextClassLoader = 0;
230 /*the_main_thread->inheritedAccessControlContext = 0;*/
231 /*the_main_thread->values = 0;*/
233 /* Allocate and init ThreadGroup */
234 the_main_thread->group =
235 (threadGroup *) native_new_and_init(class_load(class_new(utf_new_char("java/lang/ThreadGroup"))));
236 assert(the_main_thread->group != 0);
240 /* Load exception classes */
241 /* loader_load_sysclass(&class_java_lang_ThreadDeath, */
242 /* utf_new_char("java/lang/ThreadDeath")); */
243 class_java_lang_ThreadDeath =
244 class_load(class_new(utf_new_char("java/lang/ThreadDeath")));
246 DBG( fprintf(stderr, "finishing initThreads\n"); );
248 mainThread = currentThread = the_main_thread;
249 contexts[0]=mainThread->vmThread;
250 /* Add thread into runQ */
251 iresumeThread(mainThread);
253 assert(blockInts == 0);
257 * Start a new thread running.
260 startThread (thread* tid)
264 /* Allocate a stack context */
265 for (i = 0; i < MAXTHREADS; ++i)
270 panic("Too many threads");
272 assert(tid->priority >= MIN_THREAD_PRIO && tid->priority <= MAX_THREAD_PRIO);
273 contexts[i]=tid->vmThread;
274 /* tid->PrivateInfo = i + 1;
275 CONTEXT(tid).free = false;*/
276 if (tid->vmThread==0) {
277 panic("vmThread field not set");
278 /* tid->vmThread=init_vmthread(tid);*/
281 /* CONTEXT(tid).thread = tid;*/
282 CONTEXT(tid).nextlive = liveThreads;
284 allocThreadStack(tid, threadStackSize);
285 CONTEXT(tid).usedStackTop = CONTEXT(tid).stackBase;
286 CONTEXT(tid).flags = THREAD_FLAGS_GENERAL;
287 CONTEXT(tid).status = THREAD_SUSPENDED;
288 CONTEXT(tid).priority = (u1)tid->priority;
289 CONTEXT(tid).texceptionptr = 0;
291 /* Construct the initial restore point. */
292 THREADINIT((&CONTEXT(tid)), firstStartThread);
294 DBG( printf("new thread %p base %p end %p\n",
295 tid, CONTEXT(tid).stackBase,
296 CONTEXT(tid).stackEnd); );
302 /* Add thread into runQ */
308 * Start a daemon thread.
310 static thread *startDaemon(void* func, char* nm, int stackSize)
315 DBG( printf("startDaemon %s\n", nm); );
317 tid = (thread *) builtin_new(class_new(utf_new_char("java/lang/Thread")));
320 /* for (i = 0; i < MAXTHREADS; ++i)
324 panic("Too many threads");*/
326 /* tid->PrivateInfo = i + 1;
327 CONTEXT(tid).free = false;*/
328 tid->name = 0; /* for the moment */
329 tid->priority = MAX_THREAD_PRIO;
330 CONTEXT(tid).priority = (u1)tid->priority;
331 tid->vmThread->next = 0;
332 CONTEXT(tid).status = THREAD_SUSPENDED;
334 allocThreadStack(tid, stackSize);
335 /*tid->single_step = 0;*/
337 /*tid->stillborn = 0;*/
341 /* Construct the initial restore point. */
342 THREADINIT((&CONTEXT(tid)), func);
351 * All threads start here.
354 firstStartThread(void)
358 DBG( printf("firstStartThread %p\n", currentThread); );
360 if (stack_to_be_freed != 0) {
361 stack_to_be_freed = 0;
364 /* Every thread starts with the interrupts off */
366 assert(blockInts == 0);
368 /* Find the run()V method and call it */
369 method = class_findmethod(currentThread->vmThread->header.vftbl->class,
370 utf_new_char("run"), utf_new_char("()V"));
372 panic("Cannot find method \'void run ()\'");
374 asm_calljavafunction(method, currentThread->vmThread, NULL, NULL, NULL);
377 utf_display((*exceptionptr)->vftbl->class->name);
382 assert("Thread returned from killThread" == 0);
386 * Resume a thread running.
387 * This routine has to be called only from locations which ensure
388 * run / block queue consistency. There is no check for illegal resume
389 * conditions (like explicitly resuming an IO blocked thread). There also
390 * is no update of any blocking queue. Both has to be done by the caller
393 iresumeThread(thread* tid)
396 DBG( printf("resumeThread %p\n", tid); );
399 if (tid->vmThread==0) {
404 if (currentThread->vmThread==0) {
406 for (i1=0;i1<MAXTHREADS;i1++) {
407 if (!contexts[i1]) continue;
408 if (contexts[i1]->thread==currentThread) {
413 if (i1==MAXTHREADS) vmctid=0; /*panic("Thread not found in iresumeThread");*/
416 vmctid=currentThread->vmThread;
419 if (CONTEXT(tid).status != THREAD_RUNNING)
421 CONTEXT(tid).status = THREAD_RUNNING;
423 DBG( fprintf(stderr, "prio is %d\n", CONTEXT(tid).priority); );
425 /* Place thread on the end of its queue */
426 if (threadQhead[CONTEXT(tid).priority] == 0) {
427 threadQhead[CONTEXT(tid).priority] = tid;
428 threadQtail[CONTEXT(tid).priority] = tid;
430 if ((vmctid==0) || (CONTEXT(tid).priority
431 > vmctid->priority) )
432 needReschedule = true;
436 threadQtail[CONTEXT(tid).priority]->vmThread->next = tid;
437 threadQtail[CONTEXT(tid).priority] = tid;
439 tid->vmThread->next = 0;
441 SDBG( else { printf("Re-resuming %p\n", tid); } );
447 * Yield process to another thread of equal priority.
454 if (threadQhead[CONTEXT(currentThread).priority]
455 != threadQtail[CONTEXT(currentThread).priority])
457 /* Get the next thread and move me to the end */
458 threadQhead[CONTEXT(currentThread).priority] = currentThread->vmThread->next;
459 threadQtail[CONTEXT(currentThread).priority]->vmThread->next = currentThread;
460 threadQtail[CONTEXT(currentThread).priority] = currentThread;
461 currentThread->vmThread->next = 0;
462 needReschedule = true;
469 * Explicit request by user to resume a thread
470 * The definition says that it is just legal to call this after a preceeding
471 * suspend (which got through). If the thread was blocked for some other
472 * reason (either sleep or IO or a muxSem), we simply can't do it
473 * We use a new thread flag THREAD_FLAGS_USER_SUSPEND for this purpose
474 * (which is set by suspendThread(.))
477 resumeThread (thread* tid)
479 if ((CONTEXT(tid).flags & THREAD_FLAGS_USER_SUSPEND) != 0)
482 CONTEXT(tid).flags &= ~THREAD_FLAGS_USER_SUSPEND;
490 * This is an explicit user request to suspend the thread - the counterpart
491 * for resumeThreadRequest(.). It is JUST called by the java method
493 * What makes it distinct is the fact that the suspended thread is not contained
494 * in any block queue. Without a special flag (indicating the user suspend), we
495 * can't check s suspended thread for this condition afterwards (which is
496 * required by resumeThreadRequest()). The new thread flag
497 * THREAD_FLAGS_USER_SUSPEND is used for this purpose.
500 suspendThread(thread* tid)
506 if (CONTEXT(tid).status != THREAD_SUSPENDED)
508 CONTEXT(tid).status = THREAD_SUSPENDED;
511 * This is used to indicate the explicit suspend condition
512 * required by resumeThreadRequest()
514 CONTEXT(tid).flags |= THREAD_FLAGS_USER_SUSPEND;
516 for (ntid = &threadQhead[CONTEXT(tid).priority];
518 ntid = &(*ntid)->vmThread->next)
522 *ntid = tid->vmThread->next;
523 tid->vmThread->next = 0;
524 if (tid == currentThread)
532 SDBG( else { printf("Re-suspending %p\n", tid); } );
538 * Suspend a thread on a queue.
541 suspendOnQThread(thread* tid, thread** queue)
545 DBG( printf("suspendOnQThread %p %p\n", tid, queue); );
547 assert(blockInts > 0);
549 if (CONTEXT(tid).status != THREAD_SUSPENDED)
551 CONTEXT(tid).status = THREAD_SUSPENDED;
553 for (ntid = &threadQhead[CONTEXT(tid).priority];
555 ntid = &(*ntid)->vmThread->next)
559 *ntid = tid->vmThread->next;
560 /* Insert onto head of lock wait Q */
561 tid->vmThread->next = *queue;
563 if (tid == currentThread)
565 DBG( fprintf(stderr, "suspending %p (cur=%p) with prio %d\n",
566 tid, currentThread, CONTEXT(tid).priority); );
573 SDBG( else { printf("Re-suspending %p on %p\n", tid, *queue); } );
580 killThread(thread* tid)
587 /* A null tid means the current thread */
593 if (tid->vmThread==0) {
595 for (i1=0;i1<MAXTHREADS;i1++) {
596 if (!contexts[i1]) continue;
597 if (contexts[i1]->thread==tid) {
598 context=contexts[i1];
602 if (i1==MAXTHREADS) panic("Thread not found in killThread");
604 } else context=tid->vmThread;
606 DBG( printf("killThread %p\n", tid); );
608 if (context->status != THREAD_DEAD)
610 /* Get thread off runq (if it needs it) */
611 if (context->status == THREAD_RUNNING)
613 for (ntid = &threadQhead[context->priority];
615 ntid = &(*ntid)->vmThread->next)
619 *ntid = context->next;
625 context->status = THREAD_DEAD;
631 /* If we only have daemons left, then everyone is dead. */
632 if (talive == tdaemon) {
633 /* atexit functions get called to clean things up */
638 /* Notify on the object just in case anyone is waiting */
639 internal_lock_mutex_for_object(&tid->header);
640 internal_broadcast_cond_for_object(&tid->header);
641 internal_unlock_mutex_for_object(&tid->header);
643 /* Remove thread from live list to it can be garbaged */
644 for (ntid = &liveThreads;
646 ntid = &(CONTEXT((*ntid)).nextlive))
650 (*ntid) = context->nextlive;
657 freeThreadStack(context);
660 if (tid != mainThread)
663 for (i=0;i<MAXTHREADS;i++) {
664 if (!contexts[i]) continue;
665 if (contexts[i]==context) {
671 /* if (tid != mainThread) {
672 CONTEXT(tid).free = true;
673 CONTEXT(tid).thread = NULL;
676 /* Run something else */
677 needReschedule = true;
679 for (ntid = &sleepThreads;
681 ntid = &(CONTEXT((*ntid)).next))
685 (*ntid) = context->next;
694 * Change thread priority.
697 setPriorityThread(thread* tid, int prio)
701 assert(prio >= MIN_THREAD_PRIO && prio <= MAX_THREAD_PRIO);
704 /* if (tid->PrivateInfo == 0) {
705 tid->priority = prio;
709 if (CONTEXT(tid).status == THREAD_SUSPENDED) {
710 CONTEXT(tid).priority = (u8)prio;
716 /* Remove from current thread list */
717 for (ntid = &threadQhead[CONTEXT(tid).priority]; *ntid != 0; ntid = &(*ntid)->vmThread->next) {
719 *ntid = tid->vmThread->next;
724 /* Insert onto a new one */
725 tid->priority = prio;
726 CONTEXT(tid).priority = (u8)tid->priority;
727 if (threadQhead[prio] == 0) {
728 threadQhead[prio] = tid;
729 threadQtail[prio] = tid;
730 if (prio > CONTEXT(currentThread).priority) {
731 needReschedule = true;
735 threadQtail[prio]->vmThread->next = tid;
736 threadQtail[prio] = tid;
738 tid->vmThread->next = 0;
744 * Get the current time in milliseconds since 1970-01-01.
752 gettimeofday(&tv, 0);
756 time += tv.tv_usec / 1000;
762 * Put a thread to sleep.
765 sleepThread (s8 time)
769 /* Sleep for no time */
776 /* Get absolute time */
777 CONTEXT(currentThread).time = time + currentTime();
779 /* Find place in alarm list */
780 for (tidp = &sleepThreads; (*tidp) != 0; tidp = &((*tidp)->vmThread->next))
782 if (CONTEXT((*tidp)).time > CONTEXT(currentThread).time)
786 /* Suspend thread on it */
787 suspendOnQThread(currentThread, tidp);
793 * Is this thread alive?
796 aliveThread(thread* tid)
798 if (tid!=mainThread && CONTEXT(tid).status != THREAD_DEAD)
805 * Reschedule the thread.
806 * Called whenever a change in the running thread is required.
816 /* A reschedule in a non-blocked context is half way to hell */
817 assert(blockInts > 0);
820 /* Check events - we may release a high priority thread */
821 /* Just check IO, no need for a reschedule call by checkEvents() */
822 needReschedule = false;
827 for (i = MAX_THREAD_PRIO; i >= MIN_THREAD_PRIO; i--)
829 if (threadQhead[i] != 0)
831 DBG( fprintf(stderr, "found thread %p in head %d\n", threadQhead[i], i); );
833 if (threadQhead[i] != currentThread)
835 /* USEDSTACKTOP((CONTEXT(currentThread).usedStackTop)); */
837 lastThread = currentThread;
838 currentThread = threadQhead[i];
840 CONTEXT(currentThread).texceptionptr = *exceptionptr;
842 DBG( fprintf(stderr, "thread switch from: %p to: %p\n", lastThread, currentThread); );
844 THREADSWITCH((&CONTEXT(currentThread)),
845 (&CONTEXT(lastThread)));
849 *exceptionptr = CONTEXT(currentThread).texceptionptr;
851 if (stack_to_be_freed != 0) {
852 stack_to_be_freed = 0;
855 /* Alarm signal may be blocked - if so
859 if (alarmBlocked == true) {
860 alarmBlocked = false;
862 sigaddset(&nsig, SIGALRM);
863 sigprocmask(SIG_UNBLOCK, &nsig, 0);
867 /* I might be dying */
868 if ((CONTEXT(lastThread).flags & THREAD_FLAGS_KILLED)
871 CONTEXT(lastThread).flags &= ~THREAD_FLAGS_KILLED;
872 *exceptionptr = native_new_and_init(class_java_lang_ThreadDeath);
875 /* Now we kill the schedule and turn ints
877 needReschedule = false;
881 /* Nothing to run - wait for external event */
882 DBG( fprintf(stderr, "nothing more to do\n"); );
887 void lock_stopworld(int dummy)
891 void unlock_stopworld()
895 void cacao_suspendhandler(void *ctx)