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.
18 #include <sys/types.h>
19 #include <sys/mman.h> /* for mprotect */
33 static classinfo *class_java_lang_ThreadDeath;
43 #if defined(USE_INTERNAL_THREADS)
45 thread* currentThread = NULL;
47 thread* threadQhead[MAX_THREAD_PRIO + 1];
48 thread* threadQtail[MAX_THREAD_PRIO + 1];
50 thread* liveThreads = NULL;
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)
128 thread *the_main_thread;
133 for (i = 0; i < MAXTHREADS; ++i) {
134 contexts[i].free = true;
135 contexts[i].thread = NULL;
136 heap_addreference((void**)&contexts[i].thread);
139 /* Allocate a thread to be the main thread */
140 liveThreads = the_main_thread = (thread*)builtin_new(loader_load(unicode_new_char("java/lang/Thread")));
141 assert(the_main_thread != 0);
142 /* heap_addreference((void **) &liveThreads); */
144 the_main_thread->PrivateInfo = 1;
145 CONTEXT(the_main_thread).free = false;
147 the_main_thread->name = javastring_new(unicode_new_char("main"));
148 the_main_thread->priority = NORM_THREAD_PRIO;
149 CONTEXT(the_main_thread).priority = (u1)the_main_thread->priority;
150 CONTEXT(the_main_thread).exceptionptr = 0;
151 the_main_thread->next = 0;
152 CONTEXT(the_main_thread).status = THREAD_SUSPENDED;
153 CONTEXT(the_main_thread).stackBase = CONTEXT(the_main_thread).stackEnd = stackbottom;
154 THREADINFO(&CONTEXT(the_main_thread));
156 DBG( printf("main thread %p base %p end %p\n",
158 CONTEXT(the_main_thread).stackBase,
159 CONTEXT(the_main_thread).stackEnd); );
161 CONTEXT(the_main_thread).flags = THREAD_FLAGS_NOSTACKALLOC;
162 CONTEXT(the_main_thread).nextlive = 0;
163 CONTEXT(the_main_thread).thread = the_main_thread;
164 the_main_thread->single_step = 0;
165 the_main_thread->daemon = 0;
166 the_main_thread->stillborn = 0;
167 the_main_thread->target = 0;
168 the_main_thread->interruptRequested = 0;
169 the_main_thread->group =
170 (threadGroup*)builtin_new(loader_load(unicode_new_char("java/lang/ThreadGroup")));
171 /* we should call the constructor */
172 assert(the_main_thread->group != 0);
176 /* Load exception classes */
177 class_java_lang_ThreadDeath = loader_load(unicode_new_char("java/lang/ThreadDeath"));
179 DBG( fprintf(stderr, "finishing initThreads\n"); );
181 mainThread = currentThread = the_main_thread;
183 /* heap_addreference((void**)&mainThread); */
185 /* Add thread into runQ */
186 iresumeThread(mainThread);
188 assert(blockInts == 0);
192 * Start a new thread running.
195 startThread (thread* tid)
199 /* Allocate a stack context */
200 for (i = 0; i < MAXTHREADS; ++i)
201 if (contexts[i].free)
205 panic("Too many threads");
207 tid->PrivateInfo = i + 1;
208 CONTEXT(tid).free = false;
209 CONTEXT(tid).thread = tid;
210 CONTEXT(tid).nextlive = liveThreads;
212 allocThreadStack(tid, threadStackSize);
213 CONTEXT(tid).usedStackTop = CONTEXT(tid).stackBase;
214 CONTEXT(tid).flags = THREAD_FLAGS_GENERAL;
215 CONTEXT(tid).status = THREAD_SUSPENDED;
216 CONTEXT(tid).priority = (u1)tid->priority;
217 CONTEXT(tid).exceptionptr = 0;
219 /* Construct the initial restore point. */
220 THREADINIT((&CONTEXT(tid)), firstStartThread);
222 DBG( printf("new thread %p base %p end %p\n",
223 tid, CONTEXT(tid).stackBase,
224 CONTEXT(tid).stackEnd); );
230 /* Add thread into runQ */
235 * Start a daemon thread.
238 startDaemon(void* func, char* nm, int stackSize)
243 DBG( printf("startDaemon %s\n", nm); );
245 tid = (thread*)builtin_new(loader_load(unicode_new_char("java/lang/Thread")));
248 for (i = 0; i < MAXTHREADS; ++i)
249 if (contexts[i].free)
252 panic("Too many threads");
254 tid->PrivateInfo = i + 1;
255 CONTEXT(tid).free = false;
256 tid->name = 0; /* for the moment */
257 tid->priority = MAX_THREAD_PRIO;
258 CONTEXT(tid).priority = (u1)tid->priority;
260 CONTEXT(tid).status = THREAD_SUSPENDED;
262 allocThreadStack(tid, stackSize);
263 tid->single_step = 0;
267 tid->interruptRequested = 0;
270 /* Construct the initial restore point. */
271 THREADINIT((&CONTEXT(tid)), func);
280 * All threads start here.
283 firstStartThread(void)
287 DBG( printf("firstStartThread %p\n", currentThread); );
289 /* Every thread starts with the interrupts off */
291 assert(blockInts == 0);
293 /* Find the run()V method and call it */
294 method = class_findmethod(currentThread->header.vftbl->class,
295 unicode_new_char("run"), unicode_new_char("()V"));
297 panic("Cannot find method \'void run ()\'");
298 asm_calljavamethod(method, currentThread, NULL, NULL, NULL);
301 assert("Thread returned from killThread" == 0);
305 * Resume a thread running.
306 * This routine has to be called only from locations which ensure
307 * run / block queue consistency. There is no check for illegal resume
308 * conditions (like explicitly resuming an IO blocked thread). There also
309 * is no update of any blocking queue. Both has to be done by the caller
312 iresumeThread(thread* tid)
314 DBG( printf("resumeThread %p\n", tid); );
318 if (CONTEXT(tid).status != THREAD_RUNNING)
320 CONTEXT(tid).status = THREAD_RUNNING;
322 DBG( fprintf(stderr, "prio is %d\n", CONTEXT(tid).priority); );
324 /* Place thread on the end of its queue */
325 if (threadQhead[CONTEXT(tid).priority] == 0) {
326 threadQhead[CONTEXT(tid).priority] = tid;
327 threadQtail[CONTEXT(tid).priority] = tid;
328 if (CONTEXT(tid).priority
329 > CONTEXT(currentThread).priority)
330 needReschedule = true;
334 threadQtail[CONTEXT(tid).priority]->next = tid;
335 threadQtail[CONTEXT(tid).priority] = tid;
339 SDBG( else { printf("Re-resuming %p\n", tid); } );
345 * Yield process to another thread of equal priority.
352 if (threadQhead[CONTEXT(currentThread).priority]
353 != threadQtail[CONTEXT(currentThread).priority])
355 /* Get the next thread and move me to the end */
356 threadQhead[CONTEXT(currentThread).priority] = currentThread->next;
357 threadQtail[CONTEXT(currentThread).priority]->next = currentThread;
358 threadQtail[CONTEXT(currentThread).priority] = currentThread;
359 currentThread->next = 0;
360 needReschedule = true;
367 * Explicit request by user to resume a thread
368 * The definition says that it is just legal to call this after a preceeding
369 * suspend (which got through). If the thread was blocked for some other
370 * reason (either sleep or IO or a muxSem), we simply can't do it
371 * We use a new thread flag THREAD_FLAGS_USER_SUSPEND for this purpose
372 * (which is set by suspendThread(.))
375 resumeThread(thread* tid)
377 if ((CONTEXT(tid).flags & THREAD_FLAGS_USER_SUSPEND) != 0)
380 CONTEXT(tid).flags &= ~THREAD_FLAGS_USER_SUSPEND;
388 * This is an explicit user request to suspend the thread - the counterpart
389 * for resumeThreadRequest(.). It is JUST called by the java method
391 * What makes it distinct is the fact that the suspended thread is not contained
392 * in any block queue. Without a special flag (indicating the user suspend), we
393 * can't check s suspended thread for this condition afterwards (which is
394 * required by resumeThreadRequest()). The new thread flag
395 * THREAD_FLAGS_USER_SUSPEND is used for this purpose.
398 suspendThread(thread* tid)
404 if (CONTEXT(tid).status != THREAD_SUSPENDED)
406 CONTEXT(tid).status = THREAD_SUSPENDED;
409 * This is used to indicate the explicit suspend condition
410 * required by resumeThreadRequest()
412 CONTEXT(tid).flags |= THREAD_FLAGS_USER_SUSPEND;
414 for (ntid = &threadQhead[CONTEXT(tid).priority];
416 ntid = &(*ntid)->next)
422 if (tid == currentThread)
430 SDBG( else { printf("Re-suspending %p\n", tid); } );
436 * Suspend a thread on a queue.
439 suspendOnQThread(thread* tid, thread** queue)
443 DBG( printf("suspendOnQThread %p %p\n", tid, queue); );
445 assert(blockInts == 1);
447 if (CONTEXT(tid).status != THREAD_SUSPENDED)
449 CONTEXT(tid).status = THREAD_SUSPENDED;
451 for (ntid = &threadQhead[CONTEXT(tid).priority];
453 ntid = &(*ntid)->next)
458 /* Insert onto head of lock wait Q */
461 if (tid == currentThread)
463 DBG( fprintf(stderr, "suspending %p (cur=%p) with prio %d\n",
464 tid, currentThread, CONTEXT(tid).priority); );
471 SDBG( else { printf("Re-suspending %p on %p\n", tid, *queue); } );
478 killThread(thread* tid)
484 /* A null tid means the current thread */
490 DBG( printf("killThread %p\n", tid); );
492 if (CONTEXT(tid).status != THREAD_DEAD)
494 /* Get thread off runq (if it needs it) */
495 if (CONTEXT(tid).status == THREAD_RUNNING)
497 for (ntid = &threadQhead[CONTEXT(tid).priority];
499 ntid = &(*ntid)->next)
509 CONTEXT(tid).status = THREAD_DEAD;
515 /* If we only have daemons left, then everyone is dead. */
516 if (talive == tdaemon) {
517 /* atexit functions get called to clean things up */
521 /* Notify on the object just in case anyone is waiting */
522 internal_lock_mutex_for_object(&tid->header);
523 internal_broadcast_cond_for_object(&tid->header);
524 internal_unlock_mutex_for_object(&tid->header);
526 /* Remove thread from live list to it can be garbaged */
527 for (ntid = &liveThreads;
529 ntid = &(CONTEXT((*ntid)).nextlive))
533 (*ntid) = CONTEXT(tid).nextlive;
539 freeThreadStack(tid);
542 if (tid != mainThread) {
543 CONTEXT(tid).free = true;
544 CONTEXT(tid).thread = NULL;
547 /* Run something else */
548 needReschedule = true;
554 * Change thread priority.
557 setPriorityThread(thread* tid, int prio)
561 if (tid->PrivateInfo == 0) {
562 tid->priority = prio;
566 if (CONTEXT(tid).status == THREAD_SUSPENDED) {
567 CONTEXT(tid).priority = (u8)prio;
573 /* Remove from current thread list */
574 for (ntid = &threadQhead[CONTEXT(tid).priority]; *ntid != 0; ntid = &(*ntid)->next) {
581 /* Insert onto a new one */
582 tid->priority = prio;
583 CONTEXT(tid).priority = (u8)tid->priority;
584 if (threadQhead[prio] == 0) {
585 threadQhead[prio] = tid;
586 threadQtail[prio] = tid;
587 if (prio > CONTEXT(currentThread).priority) {
588 needReschedule = true;
592 threadQtail[prio]->next = tid;
593 threadQtail[prio] = tid;
601 * Is this thread alive?
604 aliveThread(thread* tid)
606 if (tid->PrivateInfo != 0 && CONTEXT(tid).status != THREAD_DEAD)
613 * Reschedule the thread.
614 * Called whenever a change in the running thread is required.
624 /* A reschedule in a non-blocked context is half way to hell */
625 assert(blockInts > 0);
628 /* Check events - we may release a high priority thread */
629 /* Just check IO, no need for a reschedule call by checkEvents() */
630 needReschedule = false;
635 for (i = MAX_THREAD_PRIO; i >= MIN_THREAD_PRIO; i--)
637 if (threadQhead[i] != 0)
639 DBG( fprintf(stderr, "found thread %p in head %d\n", threadQhead[i], i); );
641 if (threadQhead[i] != currentThread)
643 /* USEDSTACKTOP((CONTEXT(currentThread).usedStackTop)); */
645 lastThread = currentThread;
646 currentThread = threadQhead[i];
648 CONTEXT(currentThread).exceptionptr = exceptionptr;
650 THREADSWITCH((&CONTEXT(currentThread)),
651 (&CONTEXT(lastThread)));
654 exceptionptr = CONTEXT(currentThread).exceptionptr;
656 /* Alarm signal may be blocked - if so
660 if (alarmBlocked == true) {
661 alarmBlocked = false;
663 sigaddset(&nsig, SIGALRM);
664 sigprocmask(SIG_UNBLOCK, &nsig, 0);
668 /* I might be dying */
669 if ((CONTEXT(lastThread).flags & THREAD_FLAGS_KILLED)
672 CONTEXT(lastThread).flags &= ~THREAD_FLAGS_KILLED;
673 exceptionptr = native_new_and_init(class_java_lang_ThreadDeath);
676 /* Now we kill the schedule and turn ints
678 needReschedule = false;
682 /* Nothing to run - wait for external event */
683 DBG( fprintf(stderr, "nothing more to do\n"); );