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 */
32 #include "toolbox/loging.h"
33 #include "toolbox/memory.h"
35 #if defined(NATIVE_THREADS)
36 pthread_mutex_t cast_mutex = PTHREAD_MUTEX_INITIALIZER;
37 pthread_mutex_t compiler_mutex = PTHREAD_MUTEX_INITIALIZER;
40 static classinfo *class_java_lang_ThreadDeath;
42 thread* currentThread = NULL;
44 thread* threadQhead[MAX_THREAD_PRIO + 1];
45 thread* threadQtail[MAX_THREAD_PRIO + 1];
47 thread* liveThreads = NULL;
48 thread* sleepThreads = NULL;
53 ctx contexts[MAXTHREADS];
55 /* Number of threads alive, also counting daemons */
58 /* Number of daemon threads alive */
61 static void firstStartThread(void);
63 void reschedule(void);
65 /* Setup default thread stack size - this can be overwritten if required */
66 int threadStackSize = THREADSTACKSIZE;
68 /* Pointer to the stack of the last killed thread. The free is delayed. */
69 void *stack_to_be_freed = 0;
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();
80 unsigned long pageBegin;
82 assert(stack_to_be_freed == 0);
84 CONTEXT(tid).stackMem = GCNEW(u1, size + 4 * pageSize);
85 assert(CONTEXT(tid).stackMem != 0);
86 CONTEXT(tid).stackEnd = CONTEXT(tid).stackMem + size + 2 * pageSize;
88 pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
89 pageBegin = pageBegin - pageBegin % pageSize;
91 CONTEXT(tid).stackBase = (u1*)pageBegin + pageSize;
95 * Mark the stack for a thread to be freed. We cannot free the stack
96 * immediately because it is still in use!
99 freeThreadStack (thread *tid)
101 if (!(CONTEXT(tid).flags & THREAD_FLAGS_NOSTACKALLOC))
103 int pageSize = getpagesize();
104 unsigned long pageBegin;
106 pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
107 pageBegin = pageBegin - pageBegin % pageSize;
109 assert(stack_to_be_freed == 0);
111 stack_to_be_freed = CONTEXT(tid).stackMem;
113 CONTEXT(tid).stackMem = 0;
114 CONTEXT(tid).stackBase = 0;
115 CONTEXT(tid).stackEnd = 0;
119 * Initialize threads.
122 initThreads(u1 *stackbottom)
124 thread *the_main_thread;
126 char mainname[] = "main";
127 /*int len = strlen(mainname);*/
129 signal(SIGPIPE, SIG_IGN);
133 for (i = 0; i < MAXTHREADS; ++i) {
134 contexts[i].free = true;
135 contexts[i].thread = NULL;
138 /* Allocate a thread to be the main thread */
139 liveThreads = the_main_thread = (thread*)builtin_new(loader_load_sysclass(NULL,utf_new_char("java/lang/Thread")));
140 assert(the_main_thread != 0);
142 the_main_thread->PrivateInfo = 1;
143 CONTEXT(the_main_thread).free = false;
149 m = class_fetchmethod(
150 class_java_lang_String,
151 utf_new_char ("toCharArray"),
152 utf_new_char ("()[C")
154 printf("DEADCODE LIVES ?????????\n");fflush(stdout);
155 the_main_thread->name = asm_calljavafunction (m, javastring_new(utf_new_char("main")), 0, 0, 0);
158 the_main_thread->name=javastring_new(utf_new_char(mainname));
159 /* the_main_thread->name = builtin_newarray_char(len);
160 { u2 *d = the_main_thread->name->data;
161 for (i=0; i<len; i++)
164 the_main_thread->priority = NORM_THREAD_PRIO;
165 CONTEXT(the_main_thread).priority = (u1)the_main_thread->priority;
166 CONTEXT(the_main_thread).exceptionptr = 0;
167 the_main_thread->next = 0;
168 CONTEXT(the_main_thread).status = THREAD_SUSPENDED;
169 CONTEXT(the_main_thread).stackBase = CONTEXT(the_main_thread).stackEnd = stackbottom;
170 THREADINFO(&CONTEXT(the_main_thread));
172 DBG( printf("main thread %p base %p end %p\n",
174 CONTEXT(the_main_thread).stackBase,
175 CONTEXT(the_main_thread).stackEnd); );
177 CONTEXT(the_main_thread).flags = THREAD_FLAGS_NOSTACKALLOC;
178 CONTEXT(the_main_thread).nextlive = 0;
179 CONTEXT(the_main_thread).thread = the_main_thread;
180 /*the_main_thread->single_step = 0;*/
181 the_main_thread->daemon = 0;
182 /*the_main_thread->stillborn = 0;*/
183 /*the_main_thread->target = 0;*/
185 the_main_thread->contextClassLoader = 0;
186 /*the_main_thread->inheritedAccessControlContext = 0;*/
187 /*the_main_thread->values = 0;*/
189 /* Allocate and init ThreadGroup */
190 the_main_thread->group = (threadGroup*)native_new_and_init(loader_load(utf_new_char("java/lang/ThreadGroup")));
191 assert(the_main_thread->group != 0);
195 /* Load exception classes */
196 loader_load_sysclass(&class_java_lang_ThreadDeath,
197 utf_new_char("java/lang/ThreadDeath"));
199 DBG( fprintf(stderr, "finishing initThreads\n"); );
201 mainThread = currentThread = the_main_thread;
203 /* Add thread into runQ */
204 iresumeThread(mainThread);
206 assert(blockInts == 0);
210 * Start a new thread running.
213 startThread (thread* tid)
217 /* Allocate a stack context */
218 for (i = 0; i < MAXTHREADS; ++i)
219 if (contexts[i].free)
223 panic("Too many threads");
225 assert(tid->priority >= MIN_THREAD_PRIO && tid->priority <= MAX_THREAD_PRIO);
227 tid->PrivateInfo = i + 1;
228 CONTEXT(tid).free = false;
229 CONTEXT(tid).thread = tid;
230 CONTEXT(tid).nextlive = liveThreads;
232 allocThreadStack(tid, threadStackSize);
233 CONTEXT(tid).usedStackTop = CONTEXT(tid).stackBase;
234 CONTEXT(tid).flags = THREAD_FLAGS_GENERAL;
235 CONTEXT(tid).status = THREAD_SUSPENDED;
236 CONTEXT(tid).priority = (u1)tid->priority;
237 CONTEXT(tid).exceptionptr = 0;
239 /* Construct the initial restore point. */
240 THREADINIT((&CONTEXT(tid)), firstStartThread);
242 DBG( printf("new thread %p base %p end %p\n",
243 tid, CONTEXT(tid).stackBase,
244 CONTEXT(tid).stackEnd); );
250 /* Add thread into runQ */
255 * Start a daemon thread.
258 startDaemon(void* func, char* nm, int stackSize)
263 DBG( printf("startDaemon %s\n", nm); );
265 tid = (thread*)builtin_new(loader_load_sysclass(NULL,utf_new_char("java/lang/Thread")));
268 for (i = 0; i < MAXTHREADS; ++i)
269 if (contexts[i].free)
272 panic("Too many threads");
274 tid->PrivateInfo = i + 1;
275 CONTEXT(tid).free = false;
276 tid->name = 0; /* for the moment */
277 tid->priority = MAX_THREAD_PRIO;
278 CONTEXT(tid).priority = (u1)tid->priority;
280 CONTEXT(tid).status = THREAD_SUSPENDED;
282 allocThreadStack(tid, stackSize);
283 /*tid->single_step = 0;*/
285 /*tid->stillborn = 0;*/
289 /* Construct the initial restore point. */
290 THREADINIT((&CONTEXT(tid)), func);
299 * All threads start here.
302 firstStartThread(void)
306 DBG( printf("firstStartThread %p\n", currentThread); );
308 if (stack_to_be_freed != 0) {
309 stack_to_be_freed = 0;
312 /* Every thread starts with the interrupts off */
314 assert(blockInts == 0);
316 /* Find the run()V method and call it */
317 method = class_findmethod(currentThread->header.vftbl->class,
318 utf_new_char("run"), utf_new_char("()V"));
320 panic("Cannot find method \'void run ()\'");
322 asm_calljavafunction(method, currentThread, NULL, NULL, NULL);
325 utf_display(exceptionptr->vftbl->class->name);
330 assert("Thread returned from killThread" == 0);
334 * Resume a thread running.
335 * This routine has to be called only from locations which ensure
336 * run / block queue consistency. There is no check for illegal resume
337 * conditions (like explicitly resuming an IO blocked thread). There also
338 * is no update of any blocking queue. Both has to be done by the caller
341 iresumeThread(thread* tid)
343 DBG( printf("resumeThread %p\n", tid); );
347 if (CONTEXT(tid).status != THREAD_RUNNING)
349 CONTEXT(tid).status = THREAD_RUNNING;
351 DBG( fprintf(stderr, "prio is %d\n", CONTEXT(tid).priority); );
353 /* Place thread on the end of its queue */
354 if (threadQhead[CONTEXT(tid).priority] == 0) {
355 threadQhead[CONTEXT(tid).priority] = tid;
356 threadQtail[CONTEXT(tid).priority] = tid;
357 if (CONTEXT(tid).priority
358 > CONTEXT(currentThread).priority)
359 needReschedule = true;
363 threadQtail[CONTEXT(tid).priority]->next = tid;
364 threadQtail[CONTEXT(tid).priority] = tid;
368 SDBG( else { printf("Re-resuming %p\n", tid); } );
374 * Yield process to another thread of equal priority.
381 if (threadQhead[CONTEXT(currentThread).priority]
382 != threadQtail[CONTEXT(currentThread).priority])
384 /* Get the next thread and move me to the end */
385 threadQhead[CONTEXT(currentThread).priority] = currentThread->next;
386 threadQtail[CONTEXT(currentThread).priority]->next = currentThread;
387 threadQtail[CONTEXT(currentThread).priority] = currentThread;
388 currentThread->next = 0;
389 needReschedule = true;
396 * Explicit request by user to resume a thread
397 * The definition says that it is just legal to call this after a preceeding
398 * suspend (which got through). If the thread was blocked for some other
399 * reason (either sleep or IO or a muxSem), we simply can't do it
400 * We use a new thread flag THREAD_FLAGS_USER_SUSPEND for this purpose
401 * (which is set by suspendThread(.))
404 resumeThread (thread* tid)
406 if ((CONTEXT(tid).flags & THREAD_FLAGS_USER_SUSPEND) != 0)
409 CONTEXT(tid).flags &= ~THREAD_FLAGS_USER_SUSPEND;
417 * This is an explicit user request to suspend the thread - the counterpart
418 * for resumeThreadRequest(.). It is JUST called by the java method
420 * What makes it distinct is the fact that the suspended thread is not contained
421 * in any block queue. Without a special flag (indicating the user suspend), we
422 * can't check s suspended thread for this condition afterwards (which is
423 * required by resumeThreadRequest()). The new thread flag
424 * THREAD_FLAGS_USER_SUSPEND is used for this purpose.
427 suspendThread(thread* tid)
433 if (CONTEXT(tid).status != THREAD_SUSPENDED)
435 CONTEXT(tid).status = THREAD_SUSPENDED;
438 * This is used to indicate the explicit suspend condition
439 * required by resumeThreadRequest()
441 CONTEXT(tid).flags |= THREAD_FLAGS_USER_SUSPEND;
443 for (ntid = &threadQhead[CONTEXT(tid).priority];
445 ntid = &(*ntid)->next)
451 if (tid == currentThread)
459 SDBG( else { printf("Re-suspending %p\n", tid); } );
465 * Suspend a thread on a queue.
468 suspendOnQThread(thread* tid, thread** queue)
472 DBG( printf("suspendOnQThread %p %p\n", tid, queue); );
474 assert(blockInts > 0);
476 if (CONTEXT(tid).status != THREAD_SUSPENDED)
478 CONTEXT(tid).status = THREAD_SUSPENDED;
480 for (ntid = &threadQhead[CONTEXT(tid).priority];
482 ntid = &(*ntid)->next)
487 /* Insert onto head of lock wait Q */
490 if (tid == currentThread)
492 DBG( fprintf(stderr, "suspending %p (cur=%p) with prio %d\n",
493 tid, currentThread, CONTEXT(tid).priority); );
500 SDBG( else { printf("Re-suspending %p on %p\n", tid, *queue); } );
507 killThread(thread* tid)
513 /* A null tid means the current thread */
519 DBG( printf("killThread %p\n", tid); );
521 if (CONTEXT(tid).status != THREAD_DEAD)
523 /* Get thread off runq (if it needs it) */
524 if (CONTEXT(tid).status == THREAD_RUNNING)
526 for (ntid = &threadQhead[CONTEXT(tid).priority];
528 ntid = &(*ntid)->next)
538 CONTEXT(tid).status = THREAD_DEAD;
544 /* If we only have daemons left, then everyone is dead. */
545 if (talive == tdaemon) {
546 /* atexit functions get called to clean things up */
551 /* Notify on the object just in case anyone is waiting */
552 internal_lock_mutex_for_object(&tid->header);
553 internal_broadcast_cond_for_object(&tid->header);
554 internal_unlock_mutex_for_object(&tid->header);
556 /* Remove thread from live list to it can be garbaged */
557 for (ntid = &liveThreads;
559 ntid = &(CONTEXT((*ntid)).nextlive))
563 (*ntid) = CONTEXT(tid).nextlive;
569 freeThreadStack(tid);
572 if (tid != mainThread) {
573 CONTEXT(tid).free = true;
574 CONTEXT(tid).thread = NULL;
577 /* Run something else */
578 needReschedule = true;
584 * Change thread priority.
587 setPriorityThread(thread* tid, int prio)
591 assert(prio >= MIN_THREAD_PRIO && prio <= MAX_THREAD_PRIO);
593 if (tid->PrivateInfo == 0) {
594 tid->priority = prio;
598 if (CONTEXT(tid).status == THREAD_SUSPENDED) {
599 CONTEXT(tid).priority = (u8)prio;
605 /* Remove from current thread list */
606 for (ntid = &threadQhead[CONTEXT(tid).priority]; *ntid != 0; ntid = &(*ntid)->next) {
613 /* Insert onto a new one */
614 tid->priority = prio;
615 CONTEXT(tid).priority = (u8)tid->priority;
616 if (threadQhead[prio] == 0) {
617 threadQhead[prio] = tid;
618 threadQtail[prio] = tid;
619 if (prio > CONTEXT(currentThread).priority) {
620 needReschedule = true;
624 threadQtail[prio]->next = tid;
625 threadQtail[prio] = tid;
633 * Get the current time in milliseconds since 1970-01-01.
641 gettimeofday(&tv, 0);
645 time += tv.tv_usec / 1000;
651 * Put a thread to sleep.
654 sleepThread (s8 time)
658 /* Sleep for no time */
665 /* Get absolute time */
666 CONTEXT(currentThread).time = time + currentTime();
668 /* Find place in alarm list */
669 for (tidp = &sleepThreads; (*tidp) != 0; tidp = &(*tidp)->next)
671 if (CONTEXT(*tidp).time > CONTEXT(currentThread).time)
675 /* Suspend thread on it */
676 suspendOnQThread(currentThread, tidp);
682 * Is this thread alive?
685 aliveThread(thread* tid)
687 if (tid->PrivateInfo != 0 && CONTEXT(tid).status != THREAD_DEAD)
694 * Reschedule the thread.
695 * Called whenever a change in the running thread is required.
705 /* A reschedule in a non-blocked context is half way to hell */
706 assert(blockInts > 0);
709 /* Check events - we may release a high priority thread */
710 /* Just check IO, no need for a reschedule call by checkEvents() */
711 needReschedule = false;
716 for (i = MAX_THREAD_PRIO; i >= MIN_THREAD_PRIO; i--)
718 if (threadQhead[i] != 0)
720 DBG( fprintf(stderr, "found thread %p in head %d\n", threadQhead[i], i); );
722 if (threadQhead[i] != currentThread)
724 /* USEDSTACKTOP((CONTEXT(currentThread).usedStackTop)); */
726 lastThread = currentThread;
727 currentThread = threadQhead[i];
729 CONTEXT(currentThread).exceptionptr = exceptionptr;
731 DBG( fprintf(stderr, "thread switch from: %p to: %p\n", lastThread, currentThread); );
732 THREADSWITCH((&CONTEXT(currentThread)),
733 (&CONTEXT(lastThread)));
736 exceptionptr = CONTEXT(currentThread).exceptionptr;
738 if (stack_to_be_freed != 0) {
739 stack_to_be_freed = 0;
742 /* Alarm signal may be blocked - if so
746 if (alarmBlocked == true) {
747 alarmBlocked = false;
749 sigaddset(&nsig, SIGALRM);
750 sigprocmask(SIG_UNBLOCK, &nsig, 0);
754 /* I might be dying */
755 if ((CONTEXT(lastThread).flags & THREAD_FLAGS_KILLED)
758 CONTEXT(lastThread).flags &= ~THREAD_FLAGS_KILLED;
759 exceptionptr = native_new_and_init(class_java_lang_ThreadDeath);
762 /* Now we kill the schedule and turn ints
764 needReschedule = false;
768 /* Nothing to run - wait for external event */
769 DBG( fprintf(stderr, "nothing more to do\n"); );