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.
19 #include <sys/types.h>
20 #include <sys/mman.h> /* for mprotect */
33 #include "toolbox/loging.h"
34 #include "toolbox/memory.h"
36 #if defined(NATIVE_THREADS)
37 pthread_mutex_t cast_mutex = PTHREAD_MUTEX_INITIALIZER;
38 pthread_mutex_t compiler_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
43 pthread_key_t tkey_threadinfo;
47 static classinfo *class_java_lang_ThreadDeath;
49 thread* currentThread = NULL;
51 thread* threadQhead[MAX_THREAD_PRIO + 1];
52 thread* threadQtail[MAX_THREAD_PRIO + 1];
54 thread* liveThreads = NULL;
55 thread* sleepThreads = NULL;
60 ctx contexts[MAXTHREADS];
62 /* Number of threads alive, also counting daemons */
65 /* Number of daemon threads alive */
68 static void firstStartThread(void);
70 void reschedule(void);
72 /* Setup default thread stack size - this can be overwritten if required */
73 int threadStackSize = THREADSTACKSIZE;
75 /* Pointer to the stack of the last killed thread. The free is delayed. */
76 void *stack_to_be_freed = 0;
78 static thread* startDaemon(void* func, char* nm, int stackSize);
81 * Allocate the stack for a thread
84 allocThreadStack (thread *tid, int size)
86 int pageSize = getpagesize();
87 unsigned long pageBegin;
89 assert(stack_to_be_freed == 0);
91 CONTEXT(tid).stackMem = GCNEW(u1, size + 4 * pageSize);
92 assert(CONTEXT(tid).stackMem != 0);
93 CONTEXT(tid).stackEnd = CONTEXT(tid).stackMem + size + 2 * pageSize;
95 pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
96 pageBegin = pageBegin - pageBegin % pageSize;
98 CONTEXT(tid).stackBase = (u1*)pageBegin + pageSize;
102 * Mark the stack for a thread to be freed. We cannot free the stack
103 * immediately because it is still in use!
106 freeThreadStack (thread *tid)
108 if (!(CONTEXT(tid).flags & THREAD_FLAGS_NOSTACKALLOC))
110 int pageSize = getpagesize();
111 unsigned long pageBegin;
113 pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
114 pageBegin = pageBegin - pageBegin % pageSize;
116 assert(stack_to_be_freed == 0);
118 stack_to_be_freed = CONTEXT(tid).stackMem;
120 CONTEXT(tid).stackMem = 0;
121 CONTEXT(tid).stackBase = 0;
122 CONTEXT(tid).stackEnd = 0;
126 * Initialize threads.
129 initThreads(u1 *stackbottom)
131 #if defined(NATIVE_THREADS) && !defined(HAVE___THREAD)
132 pthread_key_create(&tkey_threadinfo, NULL);
135 thread *the_main_thread;
137 char mainname[] = "main";
138 /*int len = strlen(mainname);*/
140 signal(SIGPIPE, SIG_IGN);
144 for (i = 0; i < MAXTHREADS; ++i) {
145 contexts[i].free = true;
146 contexts[i].thread = NULL;
149 /* Allocate a thread to be the main thread */
150 liveThreads = the_main_thread = (thread*)builtin_new(loader_load_sysclass(NULL,utf_new_char("java/lang/Thread")));
151 assert(the_main_thread != 0);
153 the_main_thread->PrivateInfo = 1;
154 CONTEXT(the_main_thread).free = false;
160 m = class_fetchmethod(
161 class_java_lang_String,
162 utf_new_char ("toCharArray"),
163 utf_new_char ("()[C")
165 printf("DEADCODE LIVES ?????????\n");fflush(stdout);
166 the_main_thread->name = asm_calljavafunction (m, javastring_new(utf_new_char("main")), 0, 0, 0);
169 the_main_thread->name=javastring_new(utf_new_char(mainname));
170 /* the_main_thread->name = builtin_newarray_char(len);
171 { u2 *d = the_main_thread->name->data;
172 for (i=0; i<len; i++)
175 the_main_thread->priority = NORM_THREAD_PRIO;
176 CONTEXT(the_main_thread).priority = (u1)the_main_thread->priority;
177 CONTEXT(the_main_thread).texceptionptr = 0;
178 the_main_thread->next = 0;
179 CONTEXT(the_main_thread).status = THREAD_SUSPENDED;
180 CONTEXT(the_main_thread).stackBase = CONTEXT(the_main_thread).stackEnd = stackbottom;
181 THREADINFO(&CONTEXT(the_main_thread));
183 DBG( printf("main thread %p base %p end %p\n",
185 CONTEXT(the_main_thread).stackBase,
186 CONTEXT(the_main_thread).stackEnd); );
188 CONTEXT(the_main_thread).flags = THREAD_FLAGS_NOSTACKALLOC;
189 CONTEXT(the_main_thread).nextlive = 0;
190 CONTEXT(the_main_thread).thread = the_main_thread;
191 /*the_main_thread->single_step = 0;*/
192 the_main_thread->daemon = 0;
193 /*the_main_thread->stillborn = 0;*/
194 /*the_main_thread->target = 0;*/
196 the_main_thread->contextClassLoader = 0;
197 /*the_main_thread->inheritedAccessControlContext = 0;*/
198 /*the_main_thread->values = 0;*/
200 /* Allocate and init ThreadGroup */
201 the_main_thread->group = (threadGroup*)native_new_and_init(loader_load(utf_new_char("java/lang/ThreadGroup")));
202 assert(the_main_thread->group != 0);
206 /* Load exception classes */
207 loader_load_sysclass(&class_java_lang_ThreadDeath,
208 utf_new_char("java/lang/ThreadDeath"));
210 DBG( fprintf(stderr, "finishing initThreads\n"); );
212 mainThread = currentThread = the_main_thread;
214 /* Add thread into runQ */
215 iresumeThread(mainThread);
217 assert(blockInts == 0);
221 * Start a new thread running.
224 startThread (thread* tid)
228 /* Allocate a stack context */
229 for (i = 0; i < MAXTHREADS; ++i)
230 if (contexts[i].free)
234 panic("Too many threads");
236 assert(tid->priority >= MIN_THREAD_PRIO && tid->priority <= MAX_THREAD_PRIO);
238 tid->PrivateInfo = i + 1;
239 CONTEXT(tid).free = false;
240 CONTEXT(tid).thread = tid;
241 CONTEXT(tid).nextlive = liveThreads;
243 allocThreadStack(tid, threadStackSize);
244 CONTEXT(tid).usedStackTop = CONTEXT(tid).stackBase;
245 CONTEXT(tid).flags = THREAD_FLAGS_GENERAL;
246 CONTEXT(tid).status = THREAD_SUSPENDED;
247 CONTEXT(tid).priority = (u1)tid->priority;
248 CONTEXT(tid).texceptionptr = 0;
250 /* Construct the initial restore point. */
251 THREADINIT((&CONTEXT(tid)), firstStartThread);
253 DBG( printf("new thread %p base %p end %p\n",
254 tid, CONTEXT(tid).stackBase,
255 CONTEXT(tid).stackEnd); );
261 /* Add thread into runQ */
266 * Start a daemon thread.
269 startDaemon(void* func, char* nm, int stackSize)
274 DBG( printf("startDaemon %s\n", nm); );
276 tid = (thread*)builtin_new(loader_load_sysclass(NULL,utf_new_char("java/lang/Thread")));
279 for (i = 0; i < MAXTHREADS; ++i)
280 if (contexts[i].free)
283 panic("Too many threads");
285 tid->PrivateInfo = i + 1;
286 CONTEXT(tid).free = false;
287 tid->name = 0; /* for the moment */
288 tid->priority = MAX_THREAD_PRIO;
289 CONTEXT(tid).priority = (u1)tid->priority;
291 CONTEXT(tid).status = THREAD_SUSPENDED;
293 allocThreadStack(tid, stackSize);
294 /*tid->single_step = 0;*/
296 /*tid->stillborn = 0;*/
300 /* Construct the initial restore point. */
301 THREADINIT((&CONTEXT(tid)), func);
310 * All threads start here.
313 firstStartThread(void)
317 DBG( printf("firstStartThread %p\n", currentThread); );
319 if (stack_to_be_freed != 0) {
320 stack_to_be_freed = 0;
323 /* Every thread starts with the interrupts off */
325 assert(blockInts == 0);
327 /* Find the run()V method and call it */
328 method = class_findmethod(currentThread->header.vftbl->class,
329 utf_new_char("run"), utf_new_char("()V"));
331 panic("Cannot find method \'void run ()\'");
333 asm_calljavafunction(method, currentThread, NULL, NULL, NULL);
336 utf_display((*exceptionptr)->vftbl->class->name);
341 assert("Thread returned from killThread" == 0);
345 * Resume a thread running.
346 * This routine has to be called only from locations which ensure
347 * run / block queue consistency. There is no check for illegal resume
348 * conditions (like explicitly resuming an IO blocked thread). There also
349 * is no update of any blocking queue. Both has to be done by the caller
352 iresumeThread(thread* tid)
354 DBG( printf("resumeThread %p\n", tid); );
358 if (CONTEXT(tid).status != THREAD_RUNNING)
360 CONTEXT(tid).status = THREAD_RUNNING;
362 DBG( fprintf(stderr, "prio is %d\n", CONTEXT(tid).priority); );
364 /* Place thread on the end of its queue */
365 if (threadQhead[CONTEXT(tid).priority] == 0) {
366 threadQhead[CONTEXT(tid).priority] = tid;
367 threadQtail[CONTEXT(tid).priority] = tid;
368 if (CONTEXT(tid).priority
369 > CONTEXT(currentThread).priority)
370 needReschedule = true;
374 threadQtail[CONTEXT(tid).priority]->next = tid;
375 threadQtail[CONTEXT(tid).priority] = tid;
379 SDBG( else { printf("Re-resuming %p\n", tid); } );
385 * Yield process to another thread of equal priority.
392 if (threadQhead[CONTEXT(currentThread).priority]
393 != threadQtail[CONTEXT(currentThread).priority])
395 /* Get the next thread and move me to the end */
396 threadQhead[CONTEXT(currentThread).priority] = currentThread->next;
397 threadQtail[CONTEXT(currentThread).priority]->next = currentThread;
398 threadQtail[CONTEXT(currentThread).priority] = currentThread;
399 currentThread->next = 0;
400 needReschedule = true;
407 * Explicit request by user to resume a thread
408 * The definition says that it is just legal to call this after a preceeding
409 * suspend (which got through). If the thread was blocked for some other
410 * reason (either sleep or IO or a muxSem), we simply can't do it
411 * We use a new thread flag THREAD_FLAGS_USER_SUSPEND for this purpose
412 * (which is set by suspendThread(.))
415 resumeThread (thread* tid)
417 if ((CONTEXT(tid).flags & THREAD_FLAGS_USER_SUSPEND) != 0)
420 CONTEXT(tid).flags &= ~THREAD_FLAGS_USER_SUSPEND;
428 * This is an explicit user request to suspend the thread - the counterpart
429 * for resumeThreadRequest(.). It is JUST called by the java method
431 * What makes it distinct is the fact that the suspended thread is not contained
432 * in any block queue. Without a special flag (indicating the user suspend), we
433 * can't check s suspended thread for this condition afterwards (which is
434 * required by resumeThreadRequest()). The new thread flag
435 * THREAD_FLAGS_USER_SUSPEND is used for this purpose.
438 suspendThread(thread* tid)
444 if (CONTEXT(tid).status != THREAD_SUSPENDED)
446 CONTEXT(tid).status = THREAD_SUSPENDED;
449 * This is used to indicate the explicit suspend condition
450 * required by resumeThreadRequest()
452 CONTEXT(tid).flags |= THREAD_FLAGS_USER_SUSPEND;
454 for (ntid = &threadQhead[CONTEXT(tid).priority];
456 ntid = &(*ntid)->next)
462 if (tid == currentThread)
470 SDBG( else { printf("Re-suspending %p\n", tid); } );
476 * Suspend a thread on a queue.
479 suspendOnQThread(thread* tid, thread** queue)
483 DBG( printf("suspendOnQThread %p %p\n", tid, queue); );
485 assert(blockInts > 0);
487 if (CONTEXT(tid).status != THREAD_SUSPENDED)
489 CONTEXT(tid).status = THREAD_SUSPENDED;
491 for (ntid = &threadQhead[CONTEXT(tid).priority];
493 ntid = &(*ntid)->next)
498 /* Insert onto head of lock wait Q */
501 if (tid == currentThread)
503 DBG( fprintf(stderr, "suspending %p (cur=%p) with prio %d\n",
504 tid, currentThread, CONTEXT(tid).priority); );
511 SDBG( else { printf("Re-suspending %p on %p\n", tid, *queue); } );
518 killThread(thread* tid)
524 /* A null tid means the current thread */
530 DBG( printf("killThread %p\n", tid); );
532 if (CONTEXT(tid).status != THREAD_DEAD)
534 /* Get thread off runq (if it needs it) */
535 if (CONTEXT(tid).status == THREAD_RUNNING)
537 for (ntid = &threadQhead[CONTEXT(tid).priority];
539 ntid = &(*ntid)->next)
549 CONTEXT(tid).status = THREAD_DEAD;
555 /* If we only have daemons left, then everyone is dead. */
556 if (talive == tdaemon) {
557 /* atexit functions get called to clean things up */
562 /* Notify on the object just in case anyone is waiting */
563 internal_lock_mutex_for_object(&tid->header);
564 internal_broadcast_cond_for_object(&tid->header);
565 internal_unlock_mutex_for_object(&tid->header);
567 /* Remove thread from live list to it can be garbaged */
568 for (ntid = &liveThreads;
570 ntid = &(CONTEXT((*ntid)).nextlive))
574 (*ntid) = CONTEXT(tid).nextlive;
580 freeThreadStack(tid);
583 if (tid != mainThread) {
584 CONTEXT(tid).free = true;
585 CONTEXT(tid).thread = NULL;
588 /* Run something else */
589 needReschedule = true;
595 * Change thread priority.
598 setPriorityThread(thread* tid, int prio)
602 assert(prio >= MIN_THREAD_PRIO && prio <= MAX_THREAD_PRIO);
604 if (tid->PrivateInfo == 0) {
605 tid->priority = prio;
609 if (CONTEXT(tid).status == THREAD_SUSPENDED) {
610 CONTEXT(tid).priority = (u8)prio;
616 /* Remove from current thread list */
617 for (ntid = &threadQhead[CONTEXT(tid).priority]; *ntid != 0; ntid = &(*ntid)->next) {
624 /* Insert onto a new one */
625 tid->priority = prio;
626 CONTEXT(tid).priority = (u8)tid->priority;
627 if (threadQhead[prio] == 0) {
628 threadQhead[prio] = tid;
629 threadQtail[prio] = tid;
630 if (prio > CONTEXT(currentThread).priority) {
631 needReschedule = true;
635 threadQtail[prio]->next = tid;
636 threadQtail[prio] = tid;
644 * Get the current time in milliseconds since 1970-01-01.
652 gettimeofday(&tv, 0);
656 time += tv.tv_usec / 1000;
662 * Put a thread to sleep.
665 sleepThread (s8 time)
669 /* Sleep for no time */
676 /* Get absolute time */
677 CONTEXT(currentThread).time = time + currentTime();
679 /* Find place in alarm list */
680 for (tidp = &sleepThreads; (*tidp) != 0; tidp = &(*tidp)->next)
682 if (CONTEXT(*tidp).time > CONTEXT(currentThread).time)
686 /* Suspend thread on it */
687 suspendOnQThread(currentThread, tidp);
693 * Is this thread alive?
696 aliveThread(thread* tid)
698 if (tid->PrivateInfo != 0 && CONTEXT(tid).status != THREAD_DEAD)
705 * Reschedule the thread.
706 * Called whenever a change in the running thread is required.
716 /* A reschedule in a non-blocked context is half way to hell */
717 assert(blockInts > 0);
720 /* Check events - we may release a high priority thread */
721 /* Just check IO, no need for a reschedule call by checkEvents() */
722 needReschedule = false;
727 for (i = MAX_THREAD_PRIO; i >= MIN_THREAD_PRIO; i--)
729 if (threadQhead[i] != 0)
731 DBG( fprintf(stderr, "found thread %p in head %d\n", threadQhead[i], i); );
733 if (threadQhead[i] != currentThread)
735 /* USEDSTACKTOP((CONTEXT(currentThread).usedStackTop)); */
737 lastThread = currentThread;
738 currentThread = threadQhead[i];
740 CONTEXT(currentThread).texceptionptr = *exceptionptr;
742 DBG( fprintf(stderr, "thread switch from: %p to: %p\n", lastThread, currentThread); );
743 THREADSWITCH((&CONTEXT(currentThread)),
744 (&CONTEXT(lastThread)));
747 *exceptionptr = CONTEXT(currentThread).texceptionptr;
749 if (stack_to_be_freed != 0) {
750 stack_to_be_freed = 0;
753 /* Alarm signal may be blocked - if so
757 if (alarmBlocked == true) {
758 alarmBlocked = false;
760 sigaddset(&nsig, SIGALRM);
761 sigprocmask(SIG_UNBLOCK, &nsig, 0);
765 /* I might be dying */
766 if ((CONTEXT(lastThread).flags & THREAD_FLAGS_KILLED)
769 CONTEXT(lastThread).flags &= ~THREAD_FLAGS_KILLED;
770 *exceptionptr = native_new_and_init(class_java_lang_ThreadDeath);
773 /* Now we kill the schedule and turn ints
775 needReschedule = false;
779 /* Nothing to run - wait for external event */
780 DBG( fprintf(stderr, "nothing more to do\n"); );