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 */
35 static classinfo *class_java_lang_ThreadDeath;
45 #if defined(USE_INTERNAL_THREADS)
47 thread* currentThread = NULL;
49 thread* threadQhead[MAX_THREAD_PRIO + 1];
50 thread* threadQtail[MAX_THREAD_PRIO + 1];
52 thread* liveThreads = NULL;
53 thread* sleepThreads = NULL;
58 ctx contexts[MAXTHREADS];
60 /* Number of threads alive, also counting daemons */
63 /* Number of daemon threads alive */
66 static void firstStartThread(void);
68 void reschedule(void);
70 /* Setup default thread stack size - this can be overwritten if required */
71 int threadStackSize = THREADSTACKSIZE;
73 /* Pointer to the stack of the last killed thread. The free is delayed. */
74 void *stack_to_be_freed = 0;
76 static thread* startDaemon(void* func, char* nm, int stackSize);
79 * Allocate the stack for a thread
82 allocThreadStack (thread *tid, int size)
84 int pageSize = getpagesize(),
86 unsigned long pageBegin;
88 assert(stack_to_be_freed == 0);
90 CONTEXT(tid).stackMem = malloc(size + 4 * pageSize);
91 assert(CONTEXT(tid).stackMem != 0);
92 CONTEXT(tid).stackEnd = CONTEXT(tid).stackMem + size + 2 * pageSize;
94 pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
95 pageBegin = pageBegin - pageBegin % pageSize;
97 result = mprotect((void*)pageBegin, pageSize, PROT_NONE);
100 CONTEXT(tid).stackBase = (u1*)pageBegin + pageSize;
104 * Mark the stack for a thread to be freed. We cannot free the stack
105 * immediately because it is still in use!
108 freeThreadStack (thread *tid)
110 if (!(CONTEXT(tid).flags & THREAD_FLAGS_NOSTACKALLOC))
112 int pageSize = getpagesize(),
114 unsigned long pageBegin;
116 pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
117 pageBegin = pageBegin - pageBegin % pageSize;
119 result = mprotect((void*)pageBegin, pageSize,
120 PROT_READ | PROT_WRITE | PROT_EXEC);
123 assert(stack_to_be_freed == 0);
125 stack_to_be_freed = CONTEXT(tid).stackMem;
127 CONTEXT(tid).stackMem = 0;
128 CONTEXT(tid).stackBase = 0;
129 CONTEXT(tid).stackEnd = 0;
133 * Initialize threads.
136 initThreads(u1 *stackbottom)
138 thread *the_main_thread;
141 signal(SIGPIPE, SIG_IGN);
145 for (i = 0; i < MAXTHREADS; ++i) {
146 contexts[i].free = true;
147 contexts[i].thread = NULL;
148 heap_addreference((void**)&contexts[i].thread);
151 /* Allocate a thread to be the main thread */
152 liveThreads = the_main_thread = (thread*)builtin_new(loader_load(utf_new_char("java/lang/Thread")));
153 assert(the_main_thread != 0);
154 /* heap_addreference((void **) &liveThreads); */
156 the_main_thread->PrivateInfo = 1;
157 CONTEXT(the_main_thread).free = false;
159 the_main_thread->name = javastring_new(utf_new_char("main"));
160 the_main_thread->priority = NORM_THREAD_PRIO;
161 CONTEXT(the_main_thread).priority = (u1)the_main_thread->priority;
162 CONTEXT(the_main_thread).exceptionptr = 0;
163 the_main_thread->next = 0;
164 CONTEXT(the_main_thread).status = THREAD_SUSPENDED;
165 CONTEXT(the_main_thread).stackBase = CONTEXT(the_main_thread).stackEnd = stackbottom;
166 THREADINFO(&CONTEXT(the_main_thread));
168 DBG( printf("main thread %p base %p end %p\n",
170 CONTEXT(the_main_thread).stackBase,
171 CONTEXT(the_main_thread).stackEnd); );
173 CONTEXT(the_main_thread).flags = THREAD_FLAGS_NOSTACKALLOC;
174 CONTEXT(the_main_thread).nextlive = 0;
175 CONTEXT(the_main_thread).thread = the_main_thread;
176 the_main_thread->single_step = 0;
177 the_main_thread->daemon = 0;
178 the_main_thread->stillborn = 0;
179 the_main_thread->target = 0;
181 the_main_thread->contextClassLoader = 0;
182 the_main_thread->inheritedAccessControlContext = 0;
183 the_main_thread->values = 0;
185 /* Allocate and init ThreadGroup */
186 the_main_thread->group = (threadGroup*)native_new_and_init(loader_load(utf_new_char("java/lang/ThreadGroup")));
187 assert(the_main_thread->group != 0);
191 /* Load exception classes */
192 class_java_lang_ThreadDeath = loader_load(utf_new_char("java/lang/ThreadDeath"));
194 DBG( fprintf(stderr, "finishing initThreads\n"); );
196 mainThread = currentThread = the_main_thread;
198 /* heap_addreference((void**)&mainThread); */
200 /* Add thread into runQ */
201 iresumeThread(mainThread);
203 assert(blockInts == 0);
207 * Start a new thread running.
210 startThread (thread* tid)
214 /* Allocate a stack context */
215 for (i = 0; i < MAXTHREADS; ++i)
216 if (contexts[i].free)
220 panic("Too many threads");
222 assert(tid->priority >= MIN_THREAD_PRIO && tid->priority <= MAX_THREAD_PRIO);
224 tid->PrivateInfo = i + 1;
225 CONTEXT(tid).free = false;
226 CONTEXT(tid).thread = tid;
227 CONTEXT(tid).nextlive = liveThreads;
229 allocThreadStack(tid, threadStackSize);
230 CONTEXT(tid).usedStackTop = CONTEXT(tid).stackBase;
231 CONTEXT(tid).flags = THREAD_FLAGS_GENERAL;
232 CONTEXT(tid).status = THREAD_SUSPENDED;
233 CONTEXT(tid).priority = (u1)tid->priority;
234 CONTEXT(tid).exceptionptr = 0;
236 /* Construct the initial restore point. */
237 THREADINIT((&CONTEXT(tid)), firstStartThread);
239 DBG( printf("new thread %p base %p end %p\n",
240 tid, CONTEXT(tid).stackBase,
241 CONTEXT(tid).stackEnd); );
247 /* Add thread into runQ */
252 * Start a daemon thread.
255 startDaemon(void* func, char* nm, int stackSize)
260 DBG( printf("startDaemon %s\n", nm); );
262 tid = (thread*)builtin_new(loader_load(utf_new_char("java/lang/Thread")));
265 for (i = 0; i < MAXTHREADS; ++i)
266 if (contexts[i].free)
269 panic("Too many threads");
271 tid->PrivateInfo = i + 1;
272 CONTEXT(tid).free = false;
273 tid->name = 0; /* for the moment */
274 tid->priority = MAX_THREAD_PRIO;
275 CONTEXT(tid).priority = (u1)tid->priority;
277 CONTEXT(tid).status = THREAD_SUSPENDED;
279 allocThreadStack(tid, stackSize);
280 tid->single_step = 0;
286 /* Construct the initial restore point. */
287 THREADINIT((&CONTEXT(tid)), func);
296 * All threads start here.
299 firstStartThread(void)
303 DBG( printf("firstStartThread %p\n", currentThread); );
305 /* Every thread starts with the interrupts off */
307 assert(blockInts == 0);
309 /* Find the run()V method and call it */
310 method = class_findmethod(currentThread->header.vftbl->class,
311 utf_new_char("run"), utf_new_char("()V"));
313 panic("Cannot find method \'void run ()\'");
314 asm_calljavamethod(method, currentThread, NULL, NULL, NULL);
317 assert("Thread returned from killThread" == 0);
321 * Resume a thread running.
322 * This routine has to be called only from locations which ensure
323 * run / block queue consistency. There is no check for illegal resume
324 * conditions (like explicitly resuming an IO blocked thread). There also
325 * is no update of any blocking queue. Both has to be done by the caller
328 iresumeThread(thread* tid)
330 DBG( printf("resumeThread %p\n", tid); );
334 if (CONTEXT(tid).status != THREAD_RUNNING)
336 CONTEXT(tid).status = THREAD_RUNNING;
338 DBG( fprintf(stderr, "prio is %d\n", CONTEXT(tid).priority); );
340 /* Place thread on the end of its queue */
341 if (threadQhead[CONTEXT(tid).priority] == 0) {
342 threadQhead[CONTEXT(tid).priority] = tid;
343 threadQtail[CONTEXT(tid).priority] = tid;
344 if (CONTEXT(tid).priority
345 > CONTEXT(currentThread).priority)
346 needReschedule = true;
350 threadQtail[CONTEXT(tid).priority]->next = tid;
351 threadQtail[CONTEXT(tid).priority] = tid;
355 SDBG( else { printf("Re-resuming %p\n", tid); } );
361 * Yield process to another thread of equal priority.
368 if (threadQhead[CONTEXT(currentThread).priority]
369 != threadQtail[CONTEXT(currentThread).priority])
371 /* Get the next thread and move me to the end */
372 threadQhead[CONTEXT(currentThread).priority] = currentThread->next;
373 threadQtail[CONTEXT(currentThread).priority]->next = currentThread;
374 threadQtail[CONTEXT(currentThread).priority] = currentThread;
375 currentThread->next = 0;
376 needReschedule = true;
383 * Explicit request by user to resume a thread
384 * The definition says that it is just legal to call this after a preceeding
385 * suspend (which got through). If the thread was blocked for some other
386 * reason (either sleep or IO or a muxSem), we simply can't do it
387 * We use a new thread flag THREAD_FLAGS_USER_SUSPEND for this purpose
388 * (which is set by suspendThread(.))
391 resumeThread (thread* tid)
393 if ((CONTEXT(tid).flags & THREAD_FLAGS_USER_SUSPEND) != 0)
396 CONTEXT(tid).flags &= ~THREAD_FLAGS_USER_SUSPEND;
404 * This is an explicit user request to suspend the thread - the counterpart
405 * for resumeThreadRequest(.). It is JUST called by the java method
407 * What makes it distinct is the fact that the suspended thread is not contained
408 * in any block queue. Without a special flag (indicating the user suspend), we
409 * can't check s suspended thread for this condition afterwards (which is
410 * required by resumeThreadRequest()). The new thread flag
411 * THREAD_FLAGS_USER_SUSPEND is used for this purpose.
414 suspendThread(thread* tid)
420 if (CONTEXT(tid).status != THREAD_SUSPENDED)
422 CONTEXT(tid).status = THREAD_SUSPENDED;
425 * This is used to indicate the explicit suspend condition
426 * required by resumeThreadRequest()
428 CONTEXT(tid).flags |= THREAD_FLAGS_USER_SUSPEND;
430 for (ntid = &threadQhead[CONTEXT(tid).priority];
432 ntid = &(*ntid)->next)
438 if (tid == currentThread)
446 SDBG( else { printf("Re-suspending %p\n", tid); } );
452 * Suspend a thread on a queue.
455 suspendOnQThread(thread* tid, thread** queue)
459 DBG( printf("suspendOnQThread %p %p\n", tid, queue); );
461 assert(blockInts == 1);
463 if (CONTEXT(tid).status != THREAD_SUSPENDED)
465 CONTEXT(tid).status = THREAD_SUSPENDED;
467 for (ntid = &threadQhead[CONTEXT(tid).priority];
469 ntid = &(*ntid)->next)
474 /* Insert onto head of lock wait Q */
477 if (tid == currentThread)
479 DBG( fprintf(stderr, "suspending %p (cur=%p) with prio %d\n",
480 tid, currentThread, CONTEXT(tid).priority); );
487 SDBG( else { printf("Re-suspending %p on %p\n", tid, *queue); } );
494 killThread(thread* tid)
500 /* A null tid means the current thread */
506 DBG( printf("killThread %p\n", tid); );
508 if (CONTEXT(tid).status != THREAD_DEAD)
510 /* Get thread off runq (if it needs it) */
511 if (CONTEXT(tid).status == THREAD_RUNNING)
513 for (ntid = &threadQhead[CONTEXT(tid).priority];
515 ntid = &(*ntid)->next)
525 CONTEXT(tid).status = THREAD_DEAD;
531 /* If we only have daemons left, then everyone is dead. */
532 if (talive == tdaemon) {
533 /* atexit functions get called to clean things up */
538 /* Notify on the object just in case anyone is waiting */
539 internal_lock_mutex_for_object(&tid->header);
540 internal_broadcast_cond_for_object(&tid->header);
541 internal_unlock_mutex_for_object(&tid->header);
543 /* Remove thread from live list to it can be garbaged */
544 for (ntid = &liveThreads;
546 ntid = &(CONTEXT((*ntid)).nextlive))
550 (*ntid) = CONTEXT(tid).nextlive;
556 freeThreadStack(tid);
559 if (tid != mainThread) {
560 CONTEXT(tid).free = true;
561 CONTEXT(tid).thread = NULL;
564 /* Run something else */
565 needReschedule = true;
571 * Change thread priority.
574 setPriorityThread(thread* tid, int prio)
578 assert(prio >= MIN_THREAD_PRIO && prio <= MAX_THREAD_PRIO);
580 if (tid->PrivateInfo == 0) {
581 tid->priority = prio;
585 if (CONTEXT(tid).status == THREAD_SUSPENDED) {
586 CONTEXT(tid).priority = (u8)prio;
592 /* Remove from current thread list */
593 for (ntid = &threadQhead[CONTEXT(tid).priority]; *ntid != 0; ntid = &(*ntid)->next) {
600 /* Insert onto a new one */
601 tid->priority = prio;
602 CONTEXT(tid).priority = (u8)tid->priority;
603 if (threadQhead[prio] == 0) {
604 threadQhead[prio] = tid;
605 threadQtail[prio] = tid;
606 if (prio > CONTEXT(currentThread).priority) {
607 needReschedule = true;
611 threadQtail[prio]->next = tid;
612 threadQtail[prio] = tid;
620 * Get the current time in milliseconds since 1970-01-01.
628 gettimeofday(&tv, 0);
632 time += tv.tv_usec / 1000;
638 * Put a thread to sleep.
641 sleepThread (s8 time)
645 /* Sleep for no time */
652 /* Get absolute time */
653 CONTEXT(currentThread).time = time + currentTime();
655 /* Find place in alarm list */
656 for (tidp = &sleepThreads; (*tidp) != 0; tidp = &(*tidp)->next)
658 if (CONTEXT(*tidp).time > CONTEXT(currentThread).time)
662 /* Suspend thread on it */
663 suspendOnQThread(currentThread, tidp);
669 * Is this thread alive?
672 aliveThread(thread* tid)
674 if (tid->PrivateInfo != 0 && CONTEXT(tid).status != THREAD_DEAD)
681 * Reschedule the thread.
682 * Called whenever a change in the running thread is required.
692 /* A reschedule in a non-blocked context is half way to hell */
693 assert(blockInts > 0);
696 /* Check events - we may release a high priority thread */
697 /* Just check IO, no need for a reschedule call by checkEvents() */
698 needReschedule = false;
703 for (i = MAX_THREAD_PRIO; i >= MIN_THREAD_PRIO; i--)
705 if (threadQhead[i] != 0)
707 DBG( fprintf(stderr, "found thread %p in head %d\n", threadQhead[i], i); );
709 if (threadQhead[i] != currentThread)
711 /* USEDSTACKTOP((CONTEXT(currentThread).usedStackTop)); */
713 lastThread = currentThread;
714 currentThread = threadQhead[i];
716 CONTEXT(currentThread).exceptionptr = exceptionptr;
718 THREADSWITCH((&CONTEXT(currentThread)),
719 (&CONTEXT(lastThread)));
722 exceptionptr = CONTEXT(currentThread).exceptionptr;
724 if (stack_to_be_freed != 0)
726 free(stack_to_be_freed);
727 stack_to_be_freed = 0;
730 /* Alarm signal may be blocked - if so
734 if (alarmBlocked == true) {
735 alarmBlocked = false;
737 sigaddset(&nsig, SIGALRM);
738 sigprocmask(SIG_UNBLOCK, &nsig, 0);
742 /* I might be dying */
743 if ((CONTEXT(lastThread).flags & THREAD_FLAGS_KILLED)
746 CONTEXT(lastThread).flags &= ~THREAD_FLAGS_KILLED;
747 exceptionptr = native_new_and_init(class_java_lang_ThreadDeath);
750 /* Now we kill the schedule and turn ints
752 needReschedule = false;
756 /* Nothing to run - wait for external event */
757 DBG( fprintf(stderr, "nothing more to do\n"); );