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;
44 thread* threadQhead[MAX_THREAD_PRIO + 1];
45 thread* threadQtail[MAX_THREAD_PRIO + 1];
50 thread* gcDaemonThread;
55 ctx contexts[MAXTHREADS];
57 /* Number of threads alive, also counting daemons */
60 /* Number of daemon threads alive */
63 static void firstStartThread(void);
65 void reschedule(void);
67 /* Setup default thread stack size - this can be overwritten if required */
68 int threadStackSize = THREADSTACKSIZE;
70 static thread* startDaemon(void* func, char* nm, int stackSize);
73 * Allocate the stack for a thread
76 allocThreadStack (thread *tid, int size)
78 int pageSize = getpagesize(),
80 unsigned long pageBegin;
82 CONTEXT(tid).stackMem = malloc(size + 2 * pageSize);
83 assert(CONTEXT(tid).stackMem != 0);
84 CONTEXT(tid).stackEnd = CONTEXT(tid).stackMem + size + 2 * pageSize;
86 pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
87 pageBegin = pageBegin - pageBegin % pageSize;
89 result = mprotect((void*)pageBegin, pageSize, PROT_NONE);
92 CONTEXT(tid).stackBase = (u1*)pageBegin + pageSize;
96 * Free the stack for a thread
99 freeThreadStack (thread *tid)
101 if (!(CONTEXT(tid).flags & THREAD_FLAGS_NOSTACKALLOC))
103 int pageSize = getpagesize(),
105 unsigned long pageBegin;
107 pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
108 pageBegin = pageBegin - pageBegin % pageSize;
110 result = mprotect((void*)pageBegin, pageSize,
111 PROT_READ | PROT_WRITE | PROT_EXEC);
114 free(CONTEXT(tid).stackMem);
116 CONTEXT(tid).stackMem = 0;
117 CONTEXT(tid).stackBase = 0;
118 CONTEXT(tid).stackEnd = 0;
122 * Initialize threads.
125 initThreads(u1 *stackbottom)
131 for (i = 0; i < MAXTHREADS; ++i)
132 contexts[i].free = true;
134 /* Allocate a thread to be the main thread */
135 currentThread = (thread*)builtin_new(loader_load(unicode_new_char("java/lang/Thread")));
136 assert(currentThread != 0);
138 currentThread->PrivateInfo = 1;
139 CONTEXT(currentThread).free = false;
141 liveThreads = currentThread;
143 currentThread->name = javastring_new(unicode_new_char("main"));
144 currentThread->priority = NORM_THREAD_PRIO;
145 CONTEXT(currentThread).priority = (u1)currentThread->priority;
146 CONTEXT(currentThread).exceptionptr = 0;
147 currentThread->next = 0;
148 CONTEXT(currentThread).status = THREAD_SUSPENDED;
149 CONTEXT(currentThread).stackBase = CONTEXT(currentThread).stackEnd = stackbottom;
150 THREADINFO(&CONTEXT(currentThread));
152 DBG( printf("main thread %p base %p end %p\n",
154 CONTEXT(currentThread).stackBase,
155 CONTEXT(currentThread).stackEnd); );
157 CONTEXT(currentThread).flags = THREAD_FLAGS_NOSTACKALLOC;
158 CONTEXT(currentThread).nextlive = 0;
159 currentThread->single_step = 0;
160 currentThread->daemon = 0;
161 currentThread->stillborn = 0;
162 currentThread->target = 0;
163 currentThread->interruptRequested = 0;
164 currentThread->group =
165 (threadGroup*)builtin_new(loader_load(unicode_new_char("java/lang/ThreadGroup")));
166 /* we should call the constructor */
167 assert(currentThread->group != 0);
171 /* Add thread into runQ */
172 iresumeThread(currentThread);
174 /* Start garbage collection thread */
175 gcDaemonThread = startDaemon(gc_thread, "gc", 1024*512);
176 iresumeThread(gcDaemonThread);
178 heap_addreference((void**)&gcDaemonThread);
180 /* Load exception classes */
181 class_java_lang_ThreadDeath = loader_load(unicode_new_char("java/lang/ThreadDeath"));
183 DBG( fprintf(stderr, "finishing initThreads\n"); );
185 assert(blockInts == 0);
189 * Start a new thread running.
192 startThread (thread* tid)
196 /* Allocate a stack context */
197 for (i = 0; i < MAXTHREADS; ++i)
198 if (contexts[i].free)
202 panic("Too many threads");
204 tid->PrivateInfo = i + 1;
205 CONTEXT(tid).free = false;
206 CONTEXT(tid).nextlive = liveThreads;
208 allocThreadStack(tid, threadStackSize);
209 CONTEXT(tid).usedStackTop = CONTEXT(tid).stackBase;
210 CONTEXT(tid).flags = THREAD_FLAGS_GENERAL;
211 CONTEXT(tid).status = THREAD_SUSPENDED;
212 CONTEXT(tid).priority = (u1)tid->priority;
213 CONTEXT(tid).exceptionptr = 0;
215 /* Construct the initial restore point. */
216 THREADINIT((&CONTEXT(tid)), firstStartThread);
218 DBG( printf("new thread %p base %p end %p\n",
219 tid, CONTEXT(tid).stackBase,
220 CONTEXT(tid).stackEnd); );
226 /* Add thread into runQ */
231 * Start a daemon thread.
234 startDaemon(void* func, char* nm, int stackSize)
239 DBG( printf("startDaemon %s\n", nm); );
241 tid = (thread*)builtin_new(loader_load(unicode_new_char("java/lang/Thread")));
244 for (i = 0; i < MAXTHREADS; ++i)
245 if (contexts[i].free)
248 panic("Too many threads");
250 tid->PrivateInfo = i + 1;
251 CONTEXT(tid).free = false;
252 tid->name = 0; /* for the moment */
253 tid->priority = MAX_THREAD_PRIO;
254 CONTEXT(tid).priority = (u1)tid->priority;
256 CONTEXT(tid).status = THREAD_SUSPENDED;
258 allocThreadStack(tid, stackSize);
259 tid->single_step = 0;
263 tid->interruptRequested = 0;
266 /* Construct the initial restore point. */
267 THREADINIT((&CONTEXT(tid)), func);
276 * All threads start here.
279 firstStartThread(void)
283 DBG( printf("firstStartThread %p\n", currentThread); );
285 /* Every thread starts with the interrupts off */
287 assert(blockInts == 0);
289 /* Find the run()V method and call it */
290 method = class_findmethod(currentThread->header.vftbl->class,
291 unicode_new_char("run"), unicode_new_char("()V"));
293 panic("Cannot find method \'void run ()\'");
294 asm_calljavamethod(method, currentThread, NULL, NULL, NULL);
297 assert("Thread returned from killThread" == 0);
301 * Resume a thread running.
302 * This routine has to be called only from locations which ensure
303 * run / block queue consistency. There is no check for illegal resume
304 * conditions (like explicitly resuming an IO blocked thread). There also
305 * is no update of any blocking queue. Both has to be done by the caller
308 iresumeThread(thread* tid)
310 DBG( printf("resumeThread %p\n", tid); );
314 if (CONTEXT(tid).status != THREAD_RUNNING)
316 CONTEXT(tid).status = THREAD_RUNNING;
318 DBG( fprintf(stderr, "prio is %d\n", CONTEXT(tid).priority); );
320 /* Place thread on the end of its queue */
321 if (threadQhead[CONTEXT(tid).priority] == 0) {
322 threadQhead[CONTEXT(tid).priority] = tid;
323 threadQtail[CONTEXT(tid).priority] = tid;
324 if (CONTEXT(tid).priority
325 > CONTEXT(currentThread).priority)
326 needReschedule = true;
330 threadQtail[CONTEXT(tid).priority]->next = tid;
331 threadQtail[CONTEXT(tid).priority] = tid;
335 SDBG( else { printf("Re-resuming %p\n", tid); } );
341 * Yield process to another thread of equal priority.
348 if (threadQhead[CONTEXT(currentThread).priority]
349 != threadQtail[CONTEXT(currentThread).priority])
351 /* Get the next thread and move me to the end */
352 threadQhead[CONTEXT(currentThread).priority] = currentThread->next;
353 threadQtail[CONTEXT(currentThread).priority]->next = currentThread;
354 threadQtail[CONTEXT(currentThread).priority] = currentThread;
355 currentThread->next = 0;
356 needReschedule = true;
363 * Explicit request by user to resume a thread
364 * The definition says that it is just legal to call this after a preceeding
365 * suspend (which got through). If the thread was blocked for some other
366 * reason (either sleep or IO or a muxSem), we simply can't do it
367 * We use a new thread flag THREAD_FLAGS_USER_SUSPEND for this purpose
368 * (which is set by suspendThread(.))
371 resumeThread(thread* tid)
373 if ((CONTEXT(tid).flags & THREAD_FLAGS_USER_SUSPEND) != 0)
376 CONTEXT(tid).flags &= ~THREAD_FLAGS_USER_SUSPEND;
384 * This is an explicit user request to suspend the thread - the counterpart
385 * for resumeThreadRequest(.). It is JUST called by the java method
387 * What makes it distinct is the fact that the suspended thread is not contained
388 * in any block queue. Without a special flag (indicating the user suspend), we
389 * can't check s suspended thread for this condition afterwards (which is
390 * required by resumeThreadRequest()). The new thread flag
391 * THREAD_FLAGS_USER_SUSPEND is used for this purpose.
394 suspendThread(thread* tid)
400 if (CONTEXT(tid).status != THREAD_SUSPENDED)
402 CONTEXT(tid).status = THREAD_SUSPENDED;
405 * This is used to indicate the explicit suspend condition
406 * required by resumeThreadRequest()
408 CONTEXT(tid).flags |= THREAD_FLAGS_USER_SUSPEND;
410 for (ntid = &threadQhead[CONTEXT(tid).priority];
412 ntid = &(*ntid)->next)
418 if (tid == currentThread)
426 SDBG( else { printf("Re-suspending %p\n", tid); } );
432 * Suspend a thread on a queue.
435 suspendOnQThread(thread* tid, thread** queue)
439 DBG( printf("suspendOnQThread %p %p\n", tid, queue); );
441 assert(blockInts == 1);
443 if (CONTEXT(tid).status != THREAD_SUSPENDED)
445 CONTEXT(tid).status = THREAD_SUSPENDED;
447 for (ntid = &threadQhead[CONTEXT(tid).priority];
449 ntid = &(*ntid)->next)
454 /* Insert onto head of lock wait Q */
457 if (tid == currentThread)
459 DBG( fprintf(stderr, "suspending %p (cur=%p) with prio %d\n",
460 tid, currentThread, CONTEXT(tid).priority); );
467 SDBG( else { printf("Re-suspending %p on %p\n", tid, *queue); } );
474 killThread(thread* tid)
480 /* A null tid means the current thread */
486 DBG( printf("killThread %p\n", tid); );
488 if (CONTEXT(tid).status != THREAD_DEAD)
490 /* Get thread off runq (if it needs it) */
491 if (CONTEXT(tid).status == THREAD_RUNNING)
493 for (ntid = &threadQhead[CONTEXT(tid).priority];
495 ntid = &(*ntid)->next)
505 CONTEXT(tid).status = THREAD_DEAD;
511 /* If we only have daemons left, then everyone is dead. */
512 if (talive == tdaemon) {
513 /* Am I suppose to close things down nicely ?? */
517 /* Notify on the object just in case anyone is waiting */
518 internal_lock_mutex_for_object(&tid->header);
519 internal_broadcast_cond_for_object(&tid->header);
520 internal_unlock_mutex_for_object(&tid->header);
522 /* Remove thread from live list to it can be garbaged */
523 for (ntid = &liveThreads;
525 ntid = &(CONTEXT((*ntid)).nextlive))
529 (*ntid) = CONTEXT(tid).nextlive;
535 freeThreadStack(tid);
538 CONTEXT(tid).free = true;
540 /* Run something else */
541 needReschedule = true;
547 * Change thread priority.
550 setPriorityThread(thread* tid, int prio)
554 if (tid->PrivateInfo == 0) {
555 tid->priority = prio;
559 if (CONTEXT(tid).status == THREAD_SUSPENDED) {
560 CONTEXT(tid).priority = (u8)prio;
566 /* Remove from current thread list */
567 for (ntid = &threadQhead[CONTEXT(tid).priority]; *ntid != 0; ntid = &(*ntid)->next) {
574 /* Insert onto a new one */
575 tid->priority = prio;
576 CONTEXT(tid).priority = (u8)tid->priority;
577 if (threadQhead[prio] == 0) {
578 threadQhead[prio] = tid;
579 threadQtail[prio] = tid;
580 if (prio > CONTEXT(currentThread).priority) {
581 needReschedule = true;
585 threadQtail[prio]->next = tid;
586 threadQtail[prio] = tid;
594 * Is this thread alive?
597 aliveThread(thread* tid)
599 if (tid->PrivateInfo != 0 && CONTEXT(tid).status != THREAD_DEAD)
606 * Reschedule the thread.
607 * Called whenever a change in the running thread is required.
617 /* A reschedule in a non-blocked context is half way to hell */
618 assert(blockInts > 0);
621 /* Check events - we may release a high priority thread */
622 /* Just check IO, no need for a reschedule call by checkEvents() */
623 needReschedule = false;
628 for (i = MAX_THREAD_PRIO; i >= MIN_THREAD_PRIO; i--)
630 if (threadQhead[i] != 0)
632 DBG( fprintf(stderr, "found thread %p in head %d\n", threadQhead[i], i); );
634 if (threadQhead[i] != currentThread)
636 USEDSTACKTOP((CONTEXT(currentThread).usedStackTop));
638 lastThread = currentThread;
639 currentThread = threadQhead[i];
641 CONTEXT(currentThread).exceptionptr = exceptionptr;
643 THREADSWITCH((&CONTEXT(currentThread)),
644 (&CONTEXT(lastThread)));
647 exceptionptr = CONTEXT(currentThread).exceptionptr;
649 /* Alarm signal may be blocked - if so
653 if (alarmBlocked == true) {
654 alarmBlocked = false;
656 sigaddset(&nsig, SIGALRM);
657 sigprocmask(SIG_UNBLOCK, &nsig, 0);
661 /* I might be dying */
662 if ((CONTEXT(lastThread).flags & THREAD_FLAGS_KILLED)
665 CONTEXT(lastThread).flags &= ~THREAD_FLAGS_KILLED;
666 exceptionptr = native_new_and_init(class_java_lang_ThreadDeath);
669 /* Now we kill the schedule and turn ints
671 needReschedule = false;
675 /* Nothing to run - wait for external event */
676 DBG( fprintf(stderr, "nothing more to do\n"); );