java.net implemented.
[cacao.git] / threads / thread.c
1 /* -*- mode: c; tab-width: 4; c-basic-offset: 4 -*- */
2 /*
3  * thread.c
4  * Thread support.
5  *
6  * Copyright (c) 1996 T. J. Wilkinson & Associates, London, UK.
7  *
8  * See the file "license.terms" for information on usage and redistribution
9  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10  *
11  * Written by Tim Wilkinson <tim@tjwassoc.demon.co.uk>, 1996.
12  */
13
14 #include "config.h"
15
16 #include <assert.h>
17
18 #include <sys/types.h>
19 #include <sys/mman.h>                   /* for mprotect */
20 #include <unistd.h>
21 #include <signal.h>
22 #include <sys/time.h>
23
24 #include "thread.h"
25 #include "locks.h"
26 #include "defines.h"
27 #include "threads.h"
28
29 #include "tables.h"
30 #include "native.h"
31 #include "loader.h"
32 #include "builtin.h"
33 #include "asmpart.h"
34
35 static classinfo *class_java_lang_ThreadDeath;
36
37 #if 1
38 #define DBG(s)
39 #define SDBG(s)
40 #else
41 #define DBG(s)                 s
42 #define SDBG(s)                s
43 #endif
44
45 #if defined(USE_INTERNAL_THREADS)
46
47 thread* currentThread = NULL;
48 thread* mainThread;
49 thread* threadQhead[MAX_THREAD_PRIO + 1];
50 thread* threadQtail[MAX_THREAD_PRIO + 1];
51
52 thread* liveThreads = NULL;
53 thread* sleepThreads = NULL;
54
55 int blockInts;
56 bool needReschedule;
57
58 ctx contexts[MAXTHREADS];
59
60 /* Number of threads alive, also counting daemons */
61 static int talive;
62
63 /* Number of daemon threads alive */
64 static int tdaemon;
65
66 static void firstStartThread(void);
67
68 void reschedule(void);
69
70 /* Setup default thread stack size - this can be overwritten if required */
71 int threadStackSize = THREADSTACKSIZE;
72
73 /* Pointer to the stack of the last killed thread. The free is delayed. */
74 void *stack_to_be_freed = 0;
75
76 static thread* startDaemon(void* func, char* nm, int stackSize);
77
78 /*
79  * Allocate the stack for a thread
80  */
81 void
82 allocThreadStack (thread *tid, int size)
83 {
84     int pageSize = getpagesize(),
85                 result;
86     unsigned long pageBegin;
87
88         assert(stack_to_be_freed == 0);
89
90     CONTEXT(tid).stackMem = malloc(size + 4 * pageSize);
91     assert(CONTEXT(tid).stackMem != 0);
92     CONTEXT(tid).stackEnd = CONTEXT(tid).stackMem + size + 2 * pageSize;
93     
94     pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
95     pageBegin = pageBegin - pageBegin % pageSize;
96
97     result = mprotect((void*)pageBegin, pageSize, PROT_NONE);
98     assert(result == 0);
99
100     CONTEXT(tid).stackBase = (u1*)pageBegin + pageSize;
101 }
102
103 /*
104  * Mark the stack for a thread to be freed. We cannot free the stack
105  * immediately because it is still in use!
106  */
107 void
108 freeThreadStack (thread *tid)
109 {
110     if (!(CONTEXT(tid).flags & THREAD_FLAGS_NOSTACKALLOC))
111     {
112                 int pageSize = getpagesize(),
113                         result;
114                 unsigned long pageBegin;
115
116                 pageBegin = (unsigned long)(CONTEXT(tid).stackMem) + pageSize - 1;
117                 pageBegin = pageBegin - pageBegin % pageSize;
118
119                 result = mprotect((void*)pageBegin, pageSize,
120                                                   PROT_READ | PROT_WRITE | PROT_EXEC);
121                 assert(result == 0);
122
123                 assert(stack_to_be_freed == 0);
124
125                 stack_to_be_freed = CONTEXT(tid).stackMem;
126     }
127     CONTEXT(tid).stackMem = 0;
128     CONTEXT(tid).stackBase = 0;
129     CONTEXT(tid).stackEnd = 0;
130 }
131
132 /*
133  * Initialize threads.
134  */
135 void
136 initThreads(u1 *stackbottom)
137 {
138         thread *the_main_thread;
139     int i;
140
141         signal(SIGPIPE, SIG_IGN);
142
143     initLocks();
144
145     for (i = 0; i < MAXTHREADS; ++i) {
146                 contexts[i].free = true;
147                 contexts[i].thread = NULL;
148                 heap_addreference((void**)&contexts[i].thread);
149         }
150
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); */
155     
156     the_main_thread->PrivateInfo = 1;
157     CONTEXT(the_main_thread).free = false;
158
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));
167
168     DBG( printf("main thread %p base %p end %p\n", 
169                                 the_main_thread,
170                                 CONTEXT(the_main_thread).stackBase,
171                                 CONTEXT(the_main_thread).stackEnd); );
172
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;
180
181         the_main_thread->contextClassLoader = 0;
182         the_main_thread->inheritedAccessControlContext = 0;
183         the_main_thread->values = 0;
184
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);
188
189         talive++;
190
191         /* Load exception classes */
192         class_java_lang_ThreadDeath = loader_load(utf_new_char("java/lang/ThreadDeath"));
193
194         DBG( fprintf(stderr, "finishing initThreads\n"); );
195
196     mainThread = currentThread = the_main_thread;
197
198         /* heap_addreference((void**)&mainThread); */
199
200         /* Add thread into runQ */
201         iresumeThread(mainThread);
202
203         assert(blockInts == 0);
204 }
205
206 /*
207  * Start a new thread running.
208  */
209 void
210 startThread (thread* tid)
211 {
212     int i;
213
214     /* Allocate a stack context */
215     for (i = 0; i < MAXTHREADS; ++i)
216                 if (contexts[i].free)
217                         break;
218
219     if (i == MAXTHREADS)
220                 panic("Too many threads");
221
222         assert(tid->priority >= MIN_THREAD_PRIO && tid->priority <= MAX_THREAD_PRIO);
223
224     tid->PrivateInfo = i + 1;
225     CONTEXT(tid).free = false;
226         CONTEXT(tid).thread = tid;
227     CONTEXT(tid).nextlive = liveThreads;
228     liveThreads = tid;
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;
235
236     /* Construct the initial restore point. */
237     THREADINIT((&CONTEXT(tid)), firstStartThread);
238
239     DBG( printf("new thread %p base %p end %p\n",
240                                 tid, CONTEXT(tid).stackBase,
241                                 CONTEXT(tid).stackEnd); );
242
243         talive++;
244         if (tid->daemon)
245                 tdaemon++;
246
247         /* Add thread into runQ */
248         iresumeThread(tid);
249 }
250
251 /*
252  * Start a daemon thread.
253  */
254 static thread*
255 startDaemon(void* func, char* nm, int stackSize)
256 {
257     thread* tid;
258     int i;
259
260     DBG( printf("startDaemon %s\n", nm); );
261
262         tid = (thread*)builtin_new(loader_load(utf_new_char("java/lang/Thread")));
263         assert(tid != 0);
264
265         for (i = 0; i < MAXTHREADS; ++i)
266                 if (contexts[i].free)
267                         break;
268         if (i == MAXTHREADS)
269                 panic("Too many threads");
270
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;
276         tid->next = 0;
277         CONTEXT(tid).status = THREAD_SUSPENDED;
278
279         allocThreadStack(tid, stackSize);
280         tid->single_step = 0;
281         tid->daemon = 1;
282         tid->stillborn = 0;
283         tid->target = 0;
284         tid->group = 0;
285
286         /* Construct the initial restore point. */
287         THREADINIT((&CONTEXT(tid)), func);
288
289         talive++;
290         tdaemon++;
291
292         return tid;
293 }
294
295 /*
296  * All threads start here.
297  */
298 static void
299 firstStartThread(void)
300 {
301     methodinfo *method;
302
303     DBG( printf("firstStartThread %p\n", currentThread); );
304
305         /* Every thread starts with the interrupts off */
306         intsRestore();
307         assert(blockInts == 0);
308
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"));
312         if (method == 0)
313                 panic("Cannot find method \'void run ()\'");
314         asm_calljavamethod(method, currentThread, NULL, NULL, NULL);
315
316         killThread(0);
317         assert("Thread returned from killThread" == 0);
318 }
319
320 /*
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
326  */
327 void
328 iresumeThread(thread* tid)
329 {
330     DBG( printf("resumeThread %p\n", tid); );
331
332         intsDisable();
333
334         if (CONTEXT(tid).status != THREAD_RUNNING)
335         {
336                 CONTEXT(tid).status = THREAD_RUNNING;
337
338                 DBG( fprintf(stderr, "prio is %d\n", CONTEXT(tid).priority); );
339
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;
347                 }
348                 else
349                 {
350                         threadQtail[CONTEXT(tid).priority]->next = tid;
351                         threadQtail[CONTEXT(tid).priority] = tid;
352                 }
353                 tid->next = 0;
354         }
355         SDBG( else { printf("Re-resuming %p\n", tid); } );
356
357         intsRestore();
358 }
359
360 /*
361  * Yield process to another thread of equal priority.
362  */
363 void
364 yieldThread()
365 {
366     intsDisable();
367
368     if (threadQhead[CONTEXT(currentThread).priority]
369                 != threadQtail[CONTEXT(currentThread).priority])
370     {
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;
377     }
378
379     intsRestore();
380 }
381
382 /*
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(.))
389  */
390 void
391 resumeThread (thread* tid)
392 {
393     if ((CONTEXT(tid).flags & THREAD_FLAGS_USER_SUSPEND) != 0)
394     {
395                 intsDisable();
396                 CONTEXT(tid).flags &= ~THREAD_FLAGS_USER_SUSPEND;
397                 iresumeThread(tid);
398                 intsRestore();
399     }
400 }
401
402 /*
403  * Suspend a thread.
404  * This is an explicit user request to suspend the thread - the counterpart
405  * for resumeThreadRequest(.). It is JUST called by the java method
406  * Thread.suspend()
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.
412  */
413 void
414 suspendThread(thread* tid)
415 {
416     thread** ntid;
417
418     intsDisable();
419
420     if (CONTEXT(tid).status != THREAD_SUSPENDED)
421     {
422                 CONTEXT(tid).status = THREAD_SUSPENDED;
423                 
424                 /*
425                  * This is used to indicate the explicit suspend condition
426                  * required by resumeThreadRequest()
427                  */
428                 CONTEXT(tid).flags |= THREAD_FLAGS_USER_SUSPEND;
429
430                 for (ntid = &threadQhead[CONTEXT(tid).priority];
431                          *ntid != 0;
432                          ntid = &(*ntid)->next)
433                 {
434                         if (*ntid == tid)
435                         {
436                                 *ntid = tid->next;
437                                 tid->next = 0;
438                                 if (tid == currentThread)
439                                 {
440                                         reschedule();
441                                 }
442                                 break;
443                         }
444                 }
445     }
446         SDBG( else { printf("Re-suspending %p\n", tid); } );
447
448         intsRestore();
449 }
450
451 /*
452  * Suspend a thread on a queue.
453  */
454 void
455 suspendOnQThread(thread* tid, thread** queue)
456 {
457     thread** ntid;
458
459         DBG( printf("suspendOnQThread %p %p\n", tid, queue); );
460
461         assert(blockInts == 1);
462
463         if (CONTEXT(tid).status != THREAD_SUSPENDED)
464         {
465                 CONTEXT(tid).status = THREAD_SUSPENDED;
466
467                 for (ntid = &threadQhead[CONTEXT(tid).priority];
468                          *ntid != 0;
469                          ntid = &(*ntid)->next)
470                 {
471                         if (*ntid == tid)
472                         {
473                                 *ntid = tid->next;
474                                 /* Insert onto head of lock wait Q */
475                                 tid->next = *queue;
476                                 *queue = tid;
477                                 if (tid == currentThread)
478                                 {
479                                         DBG( fprintf(stderr, "suspending %p (cur=%p) with prio %d\n",
480                                                                  tid, currentThread, CONTEXT(tid).priority); );
481                                         reschedule();
482                                 }
483                                 break;
484                         }
485                 }
486         }
487         SDBG( else { printf("Re-suspending %p on %p\n", tid, *queue); } );
488 }
489
490 /*
491  * Kill thread.
492  */
493 void
494 killThread(thread* tid)
495 {
496     thread** ntid;
497
498     intsDisable();
499
500     /* A null tid means the current thread */
501     if (tid == 0)
502     {
503                 tid = currentThread;
504     }
505
506         DBG( printf("killThread %p\n", tid); );
507
508         if (CONTEXT(tid).status != THREAD_DEAD)
509         {
510                 /* Get thread off runq (if it needs it) */
511                 if (CONTEXT(tid).status == THREAD_RUNNING)
512                 {
513                         for (ntid = &threadQhead[CONTEXT(tid).priority];
514                                  *ntid != 0;
515                                  ntid = &(*ntid)->next)
516                         {
517                                 if (*ntid == tid)
518                                 {
519                                         *ntid = tid->next;
520                                         break;
521                                 }
522                         }
523                 }
524
525                 CONTEXT(tid).status = THREAD_DEAD;
526                 talive--;
527                 if (tid->daemon) {
528                         tdaemon--;
529                 }
530
531                 /* If we only have daemons left, then everyone is dead. */
532                 if (talive == tdaemon) {
533                         /* atexit functions get called to clean things up */
534                         intsRestore();
535                         exit(0);
536                 }
537
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);
542
543                 /* Remove thread from live list to it can be garbaged */
544                 for (ntid = &liveThreads;
545                          *ntid != 0;
546                          ntid = &(CONTEXT((*ntid)).nextlive))
547                 {
548                         if (tid == (*ntid))
549                         {
550                                 (*ntid) = CONTEXT(tid).nextlive;
551                                 break;
552                         }
553                 }
554
555                 /* Free stack */
556                 freeThreadStack(tid);
557
558                 /* free context */
559                 if (tid != mainThread) {
560                         CONTEXT(tid).free = true;
561                         CONTEXT(tid).thread = NULL;
562                 }
563
564                 /* Run something else */
565                 needReschedule = true;
566         }
567         intsRestore();
568 }
569
570 /*
571  * Change thread priority.
572  */
573 void
574 setPriorityThread(thread* tid, int prio)
575 {
576     thread** ntid;
577
578         assert(prio >= MIN_THREAD_PRIO && prio <= MAX_THREAD_PRIO);
579
580     if (tid->PrivateInfo == 0) {
581                 tid->priority = prio;
582                 return;
583     }
584
585     if (CONTEXT(tid).status == THREAD_SUSPENDED) {
586                 CONTEXT(tid).priority = (u8)prio;
587                 return;
588     }
589
590     intsDisable();
591
592     /* Remove from current thread list */
593     for (ntid = &threadQhead[CONTEXT(tid).priority]; *ntid != 0; ntid = &(*ntid)->next) {
594                 if (*ntid == tid) {
595                         *ntid = tid->next;
596                         break;
597                 }
598     }
599
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;
608                 }
609     }
610     else {
611                 threadQtail[prio]->next = tid;
612                 threadQtail[prio] = tid;
613     }
614     tid->next = 0;
615
616     intsRestore();
617 }
618
619 /*
620  * Get the current time in milliseconds since 1970-01-01.
621  */
622 s8
623 currentTime (void)
624 {
625         struct timeval tv;
626         s8 time;
627
628         gettimeofday(&tv, 0);
629
630         time = tv.tv_sec;
631         time *= 1000;
632         time += tv.tv_usec / 1000;
633
634         return time;
635 }
636
637 /*
638  * Put a thread to sleep.
639  */
640 void
641 sleepThread (s8 time)
642 {
643     thread** tidp;
644
645     /* Sleep for no time */
646     if (time <= 0) {
647                 return;
648     }
649     
650     intsDisable();
651
652     /* Get absolute time */
653     CONTEXT(currentThread).time = time + currentTime();
654
655     /* Find place in alarm list */
656     for (tidp = &sleepThreads; (*tidp) != 0; tidp = &(*tidp)->next)
657         {
658                 if (CONTEXT(*tidp).time > CONTEXT(currentThread).time)
659                         break;
660     }
661
662     /* Suspend thread on it */
663     suspendOnQThread(currentThread, tidp);
664     
665     intsRestore();
666 }
667
668 /*
669  * Is this thread alive?
670  */
671 bool
672 aliveThread(thread* tid)
673 {
674     if (tid->PrivateInfo != 0 && CONTEXT(tid).status != THREAD_DEAD)
675                 return (true);
676     else
677                 return (false);
678 }
679
680 /*
681  * Reschedule the thread.
682  * Called whenever a change in the running thread is required.
683  */
684 void
685 reschedule(void)
686 {
687     int i;
688     thread* lastThread;
689     int b;
690     /*    sigset_t nsig; */
691
692     /* A reschedule in a non-blocked context is half way to hell */
693     assert(blockInts > 0);
694     b = blockInts;
695     
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;
699     checkEvents(false);
700
701     for (;;)
702     {
703                 for (i = MAX_THREAD_PRIO; i >= MIN_THREAD_PRIO; i--)
704                 {
705                         if (threadQhead[i] != 0)
706                         {
707                                 DBG( fprintf(stderr, "found thread %p in head %d\n", threadQhead[i], i); );
708
709                                 if (threadQhead[i] != currentThread)
710                                 {
711                                         /* USEDSTACKTOP((CONTEXT(currentThread).usedStackTop)); */
712
713                                         lastThread = currentThread;
714                                         currentThread = threadQhead[i];
715
716                                         CONTEXT(currentThread).exceptionptr = exceptionptr;
717
718                                         THREADSWITCH((&CONTEXT(currentThread)),
719                                                                  (&CONTEXT(lastThread)));
720                                         blockInts = b;
721
722                                         exceptionptr = CONTEXT(currentThread).exceptionptr;
723
724                                         if (stack_to_be_freed != 0)
725                                         {
726                                                 free(stack_to_be_freed);
727                                                 stack_to_be_freed = 0;
728                                         }
729
730                                         /* Alarm signal may be blocked - if so
731                                          * unblock it.
732                                          */
733                                         /*
734                                           if (alarmBlocked == true) {
735                                           alarmBlocked = false;
736                                           sigemptyset(&nsig);
737                                           sigaddset(&nsig, SIGALRM);
738                                           sigprocmask(SIG_UNBLOCK, &nsig, 0);
739                                           }
740                                         */
741
742                                         /* I might be dying */
743                                         if ((CONTEXT(lastThread).flags & THREAD_FLAGS_KILLED)
744                                                 != 0)
745                                         {
746                                                 CONTEXT(lastThread).flags &= ~THREAD_FLAGS_KILLED;
747                                                 exceptionptr = native_new_and_init(class_java_lang_ThreadDeath);
748                                         }
749                                 }
750                                 /* Now we kill the schedule and turn ints
751                                    back on */
752                                 needReschedule = false;
753                                 return;
754                         }
755                 }
756                 /* Nothing to run - wait for external event */
757                 DBG( fprintf(stderr, "nothing more to do\n"); );
758                 checkEvents(true);
759     }
760 }
761
762 #endif