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;
45 thread* threadQhead[MAX_THREAD_PRIO + 1];
46 thread* threadQtail[MAX_THREAD_PRIO + 1];
51 thread* gcDaemonThread;
56 ctx contexts[MAXTHREADS];
58 /* Number of threads alive, also counting daemons */
61 /* Number of daemon threads alive */
64 static void firstStartThread(void);
66 void reschedule(void);
68 /* Setup default thread stack size - this can be overwritten if required */
69 int threadStackSize = THREADSTACKSIZE;
71 static thread* startDaemon(void* func, char* nm, int stackSize);
74 * Allocate the stack for a thread
77 allocThreadStack (thread *tid, int size)
79 int pageSize = getpagesize(),
81 unsigned long pageBegin;
83 CONTEXT(tid).stackMem = malloc(size + 2 * pageSize);
84 assert(CONTEXT(tid).stackMem != 0);
85 CONTEXT(tid).stackEnd = CONTEXT(tid).stackMem + size + 2 * pageSize;
87 pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
88 pageBegin = pageBegin - pageBegin % pageSize;
90 result = mprotect((void*)pageBegin, pageSize, PROT_NONE);
93 CONTEXT(tid).stackBase = (u1*)pageBegin + pageSize;
97 * Free the stack for a thread
100 freeThreadStack (thread *tid)
102 if (!(CONTEXT(tid).flags & THREAD_FLAGS_NOSTACKALLOC))
104 int pageSize = getpagesize(),
106 unsigned long pageBegin;
108 pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
109 pageBegin = pageBegin - pageBegin % pageSize;
111 result = mprotect((void*)pageBegin, pageSize,
112 PROT_READ | PROT_WRITE | PROT_EXEC);
115 free(CONTEXT(tid).stackMem);
117 CONTEXT(tid).stackMem = 0;
118 CONTEXT(tid).stackBase = 0;
119 CONTEXT(tid).stackEnd = 0;
123 * Initialize threads.
126 initThreads(u1 *stackbottom)
132 for (i = 0; i < MAXTHREADS; ++i)
133 contexts[i].free = true;
135 /* Allocate a thread to be the main thread */
136 mainThread = currentThread = (thread*)builtin_new(loader_load(unicode_new_char("java/lang/Thread")));
137 assert(currentThread != 0);
139 currentThread->PrivateInfo = 1;
140 CONTEXT(currentThread).free = false;
142 liveThreads = currentThread;
144 currentThread->name = javastring_new(unicode_new_char("main"));
145 currentThread->priority = NORM_THREAD_PRIO;
146 CONTEXT(currentThread).priority = (u1)currentThread->priority;
147 CONTEXT(currentThread).exceptionptr = 0;
148 currentThread->next = 0;
149 CONTEXT(currentThread).status = THREAD_SUSPENDED;
150 CONTEXT(currentThread).stackBase = CONTEXT(currentThread).stackEnd = stackbottom;
151 THREADINFO(&CONTEXT(currentThread));
153 DBG( printf("main thread %p base %p end %p\n",
155 CONTEXT(currentThread).stackBase,
156 CONTEXT(currentThread).stackEnd); );
158 CONTEXT(currentThread).flags = THREAD_FLAGS_NOSTACKALLOC;
159 CONTEXT(currentThread).nextlive = 0;
160 currentThread->single_step = 0;
161 currentThread->daemon = 0;
162 currentThread->stillborn = 0;
163 currentThread->target = 0;
164 currentThread->interruptRequested = 0;
165 currentThread->group =
166 (threadGroup*)builtin_new(loader_load(unicode_new_char("java/lang/ThreadGroup")));
167 /* we should call the constructor */
168 assert(currentThread->group != 0);
172 /* Add thread into runQ */
173 iresumeThread(currentThread);
175 /* Start garbage collection thread */
176 gcDaemonThread = startDaemon(gc_thread, "gc", 16384);
177 iresumeThread(gcDaemonThread);
179 heap_addreference((void**)&gcDaemonThread);
181 /* Load exception classes */
182 class_java_lang_ThreadDeath = loader_load(unicode_new_char("java/lang/ThreadDeath"));
184 DBG( fprintf(stderr, "finishing initThreads\n"); );
186 assert(blockInts == 0);
190 * Start a new thread running.
193 startThread (thread* tid)
197 /* Allocate a stack context */
198 for (i = 0; i < MAXTHREADS; ++i)
199 if (contexts[i].free)
203 panic("Too many threads");
205 tid->PrivateInfo = i + 1;
206 CONTEXT(tid).free = false;
207 CONTEXT(tid).nextlive = liveThreads;
209 allocThreadStack(tid, threadStackSize);
210 CONTEXT(tid).usedStackTop = CONTEXT(tid).stackBase;
211 CONTEXT(tid).flags = THREAD_FLAGS_GENERAL;
212 CONTEXT(tid).status = THREAD_SUSPENDED;
213 CONTEXT(tid).priority = (u1)tid->priority;
214 CONTEXT(tid).exceptionptr = 0;
216 /* Construct the initial restore point. */
217 THREADINIT((&CONTEXT(tid)), firstStartThread);
219 DBG( printf("new thread %p base %p end %p\n",
220 tid, CONTEXT(tid).stackBase,
221 CONTEXT(tid).stackEnd); );
227 /* Add thread into runQ */
232 * Start a daemon thread.
235 startDaemon(void* func, char* nm, int stackSize)
240 DBG( printf("startDaemon %s\n", nm); );
242 tid = (thread*)builtin_new(loader_load(unicode_new_char("java/lang/Thread")));
245 for (i = 0; i < MAXTHREADS; ++i)
246 if (contexts[i].free)
249 panic("Too many threads");
251 tid->PrivateInfo = i + 1;
252 CONTEXT(tid).free = false;
253 tid->name = 0; /* for the moment */
254 tid->priority = MAX_THREAD_PRIO;
255 CONTEXT(tid).priority = (u1)tid->priority;
257 CONTEXT(tid).status = THREAD_SUSPENDED;
259 allocThreadStack(tid, stackSize);
260 tid->single_step = 0;
264 tid->interruptRequested = 0;
267 /* Construct the initial restore point. */
268 THREADINIT((&CONTEXT(tid)), func);
277 * All threads start here.
280 firstStartThread(void)
284 DBG( printf("firstStartThread %p\n", currentThread); );
286 /* Every thread starts with the interrupts off */
288 assert(blockInts == 0);
290 /* Find the run()V method and call it */
291 method = class_findmethod(currentThread->header.vftbl->class,
292 unicode_new_char("run"), unicode_new_char("()V"));
294 panic("Cannot find method \'void run ()\'");
295 asm_calljavamethod(method, currentThread, NULL, NULL, NULL);
298 assert("Thread returned from killThread" == 0);
302 * Resume a thread running.
303 * This routine has to be called only from locations which ensure
304 * run / block queue consistency. There is no check for illegal resume
305 * conditions (like explicitly resuming an IO blocked thread). There also
306 * is no update of any blocking queue. Both has to be done by the caller
309 iresumeThread(thread* tid)
311 DBG( printf("resumeThread %p\n", tid); );
315 if (CONTEXT(tid).status != THREAD_RUNNING)
317 CONTEXT(tid).status = THREAD_RUNNING;
319 DBG( fprintf(stderr, "prio is %d\n", CONTEXT(tid).priority); );
321 /* Place thread on the end of its queue */
322 if (threadQhead[CONTEXT(tid).priority] == 0) {
323 threadQhead[CONTEXT(tid).priority] = tid;
324 threadQtail[CONTEXT(tid).priority] = tid;
325 if (CONTEXT(tid).priority
326 > CONTEXT(currentThread).priority)
327 needReschedule = true;
331 threadQtail[CONTEXT(tid).priority]->next = tid;
332 threadQtail[CONTEXT(tid).priority] = tid;
336 SDBG( else { printf("Re-resuming %p\n", tid); } );
342 * Yield process to another thread of equal priority.
349 if (threadQhead[CONTEXT(currentThread).priority]
350 != threadQtail[CONTEXT(currentThread).priority])
352 /* Get the next thread and move me to the end */
353 threadQhead[CONTEXT(currentThread).priority] = currentThread->next;
354 threadQtail[CONTEXT(currentThread).priority]->next = currentThread;
355 threadQtail[CONTEXT(currentThread).priority] = currentThread;
356 currentThread->next = 0;
357 needReschedule = true;
364 * Explicit request by user to resume a thread
365 * The definition says that it is just legal to call this after a preceeding
366 * suspend (which got through). If the thread was blocked for some other
367 * reason (either sleep or IO or a muxSem), we simply can't do it
368 * We use a new thread flag THREAD_FLAGS_USER_SUSPEND for this purpose
369 * (which is set by suspendThread(.))
372 resumeThread(thread* tid)
374 if ((CONTEXT(tid).flags & THREAD_FLAGS_USER_SUSPEND) != 0)
377 CONTEXT(tid).flags &= ~THREAD_FLAGS_USER_SUSPEND;
385 * This is an explicit user request to suspend the thread - the counterpart
386 * for resumeThreadRequest(.). It is JUST called by the java method
388 * What makes it distinct is the fact that the suspended thread is not contained
389 * in any block queue. Without a special flag (indicating the user suspend), we
390 * can't check s suspended thread for this condition afterwards (which is
391 * required by resumeThreadRequest()). The new thread flag
392 * THREAD_FLAGS_USER_SUSPEND is used for this purpose.
395 suspendThread(thread* tid)
401 if (CONTEXT(tid).status != THREAD_SUSPENDED)
403 CONTEXT(tid).status = THREAD_SUSPENDED;
406 * This is used to indicate the explicit suspend condition
407 * required by resumeThreadRequest()
409 CONTEXT(tid).flags |= THREAD_FLAGS_USER_SUSPEND;
411 for (ntid = &threadQhead[CONTEXT(tid).priority];
413 ntid = &(*ntid)->next)
419 if (tid == currentThread)
427 SDBG( else { printf("Re-suspending %p\n", tid); } );
433 * Suspend a thread on a queue.
436 suspendOnQThread(thread* tid, thread** queue)
440 DBG( printf("suspendOnQThread %p %p\n", tid, queue); );
442 assert(blockInts == 1);
444 if (CONTEXT(tid).status != THREAD_SUSPENDED)
446 CONTEXT(tid).status = THREAD_SUSPENDED;
448 for (ntid = &threadQhead[CONTEXT(tid).priority];
450 ntid = &(*ntid)->next)
455 /* Insert onto head of lock wait Q */
458 if (tid == currentThread)
460 DBG( fprintf(stderr, "suspending %p (cur=%p) with prio %d\n",
461 tid, currentThread, CONTEXT(tid).priority); );
468 SDBG( else { printf("Re-suspending %p on %p\n", tid, *queue); } );
475 killThread(thread* tid)
481 /* A null tid means the current thread */
487 DBG( printf("killThread %p\n", tid); );
489 if (CONTEXT(tid).status != THREAD_DEAD)
491 /* Get thread off runq (if it needs it) */
492 if (CONTEXT(tid).status == THREAD_RUNNING)
494 for (ntid = &threadQhead[CONTEXT(tid).priority];
496 ntid = &(*ntid)->next)
506 CONTEXT(tid).status = THREAD_DEAD;
512 /* If we only have daemons left, then everyone is dead. */
513 if (talive == tdaemon) {
514 /* Am I suppose to close things down nicely ?? */
518 /* Notify on the object just in case anyone is waiting */
519 internal_lock_mutex_for_object(&tid->header);
520 internal_broadcast_cond_for_object(&tid->header);
521 internal_unlock_mutex_for_object(&tid->header);
523 /* Remove thread from live list to it can be garbaged */
524 for (ntid = &liveThreads;
526 ntid = &(CONTEXT((*ntid)).nextlive))
530 (*ntid) = CONTEXT(tid).nextlive;
536 freeThreadStack(tid);
539 CONTEXT(tid).free = true;
541 /* Run something else */
542 needReschedule = true;
548 * Change thread priority.
551 setPriorityThread(thread* tid, int prio)
555 if (tid->PrivateInfo == 0) {
556 tid->priority = prio;
560 if (CONTEXT(tid).status == THREAD_SUSPENDED) {
561 CONTEXT(tid).priority = (u8)prio;
567 /* Remove from current thread list */
568 for (ntid = &threadQhead[CONTEXT(tid).priority]; *ntid != 0; ntid = &(*ntid)->next) {
575 /* Insert onto a new one */
576 tid->priority = prio;
577 CONTEXT(tid).priority = (u8)tid->priority;
578 if (threadQhead[prio] == 0) {
579 threadQhead[prio] = tid;
580 threadQtail[prio] = tid;
581 if (prio > CONTEXT(currentThread).priority) {
582 needReschedule = true;
586 threadQtail[prio]->next = tid;
587 threadQtail[prio] = tid;
595 * Is this thread alive?
598 aliveThread(thread* tid)
600 if (tid->PrivateInfo != 0 && CONTEXT(tid).status != THREAD_DEAD)
607 * Reschedule the thread.
608 * Called whenever a change in the running thread is required.
618 /* A reschedule in a non-blocked context is half way to hell */
619 assert(blockInts > 0);
622 /* Check events - we may release a high priority thread */
623 /* Just check IO, no need for a reschedule call by checkEvents() */
624 needReschedule = false;
629 for (i = MAX_THREAD_PRIO; i >= MIN_THREAD_PRIO; i--)
631 if (threadQhead[i] != 0)
633 DBG( fprintf(stderr, "found thread %p in head %d\n", threadQhead[i], i); );
635 if (threadQhead[i] != currentThread)
637 /* USEDSTACKTOP((CONTEXT(currentThread).usedStackTop)); */
639 lastThread = currentThread;
640 currentThread = threadQhead[i];
642 CONTEXT(currentThread).exceptionptr = exceptionptr;
644 THREADSWITCH((&CONTEXT(currentThread)),
645 (&CONTEXT(lastThread)));
648 exceptionptr = CONTEXT(currentThread).exceptionptr;
650 /* Alarm signal may be blocked - if so
654 if (alarmBlocked == true) {
655 alarmBlocked = false;
657 sigaddset(&nsig, SIGALRM);
658 sigprocmask(SIG_UNBLOCK, &nsig, 0);
662 /* I might be dying */
663 if ((CONTEXT(lastThread).flags & THREAD_FLAGS_KILLED)
666 CONTEXT(lastThread).flags &= ~THREAD_FLAGS_KILLED;
667 exceptionptr = native_new_and_init(class_java_lang_ThreadDeath);
670 /* Now we kill the schedule and turn ints
672 needReschedule = false;
676 /* Nothing to run - wait for external event */
677 DBG( fprintf(stderr, "nothing more to do\n"); );