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 #include <sys/types.h>
17 #include <sys/mman.h> /* for mprotect */
22 #include "sysdep/defines.h"
23 #include "sysdep/threads.h"
25 #include "../tables.h"
26 #include "../native.h"
27 #include "../loader.h"
28 #include "../builtin.h"
29 #include "../asmpart.h"
31 static classinfo *class_java_lang_ThreadDeath;
41 #if defined(USE_INTERNAL_THREADS)
43 thread* currentThread = NULL;
45 thread* threadQhead[MAX_THREAD_PRIO + 1];
46 thread* threadQtail[MAX_THREAD_PRIO + 1];
48 thread* liveThreads = 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 static thread* startDaemon(void* func, char* nm, int stackSize);
72 * Allocate the stack for a thread
75 allocThreadStack (thread *tid, int size)
77 int pageSize = getpagesize(),
79 unsigned long pageBegin;
81 CONTEXT(tid).stackMem = malloc(size + 2 * pageSize);
82 assert(CONTEXT(tid).stackMem != 0);
83 CONTEXT(tid).stackEnd = CONTEXT(tid).stackMem + size + 2 * pageSize;
85 pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
86 pageBegin = pageBegin - pageBegin % pageSize;
88 result = mprotect((void*)pageBegin, pageSize, PROT_NONE);
91 CONTEXT(tid).stackBase = (u1*)pageBegin + pageSize;
95 * Free the stack for a thread
98 freeThreadStack (thread *tid)
100 if (!(CONTEXT(tid).flags & THREAD_FLAGS_NOSTACKALLOC))
102 int pageSize = getpagesize(),
104 unsigned long pageBegin;
106 pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
107 pageBegin = pageBegin - pageBegin % pageSize;
109 result = mprotect((void*)pageBegin, pageSize,
110 PROT_READ | PROT_WRITE | PROT_EXEC);
113 free(CONTEXT(tid).stackMem);
115 CONTEXT(tid).stackMem = 0;
116 CONTEXT(tid).stackBase = 0;
117 CONTEXT(tid).stackEnd = 0;
121 * Initialize threads.
124 initThreads(u1 *stackbottom)
126 thread *the_main_thread;
131 for (i = 0; i < MAXTHREADS; ++i)
132 contexts[i].free = true;
134 /* Allocate a thread to be the main thread */
135 liveThreads = the_main_thread = (thread*)builtin_new(loader_load(unicode_new_char("java/lang/Thread")));
136 assert(the_main_thread != 0);
137 heap_addreference((void **) &liveThreads);
139 the_main_thread->PrivateInfo = 1;
140 CONTEXT(the_main_thread).free = false;
142 the_main_thread->name = javastring_new(unicode_new_char("main"));
143 the_main_thread->priority = NORM_THREAD_PRIO;
144 CONTEXT(the_main_thread).priority = (u1)the_main_thread->priority;
145 CONTEXT(the_main_thread).exceptionptr = 0;
146 the_main_thread->next = 0;
147 CONTEXT(the_main_thread).status = THREAD_SUSPENDED;
148 CONTEXT(the_main_thread).stackBase = CONTEXT(the_main_thread).stackEnd = stackbottom;
149 THREADINFO(&CONTEXT(the_main_thread));
151 DBG( printf("main thread %p base %p end %p\n",
153 CONTEXT(the_main_thread).stackBase,
154 CONTEXT(the_main_thread).stackEnd); );
156 CONTEXT(the_main_thread).flags = THREAD_FLAGS_NOSTACKALLOC;
157 CONTEXT(the_main_thread).nextlive = 0;
158 the_main_thread->single_step = 0;
159 the_main_thread->daemon = 0;
160 the_main_thread->stillborn = 0;
161 the_main_thread->target = 0;
162 the_main_thread->interruptRequested = 0;
163 the_main_thread->group =
164 (threadGroup*)builtin_new(loader_load(unicode_new_char("java/lang/ThreadGroup")));
165 /* we should call the constructor */
166 assert(the_main_thread->group != 0);
170 /* Load exception classes */
171 class_java_lang_ThreadDeath = loader_load(unicode_new_char("java/lang/ThreadDeath"));
173 DBG( fprintf(stderr, "finishing initThreads\n"); );
175 mainThread = currentThread = the_main_thread;
177 heap_addreference((void**)&mainThread);
179 /* Add thread into runQ */
180 iresumeThread(mainThread);
182 assert(blockInts == 0);
186 * Start a new thread running.
189 startThread (thread* tid)
193 /* Allocate a stack context */
194 for (i = 0; i < MAXTHREADS; ++i)
195 if (contexts[i].free)
199 panic("Too many threads");
201 tid->PrivateInfo = i + 1;
202 CONTEXT(tid).free = false;
203 CONTEXT(tid).nextlive = liveThreads;
205 allocThreadStack(tid, threadStackSize);
206 CONTEXT(tid).usedStackTop = CONTEXT(tid).stackBase;
207 CONTEXT(tid).flags = THREAD_FLAGS_GENERAL;
208 CONTEXT(tid).status = THREAD_SUSPENDED;
209 CONTEXT(tid).priority = (u1)tid->priority;
210 CONTEXT(tid).exceptionptr = 0;
212 /* Construct the initial restore point. */
213 THREADINIT((&CONTEXT(tid)), firstStartThread);
215 DBG( printf("new thread %p base %p end %p\n",
216 tid, CONTEXT(tid).stackBase,
217 CONTEXT(tid).stackEnd); );
223 /* Add thread into runQ */
228 * Start a daemon thread.
231 startDaemon(void* func, char* nm, int stackSize)
236 DBG( printf("startDaemon %s\n", nm); );
238 tid = (thread*)builtin_new(loader_load(unicode_new_char("java/lang/Thread")));
241 for (i = 0; i < MAXTHREADS; ++i)
242 if (contexts[i].free)
245 panic("Too many threads");
247 tid->PrivateInfo = i + 1;
248 CONTEXT(tid).free = false;
249 tid->name = 0; /* for the moment */
250 tid->priority = MAX_THREAD_PRIO;
251 CONTEXT(tid).priority = (u1)tid->priority;
253 CONTEXT(tid).status = THREAD_SUSPENDED;
255 allocThreadStack(tid, stackSize);
256 tid->single_step = 0;
260 tid->interruptRequested = 0;
263 /* Construct the initial restore point. */
264 THREADINIT((&CONTEXT(tid)), func);
273 * All threads start here.
276 firstStartThread(void)
280 DBG( printf("firstStartThread %p\n", currentThread); );
282 /* Every thread starts with the interrupts off */
284 assert(blockInts == 0);
286 /* Find the run()V method and call it */
287 method = class_findmethod(currentThread->header.vftbl->class,
288 unicode_new_char("run"), unicode_new_char("()V"));
290 panic("Cannot find method \'void run ()\'");
291 asm_calljavamethod(method, currentThread, NULL, NULL, NULL);
294 assert("Thread returned from killThread" == 0);
298 * Resume a thread running.
299 * This routine has to be called only from locations which ensure
300 * run / block queue consistency. There is no check for illegal resume
301 * conditions (like explicitly resuming an IO blocked thread). There also
302 * is no update of any blocking queue. Both has to be done by the caller
305 iresumeThread(thread* tid)
307 DBG( printf("resumeThread %p\n", tid); );
311 if (CONTEXT(tid).status != THREAD_RUNNING)
313 CONTEXT(tid).status = THREAD_RUNNING;
315 DBG( fprintf(stderr, "prio is %d\n", CONTEXT(tid).priority); );
317 /* Place thread on the end of its queue */
318 if (threadQhead[CONTEXT(tid).priority] == 0) {
319 threadQhead[CONTEXT(tid).priority] = tid;
320 threadQtail[CONTEXT(tid).priority] = tid;
321 if (CONTEXT(tid).priority
322 > CONTEXT(currentThread).priority)
323 needReschedule = true;
327 threadQtail[CONTEXT(tid).priority]->next = tid;
328 threadQtail[CONTEXT(tid).priority] = tid;
332 SDBG( else { printf("Re-resuming %p\n", tid); } );
338 * Yield process to another thread of equal priority.
345 if (threadQhead[CONTEXT(currentThread).priority]
346 != threadQtail[CONTEXT(currentThread).priority])
348 /* Get the next thread and move me to the end */
349 threadQhead[CONTEXT(currentThread).priority] = currentThread->next;
350 threadQtail[CONTEXT(currentThread).priority]->next = currentThread;
351 threadQtail[CONTEXT(currentThread).priority] = currentThread;
352 currentThread->next = 0;
353 needReschedule = true;
360 * Explicit request by user to resume a thread
361 * The definition says that it is just legal to call this after a preceeding
362 * suspend (which got through). If the thread was blocked for some other
363 * reason (either sleep or IO or a muxSem), we simply can't do it
364 * We use a new thread flag THREAD_FLAGS_USER_SUSPEND for this purpose
365 * (which is set by suspendThread(.))
368 resumeThread(thread* tid)
370 if ((CONTEXT(tid).flags & THREAD_FLAGS_USER_SUSPEND) != 0)
373 CONTEXT(tid).flags &= ~THREAD_FLAGS_USER_SUSPEND;
381 * This is an explicit user request to suspend the thread - the counterpart
382 * for resumeThreadRequest(.). It is JUST called by the java method
384 * What makes it distinct is the fact that the suspended thread is not contained
385 * in any block queue. Without a special flag (indicating the user suspend), we
386 * can't check s suspended thread for this condition afterwards (which is
387 * required by resumeThreadRequest()). The new thread flag
388 * THREAD_FLAGS_USER_SUSPEND is used for this purpose.
391 suspendThread(thread* tid)
397 if (CONTEXT(tid).status != THREAD_SUSPENDED)
399 CONTEXT(tid).status = THREAD_SUSPENDED;
402 * This is used to indicate the explicit suspend condition
403 * required by resumeThreadRequest()
405 CONTEXT(tid).flags |= THREAD_FLAGS_USER_SUSPEND;
407 for (ntid = &threadQhead[CONTEXT(tid).priority];
409 ntid = &(*ntid)->next)
415 if (tid == currentThread)
423 SDBG( else { printf("Re-suspending %p\n", tid); } );
429 * Suspend a thread on a queue.
432 suspendOnQThread(thread* tid, thread** queue)
436 DBG( printf("suspendOnQThread %p %p\n", tid, queue); );
438 assert(blockInts == 1);
440 if (CONTEXT(tid).status != THREAD_SUSPENDED)
442 CONTEXT(tid).status = THREAD_SUSPENDED;
444 for (ntid = &threadQhead[CONTEXT(tid).priority];
446 ntid = &(*ntid)->next)
451 /* Insert onto head of lock wait Q */
454 if (tid == currentThread)
456 DBG( fprintf(stderr, "suspending %p (cur=%p) with prio %d\n",
457 tid, currentThread, CONTEXT(tid).priority); );
464 SDBG( else { printf("Re-suspending %p on %p\n", tid, *queue); } );
471 killThread(thread* tid)
477 /* A null tid means the current thread */
483 DBG( printf("killThread %p\n", tid); );
485 if (CONTEXT(tid).status != THREAD_DEAD)
487 /* Get thread off runq (if it needs it) */
488 if (CONTEXT(tid).status == THREAD_RUNNING)
490 for (ntid = &threadQhead[CONTEXT(tid).priority];
492 ntid = &(*ntid)->next)
502 CONTEXT(tid).status = THREAD_DEAD;
508 /* If we only have daemons left, then everyone is dead. */
509 if (talive == tdaemon) {
510 /* atexit functions get called to clean things up */
514 /* Notify on the object just in case anyone is waiting */
515 internal_lock_mutex_for_object(&tid->header);
516 internal_broadcast_cond_for_object(&tid->header);
517 internal_unlock_mutex_for_object(&tid->header);
519 /* Remove thread from live list to it can be garbaged */
520 for (ntid = &liveThreads;
522 ntid = &(CONTEXT((*ntid)).nextlive))
526 (*ntid) = CONTEXT(tid).nextlive;
532 freeThreadStack(tid);
535 CONTEXT(tid).free = true;
537 /* Run something else */
538 needReschedule = true;
544 * Change thread priority.
547 setPriorityThread(thread* tid, int prio)
551 if (tid->PrivateInfo == 0) {
552 tid->priority = prio;
556 if (CONTEXT(tid).status == THREAD_SUSPENDED) {
557 CONTEXT(tid).priority = (u8)prio;
563 /* Remove from current thread list */
564 for (ntid = &threadQhead[CONTEXT(tid).priority]; *ntid != 0; ntid = &(*ntid)->next) {
571 /* Insert onto a new one */
572 tid->priority = prio;
573 CONTEXT(tid).priority = (u8)tid->priority;
574 if (threadQhead[prio] == 0) {
575 threadQhead[prio] = tid;
576 threadQtail[prio] = tid;
577 if (prio > CONTEXT(currentThread).priority) {
578 needReschedule = true;
582 threadQtail[prio]->next = tid;
583 threadQtail[prio] = tid;
591 * Is this thread alive?
594 aliveThread(thread* tid)
596 if (tid->PrivateInfo != 0 && CONTEXT(tid).status != THREAD_DEAD)
603 * Reschedule the thread.
604 * Called whenever a change in the running thread is required.
614 /* A reschedule in a non-blocked context is half way to hell */
615 assert(blockInts > 0);
618 /* Check events - we may release a high priority thread */
619 /* Just check IO, no need for a reschedule call by checkEvents() */
620 needReschedule = false;
625 for (i = MAX_THREAD_PRIO; i >= MIN_THREAD_PRIO; i--)
627 if (threadQhead[i] != 0)
629 DBG( fprintf(stderr, "found thread %p in head %d\n", threadQhead[i], i); );
631 if (threadQhead[i] != currentThread)
633 /* USEDSTACKTOP((CONTEXT(currentThread).usedStackTop)); */
635 lastThread = currentThread;
636 currentThread = threadQhead[i];
638 CONTEXT(currentThread).exceptionptr = exceptionptr;
640 THREADSWITCH((&CONTEXT(currentThread)),
641 (&CONTEXT(lastThread)));
644 exceptionptr = CONTEXT(currentThread).exceptionptr;
646 /* Alarm signal may be blocked - if so
650 if (alarmBlocked == true) {
651 alarmBlocked = false;
653 sigaddset(&nsig, SIGALRM);
654 sigprocmask(SIG_UNBLOCK, &nsig, 0);
658 /* I might be dying */
659 if ((CONTEXT(lastThread).flags & THREAD_FLAGS_KILLED)
662 CONTEXT(lastThread).flags &= ~THREAD_FLAGS_KILLED;
663 exceptionptr = native_new_and_init(class_java_lang_ThreadDeath);
666 /* Now we kill the schedule and turn ints
668 needReschedule = false;
672 /* Nothing to run - wait for external event */
673 DBG( fprintf(stderr, "nothing more to do\n"); );