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 ctx 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);
75 * Allocate the stack for a thread
78 allocThreadStack (thread *tid, int size)
80 int pageSize = getpagesize();
81 unsigned long pageBegin;
83 assert(stack_to_be_freed == 0);
85 CONTEXT(tid).stackMem = GCNEW(u1, size + 4 * pageSize);
86 assert(CONTEXT(tid).stackMem != 0);
87 CONTEXT(tid).stackEnd = CONTEXT(tid).stackMem + size + 2 * pageSize;
89 pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
90 pageBegin = pageBegin - pageBegin % pageSize;
92 CONTEXT(tid).stackBase = (u1*)pageBegin + pageSize;
96 * Mark the stack for a thread to be freed. We cannot free the stack
97 * immediately because it is still in use!
100 freeThreadStack (thread *tid)
102 if (!(CONTEXT(tid).flags & THREAD_FLAGS_NOSTACKALLOC))
104 int pageSize = getpagesize();
105 unsigned long pageBegin;
107 pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
108 pageBegin = pageBegin - pageBegin % pageSize;
110 assert(stack_to_be_freed == 0);
112 stack_to_be_freed = CONTEXT(tid).stackMem;
114 CONTEXT(tid).stackMem = 0;
115 CONTEXT(tid).stackBase = 0;
116 CONTEXT(tid).stackEnd = 0;
120 * Initialize threads.
123 initThreads(u1 *stackbottom)
125 thread *the_main_thread;
127 char mainname[] = "main";
128 /*int len = strlen(mainname);*/
130 signal(SIGPIPE, SIG_IGN);
134 for (i = 0; i < MAXTHREADS; ++i) {
135 contexts[i].free = true;
136 contexts[i].thread = NULL;
139 /* Allocate a thread to be the main thread */
140 liveThreads = the_main_thread =
141 (thread *) builtin_new(class_new(utf_new_char("java/lang/Thread")));
142 assert(the_main_thread != 0);
144 the_main_thread->PrivateInfo = 1;
145 CONTEXT(the_main_thread).free = false;
151 m = class_fetchmethod(
152 class_java_lang_String,
153 utf_new_char ("toCharArray"),
154 utf_new_char ("()[C")
156 printf("DEADCODE LIVES ?????????\n");fflush(stdout);
157 the_main_thread->name = asm_calljavafunction (m, javastring_new(utf_new_char("main")), 0, 0, 0);
160 the_main_thread->name=javastring_new(utf_new_char(mainname));
161 /* the_main_thread->name = builtin_newarray_char(len);
162 { u2 *d = the_main_thread->name->data;
163 for (i=0; i<len; i++)
166 the_main_thread->priority = NORM_THREAD_PRIO;
167 CONTEXT(the_main_thread).priority = (u1)the_main_thread->priority;
168 CONTEXT(the_main_thread).texceptionptr = 0;
169 the_main_thread->next = 0;
170 CONTEXT(the_main_thread).status = THREAD_SUSPENDED;
171 CONTEXT(the_main_thread).stackBase = CONTEXT(the_main_thread).stackEnd = stackbottom;
172 THREADINFO(&CONTEXT(the_main_thread));
174 DBG( printf("main thread %p base %p end %p\n",
176 CONTEXT(the_main_thread).stackBase,
177 CONTEXT(the_main_thread).stackEnd); );
179 CONTEXT(the_main_thread).flags = THREAD_FLAGS_NOSTACKALLOC;
180 CONTEXT(the_main_thread).nextlive = 0;
181 CONTEXT(the_main_thread).thread = the_main_thread;
182 /*the_main_thread->single_step = 0;*/
183 the_main_thread->daemon = 0;
184 /*the_main_thread->stillborn = 0;*/
185 /*the_main_thread->target = 0;*/
187 the_main_thread->contextClassLoader = 0;
188 /*the_main_thread->inheritedAccessControlContext = 0;*/
189 /*the_main_thread->values = 0;*/
191 /* Allocate and init ThreadGroup */
192 the_main_thread->group =
193 (threadGroup *) native_new_and_init(class_load(class_new(utf_new_char("java/lang/ThreadGroup"))));
194 assert(the_main_thread->group != 0);
198 /* Load exception classes */
199 /* loader_load_sysclass(&class_java_lang_ThreadDeath, */
200 /* utf_new_char("java/lang/ThreadDeath")); */
201 class_java_lang_ThreadDeath =
202 class_load(class_new(utf_new_char("java/lang/ThreadDeath")));
204 DBG( fprintf(stderr, "finishing initThreads\n"); );
206 mainThread = currentThread = the_main_thread;
208 /* Add thread into runQ */
209 iresumeThread(mainThread);
211 assert(blockInts == 0);
215 * Start a new thread running.
218 startThread (thread* tid)
222 /* Allocate a stack context */
223 for (i = 0; i < MAXTHREADS; ++i)
224 if (contexts[i].free)
228 panic("Too many threads");
230 assert(tid->priority >= MIN_THREAD_PRIO && tid->priority <= MAX_THREAD_PRIO);
232 tid->PrivateInfo = i + 1;
233 CONTEXT(tid).free = false;
234 CONTEXT(tid).thread = tid;
235 CONTEXT(tid).nextlive = liveThreads;
237 allocThreadStack(tid, threadStackSize);
238 CONTEXT(tid).usedStackTop = CONTEXT(tid).stackBase;
239 CONTEXT(tid).flags = THREAD_FLAGS_GENERAL;
240 CONTEXT(tid).status = THREAD_SUSPENDED;
241 CONTEXT(tid).priority = (u1)tid->priority;
242 CONTEXT(tid).texceptionptr = 0;
244 /* Construct the initial restore point. */
245 THREADINIT((&CONTEXT(tid)), firstStartThread);
247 DBG( printf("new thread %p base %p end %p\n",
248 tid, CONTEXT(tid).stackBase,
249 CONTEXT(tid).stackEnd); );
255 /* Add thread into runQ */
261 * Start a daemon thread.
263 static thread *startDaemon(void* func, char* nm, int stackSize)
268 DBG( printf("startDaemon %s\n", nm); );
270 tid = (thread *) builtin_new(class_new(utf_new_char("java/lang/Thread")));
273 for (i = 0; i < MAXTHREADS; ++i)
274 if (contexts[i].free)
277 panic("Too many threads");
279 tid->PrivateInfo = i + 1;
280 CONTEXT(tid).free = false;
281 tid->name = 0; /* for the moment */
282 tid->priority = MAX_THREAD_PRIO;
283 CONTEXT(tid).priority = (u1)tid->priority;
285 CONTEXT(tid).status = THREAD_SUSPENDED;
287 allocThreadStack(tid, stackSize);
288 /*tid->single_step = 0;*/
290 /*tid->stillborn = 0;*/
294 /* Construct the initial restore point. */
295 THREADINIT((&CONTEXT(tid)), func);
304 * All threads start here.
307 firstStartThread(void)
311 DBG( printf("firstStartThread %p\n", currentThread); );
313 if (stack_to_be_freed != 0) {
314 stack_to_be_freed = 0;
317 /* Every thread starts with the interrupts off */
319 assert(blockInts == 0);
321 /* Find the run()V method and call it */
322 method = class_findmethod(currentThread->header.vftbl->class,
323 utf_new_char("run"), utf_new_char("()V"));
325 panic("Cannot find method \'void run ()\'");
327 asm_calljavafunction(method, currentThread, NULL, NULL, NULL);
330 utf_display((*exceptionptr)->vftbl->class->name);
335 assert("Thread returned from killThread" == 0);
339 * Resume a thread running.
340 * This routine has to be called only from locations which ensure
341 * run / block queue consistency. There is no check for illegal resume
342 * conditions (like explicitly resuming an IO blocked thread). There also
343 * is no update of any blocking queue. Both has to be done by the caller
346 iresumeThread(thread* tid)
348 DBG( printf("resumeThread %p\n", tid); );
352 if (CONTEXT(tid).status != THREAD_RUNNING)
354 CONTEXT(tid).status = THREAD_RUNNING;
356 DBG( fprintf(stderr, "prio is %d\n", CONTEXT(tid).priority); );
358 /* Place thread on the end of its queue */
359 if (threadQhead[CONTEXT(tid).priority] == 0) {
360 threadQhead[CONTEXT(tid).priority] = tid;
361 threadQtail[CONTEXT(tid).priority] = tid;
362 if (CONTEXT(tid).priority
363 > CONTEXT(currentThread).priority)
364 needReschedule = true;
368 threadQtail[CONTEXT(tid).priority]->next = tid;
369 threadQtail[CONTEXT(tid).priority] = tid;
373 SDBG( else { printf("Re-resuming %p\n", tid); } );
379 * Yield process to another thread of equal priority.
386 if (threadQhead[CONTEXT(currentThread).priority]
387 != threadQtail[CONTEXT(currentThread).priority])
389 /* Get the next thread and move me to the end */
390 threadQhead[CONTEXT(currentThread).priority] = currentThread->next;
391 threadQtail[CONTEXT(currentThread).priority]->next = currentThread;
392 threadQtail[CONTEXT(currentThread).priority] = currentThread;
393 currentThread->next = 0;
394 needReschedule = true;
401 * Explicit request by user to resume a thread
402 * The definition says that it is just legal to call this after a preceeding
403 * suspend (which got through). If the thread was blocked for some other
404 * reason (either sleep or IO or a muxSem), we simply can't do it
405 * We use a new thread flag THREAD_FLAGS_USER_SUSPEND for this purpose
406 * (which is set by suspendThread(.))
409 resumeThread (thread* tid)
411 if ((CONTEXT(tid).flags & THREAD_FLAGS_USER_SUSPEND) != 0)
414 CONTEXT(tid).flags &= ~THREAD_FLAGS_USER_SUSPEND;
422 * This is an explicit user request to suspend the thread - the counterpart
423 * for resumeThreadRequest(.). It is JUST called by the java method
425 * What makes it distinct is the fact that the suspended thread is not contained
426 * in any block queue. Without a special flag (indicating the user suspend), we
427 * can't check s suspended thread for this condition afterwards (which is
428 * required by resumeThreadRequest()). The new thread flag
429 * THREAD_FLAGS_USER_SUSPEND is used for this purpose.
432 suspendThread(thread* tid)
438 if (CONTEXT(tid).status != THREAD_SUSPENDED)
440 CONTEXT(tid).status = THREAD_SUSPENDED;
443 * This is used to indicate the explicit suspend condition
444 * required by resumeThreadRequest()
446 CONTEXT(tid).flags |= THREAD_FLAGS_USER_SUSPEND;
448 for (ntid = &threadQhead[CONTEXT(tid).priority];
450 ntid = &(*ntid)->next)
456 if (tid == currentThread)
464 SDBG( else { printf("Re-suspending %p\n", tid); } );
470 * Suspend a thread on a queue.
473 suspendOnQThread(thread* tid, thread** queue)
477 DBG( printf("suspendOnQThread %p %p\n", tid, queue); );
479 assert(blockInts > 0);
481 if (CONTEXT(tid).status != THREAD_SUSPENDED)
483 CONTEXT(tid).status = THREAD_SUSPENDED;
485 for (ntid = &threadQhead[CONTEXT(tid).priority];
487 ntid = &(*ntid)->next)
492 /* Insert onto head of lock wait Q */
495 if (tid == currentThread)
497 DBG( fprintf(stderr, "suspending %p (cur=%p) with prio %d\n",
498 tid, currentThread, CONTEXT(tid).priority); );
505 SDBG( else { printf("Re-suspending %p on %p\n", tid, *queue); } );
512 killThread(thread* tid)
518 /* A null tid means the current thread */
524 DBG( printf("killThread %p\n", tid); );
526 if (CONTEXT(tid).status != THREAD_DEAD)
528 /* Get thread off runq (if it needs it) */
529 if (CONTEXT(tid).status == THREAD_RUNNING)
531 for (ntid = &threadQhead[CONTEXT(tid).priority];
533 ntid = &(*ntid)->next)
543 CONTEXT(tid).status = THREAD_DEAD;
549 /* If we only have daemons left, then everyone is dead. */
550 if (talive == tdaemon) {
551 /* atexit functions get called to clean things up */
556 /* Notify on the object just in case anyone is waiting */
557 internal_lock_mutex_for_object(&tid->header);
558 internal_broadcast_cond_for_object(&tid->header);
559 internal_unlock_mutex_for_object(&tid->header);
561 /* Remove thread from live list to it can be garbaged */
562 for (ntid = &liveThreads;
564 ntid = &(CONTEXT((*ntid)).nextlive))
568 (*ntid) = CONTEXT(tid).nextlive;
574 freeThreadStack(tid);
577 if (tid != mainThread) {
578 CONTEXT(tid).free = true;
579 CONTEXT(tid).thread = NULL;
582 /* Run something else */
583 needReschedule = true;
589 * Change thread priority.
592 setPriorityThread(thread* tid, int prio)
596 assert(prio >= MIN_THREAD_PRIO && prio <= MAX_THREAD_PRIO);
598 if (tid->PrivateInfo == 0) {
599 tid->priority = prio;
603 if (CONTEXT(tid).status == THREAD_SUSPENDED) {
604 CONTEXT(tid).priority = (u8)prio;
610 /* Remove from current thread list */
611 for (ntid = &threadQhead[CONTEXT(tid).priority]; *ntid != 0; ntid = &(*ntid)->next) {
618 /* Insert onto a new one */
619 tid->priority = prio;
620 CONTEXT(tid).priority = (u8)tid->priority;
621 if (threadQhead[prio] == 0) {
622 threadQhead[prio] = tid;
623 threadQtail[prio] = tid;
624 if (prio > CONTEXT(currentThread).priority) {
625 needReschedule = true;
629 threadQtail[prio]->next = tid;
630 threadQtail[prio] = tid;
638 * Get the current time in milliseconds since 1970-01-01.
646 gettimeofday(&tv, 0);
650 time += tv.tv_usec / 1000;
656 * Put a thread to sleep.
659 sleepThread (s8 time)
663 /* Sleep for no time */
670 /* Get absolute time */
671 CONTEXT(currentThread).time = time + currentTime();
673 /* Find place in alarm list */
674 for (tidp = &sleepThreads; (*tidp) != 0; tidp = &(*tidp)->next)
676 if (CONTEXT(*tidp).time > CONTEXT(currentThread).time)
680 /* Suspend thread on it */
681 suspendOnQThread(currentThread, tidp);
687 * Is this thread alive?
690 aliveThread(thread* tid)
692 if (tid->PrivateInfo != 0 && CONTEXT(tid).status != THREAD_DEAD)
699 * Reschedule the thread.
700 * Called whenever a change in the running thread is required.
710 /* A reschedule in a non-blocked context is half way to hell */
711 assert(blockInts > 0);
714 /* Check events - we may release a high priority thread */
715 /* Just check IO, no need for a reschedule call by checkEvents() */
716 needReschedule = false;
721 for (i = MAX_THREAD_PRIO; i >= MIN_THREAD_PRIO; i--)
723 if (threadQhead[i] != 0)
725 DBG( fprintf(stderr, "found thread %p in head %d\n", threadQhead[i], i); );
727 if (threadQhead[i] != currentThread)
729 /* USEDSTACKTOP((CONTEXT(currentThread).usedStackTop)); */
731 lastThread = currentThread;
732 currentThread = threadQhead[i];
734 CONTEXT(currentThread).texceptionptr = *exceptionptr;
736 DBG( fprintf(stderr, "thread switch from: %p to: %p\n", lastThread, currentThread); );
737 THREADSWITCH((&CONTEXT(currentThread)),
738 (&CONTEXT(lastThread)));
741 *exceptionptr = CONTEXT(currentThread).texceptionptr;
743 if (stack_to_be_freed != 0) {
744 stack_to_be_freed = 0;
747 /* Alarm signal may be blocked - if so
751 if (alarmBlocked == true) {
752 alarmBlocked = false;
754 sigaddset(&nsig, SIGALRM);
755 sigprocmask(SIG_UNBLOCK, &nsig, 0);
759 /* I might be dying */
760 if ((CONTEXT(lastThread).flags & THREAD_FLAGS_KILLED)
763 CONTEXT(lastThread).flags &= ~THREAD_FLAGS_KILLED;
764 *exceptionptr = native_new_and_init(class_java_lang_ThreadDeath);
767 /* Now we kill the schedule and turn ints
769 needReschedule = false;
773 /* Nothing to run - wait for external event */
774 DBG( fprintf(stderr, "nothing more to do\n"); );
779 void lock_stopworld(int dummy)
783 void unlock_stopworld()
787 void cacao_suspendhandler(void *ctx)