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;
133 contexts[i].thread = NULL;
134 heap_addreference((void**)&contexts[i].thread);
137 /* Allocate a thread to be the main thread */
138 liveThreads = the_main_thread = (thread*)builtin_new(loader_load(unicode_new_char("java/lang/Thread")));
139 assert(the_main_thread != 0);
140 /* heap_addreference((void **) &liveThreads); */
142 the_main_thread->PrivateInfo = 1;
143 CONTEXT(the_main_thread).free = false;
145 the_main_thread->name = javastring_new(unicode_new_char("main"));
146 the_main_thread->priority = NORM_THREAD_PRIO;
147 CONTEXT(the_main_thread).priority = (u1)the_main_thread->priority;
148 CONTEXT(the_main_thread).exceptionptr = 0;
149 the_main_thread->next = 0;
150 CONTEXT(the_main_thread).status = THREAD_SUSPENDED;
151 CONTEXT(the_main_thread).stackBase = CONTEXT(the_main_thread).stackEnd = stackbottom;
152 THREADINFO(&CONTEXT(the_main_thread));
154 DBG( printf("main thread %p base %p end %p\n",
156 CONTEXT(the_main_thread).stackBase,
157 CONTEXT(the_main_thread).stackEnd); );
159 CONTEXT(the_main_thread).flags = THREAD_FLAGS_NOSTACKALLOC;
160 CONTEXT(the_main_thread).nextlive = 0;
161 CONTEXT(the_main_thread).thread = the_main_thread;
162 the_main_thread->single_step = 0;
163 the_main_thread->daemon = 0;
164 the_main_thread->stillborn = 0;
165 the_main_thread->target = 0;
166 the_main_thread->interruptRequested = 0;
167 the_main_thread->group =
168 (threadGroup*)builtin_new(loader_load(unicode_new_char("java/lang/ThreadGroup")));
169 /* we should call the constructor */
170 assert(the_main_thread->group != 0);
174 /* Load exception classes */
175 class_java_lang_ThreadDeath = loader_load(unicode_new_char("java/lang/ThreadDeath"));
177 DBG( fprintf(stderr, "finishing initThreads\n"); );
179 mainThread = currentThread = the_main_thread;
181 /* heap_addreference((void**)&mainThread); */
183 /* Add thread into runQ */
184 iresumeThread(mainThread);
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).thread = tid;
208 CONTEXT(tid).nextlive = liveThreads;
210 allocThreadStack(tid, threadStackSize);
211 CONTEXT(tid).usedStackTop = CONTEXT(tid).stackBase;
212 CONTEXT(tid).flags = THREAD_FLAGS_GENERAL;
213 CONTEXT(tid).status = THREAD_SUSPENDED;
214 CONTEXT(tid).priority = (u1)tid->priority;
215 CONTEXT(tid).exceptionptr = 0;
217 /* Construct the initial restore point. */
218 THREADINIT((&CONTEXT(tid)), firstStartThread);
220 DBG( printf("new thread %p base %p end %p\n",
221 tid, CONTEXT(tid).stackBase,
222 CONTEXT(tid).stackEnd); );
228 /* Add thread into runQ */
233 * Start a daemon thread.
236 startDaemon(void* func, char* nm, int stackSize)
241 DBG( printf("startDaemon %s\n", nm); );
243 tid = (thread*)builtin_new(loader_load(unicode_new_char("java/lang/Thread")));
246 for (i = 0; i < MAXTHREADS; ++i)
247 if (contexts[i].free)
250 panic("Too many threads");
252 tid->PrivateInfo = i + 1;
253 CONTEXT(tid).free = false;
254 tid->name = 0; /* for the moment */
255 tid->priority = MAX_THREAD_PRIO;
256 CONTEXT(tid).priority = (u1)tid->priority;
258 CONTEXT(tid).status = THREAD_SUSPENDED;
260 allocThreadStack(tid, stackSize);
261 tid->single_step = 0;
265 tid->interruptRequested = 0;
268 /* Construct the initial restore point. */
269 THREADINIT((&CONTEXT(tid)), func);
278 * All threads start here.
281 firstStartThread(void)
285 DBG( printf("firstStartThread %p\n", currentThread); );
287 /* Every thread starts with the interrupts off */
289 assert(blockInts == 0);
291 /* Find the run()V method and call it */
292 method = class_findmethod(currentThread->header.vftbl->class,
293 unicode_new_char("run"), unicode_new_char("()V"));
295 panic("Cannot find method \'void run ()\'");
296 asm_calljavamethod(method, currentThread, NULL, NULL, NULL);
299 assert("Thread returned from killThread" == 0);
303 * Resume a thread running.
304 * This routine has to be called only from locations which ensure
305 * run / block queue consistency. There is no check for illegal resume
306 * conditions (like explicitly resuming an IO blocked thread). There also
307 * is no update of any blocking queue. Both has to be done by the caller
310 iresumeThread(thread* tid)
312 DBG( printf("resumeThread %p\n", tid); );
316 if (CONTEXT(tid).status != THREAD_RUNNING)
318 CONTEXT(tid).status = THREAD_RUNNING;
320 DBG( fprintf(stderr, "prio is %d\n", CONTEXT(tid).priority); );
322 /* Place thread on the end of its queue */
323 if (threadQhead[CONTEXT(tid).priority] == 0) {
324 threadQhead[CONTEXT(tid).priority] = tid;
325 threadQtail[CONTEXT(tid).priority] = tid;
326 if (CONTEXT(tid).priority
327 > CONTEXT(currentThread).priority)
328 needReschedule = true;
332 threadQtail[CONTEXT(tid).priority]->next = tid;
333 threadQtail[CONTEXT(tid).priority] = tid;
337 SDBG( else { printf("Re-resuming %p\n", tid); } );
343 * Yield process to another thread of equal priority.
350 if (threadQhead[CONTEXT(currentThread).priority]
351 != threadQtail[CONTEXT(currentThread).priority])
353 /* Get the next thread and move me to the end */
354 threadQhead[CONTEXT(currentThread).priority] = currentThread->next;
355 threadQtail[CONTEXT(currentThread).priority]->next = currentThread;
356 threadQtail[CONTEXT(currentThread).priority] = currentThread;
357 currentThread->next = 0;
358 needReschedule = true;
365 * Explicit request by user to resume a thread
366 * The definition says that it is just legal to call this after a preceeding
367 * suspend (which got through). If the thread was blocked for some other
368 * reason (either sleep or IO or a muxSem), we simply can't do it
369 * We use a new thread flag THREAD_FLAGS_USER_SUSPEND for this purpose
370 * (which is set by suspendThread(.))
373 resumeThread(thread* tid)
375 if ((CONTEXT(tid).flags & THREAD_FLAGS_USER_SUSPEND) != 0)
378 CONTEXT(tid).flags &= ~THREAD_FLAGS_USER_SUSPEND;
386 * This is an explicit user request to suspend the thread - the counterpart
387 * for resumeThreadRequest(.). It is JUST called by the java method
389 * What makes it distinct is the fact that the suspended thread is not contained
390 * in any block queue. Without a special flag (indicating the user suspend), we
391 * can't check s suspended thread for this condition afterwards (which is
392 * required by resumeThreadRequest()). The new thread flag
393 * THREAD_FLAGS_USER_SUSPEND is used for this purpose.
396 suspendThread(thread* tid)
402 if (CONTEXT(tid).status != THREAD_SUSPENDED)
404 CONTEXT(tid).status = THREAD_SUSPENDED;
407 * This is used to indicate the explicit suspend condition
408 * required by resumeThreadRequest()
410 CONTEXT(tid).flags |= THREAD_FLAGS_USER_SUSPEND;
412 for (ntid = &threadQhead[CONTEXT(tid).priority];
414 ntid = &(*ntid)->next)
420 if (tid == currentThread)
428 SDBG( else { printf("Re-suspending %p\n", tid); } );
434 * Suspend a thread on a queue.
437 suspendOnQThread(thread* tid, thread** queue)
441 DBG( printf("suspendOnQThread %p %p\n", tid, queue); );
443 assert(blockInts == 1);
445 if (CONTEXT(tid).status != THREAD_SUSPENDED)
447 CONTEXT(tid).status = THREAD_SUSPENDED;
449 for (ntid = &threadQhead[CONTEXT(tid).priority];
451 ntid = &(*ntid)->next)
456 /* Insert onto head of lock wait Q */
459 if (tid == currentThread)
461 DBG( fprintf(stderr, "suspending %p (cur=%p) with prio %d\n",
462 tid, currentThread, CONTEXT(tid).priority); );
469 SDBG( else { printf("Re-suspending %p on %p\n", tid, *queue); } );
476 killThread(thread* tid)
482 /* A null tid means the current thread */
488 DBG( printf("killThread %p\n", tid); );
490 if (CONTEXT(tid).status != THREAD_DEAD)
492 /* Get thread off runq (if it needs it) */
493 if (CONTEXT(tid).status == THREAD_RUNNING)
495 for (ntid = &threadQhead[CONTEXT(tid).priority];
497 ntid = &(*ntid)->next)
507 CONTEXT(tid).status = THREAD_DEAD;
513 /* If we only have daemons left, then everyone is dead. */
514 if (talive == tdaemon) {
515 /* atexit functions get called to clean things up */
519 /* Notify on the object just in case anyone is waiting */
520 internal_lock_mutex_for_object(&tid->header);
521 internal_broadcast_cond_for_object(&tid->header);
522 internal_unlock_mutex_for_object(&tid->header);
524 /* Remove thread from live list to it can be garbaged */
525 for (ntid = &liveThreads;
527 ntid = &(CONTEXT((*ntid)).nextlive))
531 (*ntid) = CONTEXT(tid).nextlive;
537 freeThreadStack(tid);
540 if (tid != mainThread) {
541 CONTEXT(tid).free = true;
542 CONTEXT(tid).thread = NULL;
545 /* Run something else */
546 needReschedule = true;
552 * Change thread priority.
555 setPriorityThread(thread* tid, int prio)
559 if (tid->PrivateInfo == 0) {
560 tid->priority = prio;
564 if (CONTEXT(tid).status == THREAD_SUSPENDED) {
565 CONTEXT(tid).priority = (u8)prio;
571 /* Remove from current thread list */
572 for (ntid = &threadQhead[CONTEXT(tid).priority]; *ntid != 0; ntid = &(*ntid)->next) {
579 /* Insert onto a new one */
580 tid->priority = prio;
581 CONTEXT(tid).priority = (u8)tid->priority;
582 if (threadQhead[prio] == 0) {
583 threadQhead[prio] = tid;
584 threadQtail[prio] = tid;
585 if (prio > CONTEXT(currentThread).priority) {
586 needReschedule = true;
590 threadQtail[prio]->next = tid;
591 threadQtail[prio] = tid;
599 * Is this thread alive?
602 aliveThread(thread* tid)
604 if (tid->PrivateInfo != 0 && CONTEXT(tid).status != THREAD_DEAD)
611 * Reschedule the thread.
612 * Called whenever a change in the running thread is required.
622 /* A reschedule in a non-blocked context is half way to hell */
623 assert(blockInts > 0);
626 /* Check events - we may release a high priority thread */
627 /* Just check IO, no need for a reschedule call by checkEvents() */
628 needReschedule = false;
633 for (i = MAX_THREAD_PRIO; i >= MIN_THREAD_PRIO; i--)
635 if (threadQhead[i] != 0)
637 DBG( fprintf(stderr, "found thread %p in head %d\n", threadQhead[i], i); );
639 if (threadQhead[i] != currentThread)
641 /* USEDSTACKTOP((CONTEXT(currentThread).usedStackTop)); */
643 lastThread = currentThread;
644 currentThread = threadQhead[i];
646 CONTEXT(currentThread).exceptionptr = exceptionptr;
648 THREADSWITCH((&CONTEXT(currentThread)),
649 (&CONTEXT(lastThread)));
652 exceptionptr = CONTEXT(currentThread).exceptionptr;
654 /* Alarm signal may be blocked - if so
658 if (alarmBlocked == true) {
659 alarmBlocked = false;
661 sigaddset(&nsig, SIGALRM);
662 sigprocmask(SIG_UNBLOCK, &nsig, 0);
666 /* I might be dying */
667 if ((CONTEXT(lastThread).flags & THREAD_FLAGS_KILLED)
670 CONTEXT(lastThread).flags &= ~THREAD_FLAGS_KILLED;
671 exceptionptr = native_new_and_init(class_java_lang_ThreadDeath);
674 /* Now we kill the schedule and turn ints
676 needReschedule = false;
680 /* Nothing to run - wait for external event */
681 DBG( fprintf(stderr, "nothing more to do\n"); );