Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


(no commit message)
[palacios.git] / palacios / src / geekos / kthread.c
1 /*
2  * Kernel threads
3  * Copyright (c) 2001,2003 David H. Hovemeyer <daveho@cs.umd.edu>
4  * $Revision: 1.1.1.1 $
5  * 
6  * This is free software.  You are permitted to use,
7  * redistribute, and modify it as specified in the file "COPYING".
8  */
9
10 #include <geekos/kassert.h>
11 #include <geekos/defs.h>
12 #include <geekos/screen.h>
13 #include <geekos/int.h>
14 #include <geekos/mem.h>
15 #include <geekos/symbol.h>
16 #include <geekos/string.h>
17 #include <geekos/kthread.h>
18 #include <geekos/malloc.h>
19 #include <geekos/serial.h>
20
21 /* ----------------------------------------------------------------------
22  * Private data
23  * ---------------------------------------------------------------------- */
24
25 /*
26  * List of all threads in the system.
27  */
28 static struct All_Thread_List s_allThreadList;
29
30 /*
31  * Queue of runnable threads.
32  */
33 static struct Thread_Queue s_runQueue;
34
35 /*
36  * Current thread.
37  */
38 struct Kernel_Thread* g_currentThread;
39
40 /*
41  * Boolean flag indicating that we need to choose a new runnable thread.
42  * It is checked by the interrupt return code (Handle_Interrupt,
43  * in lowlevel.asm) before returning from an interrupt.
44  */
45 int g_needReschedule;
46
47 /*
48  * Boolean flag indicating that preemption is disabled.
49  * When set, external interrupts (such as the timer tick)
50  * will not cause a new thread to be selected.
51  */
52 volatile int g_preemptionDisabled;
53
54 /*
55  * Queue of finished threads needing disposal,
56  * and a wait queue used for communication between exited threads
57  * and the reaper thread.
58  */
59 static struct Thread_Queue s_graveyardQueue;
60 static struct Thread_Queue s_reaperWaitQueue;
61
62 /*
63  * Counter for keys that access thread-local data, and an array
64  * of destructors for freeing that data when the thread dies.  This is
65  * based on POSIX threads' thread-specific data functionality.
66  */
67 static unsigned int s_tlocalKeyCounter = 0;
68 static tlocal_destructor_t s_tlocalDestructors[MAX_TLOCAL_KEYS];
69
70 /* ----------------------------------------------------------------------
71  * Private functions
72  * ---------------------------------------------------------------------- */
73
74 /*
75  * Initialize a new Kernel_Thread.
76  */
77 static void Init_Thread(struct Kernel_Thread* kthread, void* stackPage,
78         int priority, bool detached)
79 {
80     static int nextFreePid = 1;
81
82     struct Kernel_Thread* owner = detached ? (struct Kernel_Thread*)0 : g_currentThread;
83
84     memset(kthread, '\0', sizeof(*kthread));
85     kthread->stackPage = stackPage;
86     kthread->esp = ((ulong_t) kthread->stackPage) + PAGE_SIZE;
87     kthread->numTicks = 0;
88     kthread->priority = priority;
89     kthread->userContext = 0;
90     kthread->owner = owner;
91
92     /*
93      * The thread has an implicit self-reference.
94      * If the thread is not detached, then its owner
95      * also has a reference to it.
96      */
97     kthread->refCount = detached ? 1 : 2;
98
99     kthread->alive = true;
100     Clear_Thread_Queue(&kthread->joinQueue);
101     kthread->pid = nextFreePid++;
102
103 }
104
105 /*
106  * Create a new raw thread object.
107  * Returns a null pointer if there isn't enough memory.
108  */
109 static struct Kernel_Thread* Create_Thread(int priority, bool detached)
110 {
111     struct Kernel_Thread* kthread;
112     void* stackPage = 0;
113
114     /*
115      * For now, just allocate one page each for the thread context
116      * object and the thread's stack.
117      */
118     kthread = Alloc_Page();
119     if (kthread != 0)
120         stackPage = Alloc_Page();    
121
122     /* Make sure that the memory allocations succeeded. */
123     if (kthread == 0)
124         return 0;
125     if (stackPage == 0) {
126         Free_Page(kthread);
127         return 0;
128     }
129
130     /*Print("New thread @ %x, stack @ %x\n", kthread, stackPage); */
131
132     /*
133      * Initialize the stack pointer of the new thread
134      * and accounting info
135      */
136     Init_Thread(kthread, stackPage, priority, detached);
137
138     /* Add to the list of all threads in the system. */
139     Add_To_Back_Of_All_Thread_List(&s_allThreadList, kthread);
140
141     return kthread;
142 }
143
144 /*
145  * Push a dword value on the stack of given thread.
146  * We use this to set up some context for the thread before
147  * we make it runnable.
148  */
149 static __inline__ void Push(struct Kernel_Thread* kthread, ulong_t value)
150 {
151     kthread->esp -= 4;
152     *((ulong_t *) kthread->esp) = value;
153 }
154
155 /*
156  * Destroy given thread.
157  * This function should perform all cleanup needed to
158  * reclaim the resources used by a thread.
159  * Called with interrupts enabled.
160  */
161 static void Destroy_Thread(struct Kernel_Thread* kthread)
162 {
163
164     /* Dispose of the thread's memory. */
165     Disable_Interrupts();
166     Free_Page(kthread->stackPage);
167     Free_Page(kthread);
168
169     /* Remove from list of all threads */
170     Remove_From_All_Thread_List(&s_allThreadList, kthread);
171
172     Enable_Interrupts();
173
174 }
175
176 /*
177  * Hand given thread to the reaper for destruction.
178  * Must be called with interrupts disabled!
179  */
180 static void Reap_Thread(struct Kernel_Thread* kthread)
181 {
182     KASSERT(!Interrupts_Enabled());
183     Enqueue_Thread(&s_graveyardQueue, kthread);
184     Wake_Up(&s_reaperWaitQueue);
185 }
186
187 /*
188  * Called when a reference to the thread is broken.
189  */
190 static void Detach_Thread(struct Kernel_Thread* kthread)
191 {
192     KASSERT(!Interrupts_Enabled());
193     KASSERT(kthread->refCount > 0);
194
195     --kthread->refCount;
196     if (kthread->refCount == 0) {
197         Reap_Thread(kthread);
198     }
199 }
200
201 /*
202  * This function performs any needed initialization before
203  * a thread start function is executed.  Currently we just use
204  * it to enable interrupts (since Schedule() always activates
205  * a thread with interrupts disabled).
206  */
207 static void Launch_Thread(void)
208 {
209     Enable_Interrupts();
210 }
211
212 /*
213  * Push initial values for general purpose registers.
214  */
215 static void Push_General_Registers(struct Kernel_Thread* kthread)
216 {
217     /*
218      * Push initial values for saved general-purpose registers.
219      * (The actual values are not important.)
220      */
221     Push(kthread, 0);  /* eax */
222     Push(kthread, 0);  /* ebx */
223     Push(kthread, 0);  /* edx */
224     Push(kthread, 0);  /* edx */
225     Push(kthread, 0);  /* esi */
226     Push(kthread, 0);  /* edi */
227     Push(kthread, 0);  /* ebp */
228 }
229
230 /*
231  * Shutdown a kernel thread.
232  * This is called if a kernel thread exits by falling off
233  * the end of its start function.
234  */
235 static void Shutdown_Thread(void)
236 {
237     Exit(0);
238 }
239
240 /*
241  * Set up the initial context for a kernel-mode-only thread.
242  */
243 static void Setup_Kernel_Thread(
244     struct Kernel_Thread* kthread,
245     Thread_Start_Func startFunc,
246     ulong_t arg)
247 {
248     /*
249      * Push the argument to the thread start function, and the
250      * return address (the Shutdown_Thread function, so the thread will
251      * go away cleanly when the start function returns).
252      */
253     Push(kthread, arg);
254     Push(kthread, (ulong_t) &Shutdown_Thread);
255
256     /* Push the address of the start function. */
257     Push(kthread, (ulong_t) startFunc);
258
259     /*
260      * To make the thread schedulable, we need to make it look
261      * like it was suspended by an interrupt.  This means pushing
262      * an "eflags, cs, eip" sequence onto the stack,
263      * as well as int num, error code, saved registers, etc.
264      */
265
266     /*
267      * The EFLAGS register will have all bits clear.
268      * The important constraint is that we want to have the IF
269      * bit clear, so that interrupts are disabled when the
270      * thread starts.
271      */
272     Push(kthread, 0UL);  /* EFLAGS */
273
274     /*
275      * As the "return address" specifying where the new thread will
276      * start executing, use the Launch_Thread() function.
277      */
278     Push(kthread, KERNEL_CS);
279     Push(kthread, (ulong_t) &Launch_Thread);
280
281     /* Push fake error code and interrupt number. */
282     Push(kthread, 0);
283     Push(kthread, 0);
284
285     /* Push initial values for general-purpose registers. */
286     Push_General_Registers(kthread);
287
288     /*
289      * Push values for saved segment registers.
290      * Only the ds and es registers will contain valid selectors.
291      * The fs and gs registers are not used by any instruction
292      * generated by gcc.
293      */
294     Push(kthread, KERNEL_DS);  /* ds */
295     Push(kthread, KERNEL_DS);  /* es */
296     Push(kthread, 0);  /* fs */
297     Push(kthread, 0);  /* gs */
298 }
299
300
301
302 /*
303  * This is the body of the idle thread.  Its job is to preserve
304  * the invariant that a runnable thread always exists,
305  * i.e., the run queue is never empty.
306  */
307 static void Idle(ulong_t arg)
308 {
309     while (true)
310         Yield();
311 }
312
313 /*
314  * The reaper thread.  Its job is to de-allocate memory
315  * used by threads which have finished.
316  */
317 static void Reaper(ulong_t arg)
318 {
319     struct Kernel_Thread *kthread;
320
321     Disable_Interrupts();
322
323     while (true) {
324         /* See if there are any threads needing disposal. */
325         if ((kthread = s_graveyardQueue.head) == 0) {
326             /* Graveyard is empty, so wait for a thread to die. */
327             Wait(&s_reaperWaitQueue);
328         }
329         else {
330             /* Make the graveyard queue empty. */
331             Clear_Thread_Queue(&s_graveyardQueue);
332
333             /*
334              * Now we can re-enable interrupts, since we
335              * have removed all the threads needing disposal.
336              */
337             Enable_Interrupts();
338             Yield();   /* allow other threads to run? */
339
340             /* Dispose of the dead threads. */
341             while (kthread != 0) {
342                 struct Kernel_Thread* next = Get_Next_In_Thread_Queue(kthread);
343 #if 0
344                 Print("Reaper: disposing of thread @ %x, stack @ %x\n",
345                     kthread, kthread->stackPage);
346 #endif
347                 Destroy_Thread(kthread);
348                 kthread = next;
349             }
350
351             /*
352              * Disable interrupts again, since we're going to
353              * do another iteration.
354              */
355             Disable_Interrupts();
356         }
357     }
358 }
359
360 /*
361  * Find the best (highest priority) thread in given
362  * thread queue.  Returns null if queue is empty.
363  */
364 static __inline__ struct Kernel_Thread* Find_Best(struct Thread_Queue* queue)
365 {
366     /* Pick the highest priority thread */
367     struct Kernel_Thread *kthread = queue->head, *best = 0;
368     while (kthread != 0) {
369         if (best == 0 || kthread->priority > best->priority)
370             best = kthread;
371         kthread = Get_Next_In_Thread_Queue(kthread);
372     }
373     return best;
374 }
375
376 /*
377  * Acquires pointer to thread-local data from the current thread
378  * indexed by the given key.  Assumes interrupts are off.
379  */
380 static __inline__ const void** Get_Tlocal_Pointer(tlocal_key_t k) 
381 {
382     struct Kernel_Thread* current = g_currentThread;
383
384     KASSERT(k < MAX_TLOCAL_KEYS);
385
386     return &current->tlocalData[k];
387 }
388
389 /*
390  * Clean up any thread-local data upon thread exit.  Assumes
391  * this is called with interrupts disabled.  We follow the POSIX style
392  * of possibly invoking a destructor more than once, because a
393  * destructor to some thread-local data might cause other thread-local
394  * data to become alive once again.  If everything is NULL by the end
395  * of an iteration, we are done.
396  */
397 static void Tlocal_Exit(struct Kernel_Thread* curr) {
398     int i, j, called = 0;
399
400     KASSERT(!Interrupts_Enabled());
401
402     for (j = 0; j<MIN_DESTRUCTOR_ITERATIONS; j++) {
403
404         for (i = 0; i<MAX_TLOCAL_KEYS; i++) {
405
406             void *x = (void *)curr->tlocalData[i];
407             if (x != NULL && s_tlocalDestructors[i] != NULL) {
408
409                 curr->tlocalData[i] = NULL;
410                 called = 1;
411
412                 Enable_Interrupts();
413                 s_tlocalDestructors[i](x);
414                 Disable_Interrupts();
415             }
416         }
417         if (!called) break;
418     }
419 }
420
421
422 /* ----------------------------------------------------------------------
423  * Public functions
424  * ---------------------------------------------------------------------- */
425
426 void Init_Scheduler(void)
427 {
428     struct Kernel_Thread* mainThread = (struct Kernel_Thread *) KERNEL_THREAD_OBJECT;
429
430     PrintBoth("Initializing Scheduler\n");
431
432     /*
433      * Create initial kernel thread context object and stack,
434      * and make them current.
435      */
436     Init_Thread(mainThread, (void *) KERNEL_STACK, PRIORITY_NORMAL, true);
437     g_currentThread = mainThread;
438     Add_To_Back_Of_All_Thread_List(&s_allThreadList, mainThread);
439
440     /*
441      * Create the idle thread.
442      */
443     /*Print("starting idle thread\n");*/
444     Start_Kernel_Thread(Idle, 0, PRIORITY_IDLE, true);
445
446     /*
447      * Create the reaper thread.
448      */
449     /*Print("starting reaper thread\n");*/
450     Start_Kernel_Thread(Reaper, 0, PRIORITY_NORMAL, true);
451 }
452
453 /*
454  * Start a kernel-mode-only thread, using given function as its body
455  * and passing given argument as its parameter.  Returns pointer
456  * to the new thread if successful, null otherwise.
457  *
458  * startFunc - is the function to be called by the new thread
459  * arg - is a paramter to pass to the new function
460  * priority - the priority of this thread (use PRIORITY_NORMAL) for
461  *    most things
462  * detached - use false for kernel threads
463  */
464 struct Kernel_Thread* Start_Kernel_Thread(
465     Thread_Start_Func startFunc,
466     ulong_t arg,
467     int priority,
468     bool detached
469 )
470 {
471     struct Kernel_Thread* kthread = Create_Thread(priority, detached);
472     if (kthread != 0) {
473         /*
474          * Create the initial context for the thread to make
475          * it schedulable.
476          */
477         Setup_Kernel_Thread(kthread, startFunc, arg);
478
479
480         /* Atomically put the thread on the run queue. */
481         Make_Runnable_Atomic(kthread);
482     }
483
484     return kthread;
485 }
486
487 /*
488  * Add given thread to the run queue, so that it
489  * may be scheduled.  Must be called with interrupts disabled!
490  */
491 void Make_Runnable(struct Kernel_Thread* kthread)
492 {
493     KASSERT(!Interrupts_Enabled());
494
495     Enqueue_Thread(&s_runQueue, kthread);
496 }
497
498 /*
499  * Atomically make a thread runnable.
500  * Assumes interrupts are currently enabled.
501  */
502 void Make_Runnable_Atomic(struct Kernel_Thread* kthread)
503 {
504     Disable_Interrupts();
505     Make_Runnable(kthread);
506     Enable_Interrupts();
507 }
508
509 /*
510  * Get the thread that currently has the CPU.
511  */
512 struct Kernel_Thread* Get_Current(void)
513 {
514     return g_currentThread;
515 }
516
517 /*
518  * Get the next runnable thread from the run queue.
519  * This is the scheduler.
520  */
521 struct Kernel_Thread* Get_Next_Runnable(void)
522 {
523     struct Kernel_Thread* best = 0;
524
525     best = Find_Best(&s_runQueue);
526     KASSERT(best != 0);
527     Remove_Thread(&s_runQueue, best);
528
529 /*
530  *    Print("Scheduling %x\n", best);
531  */
532     return best;
533 }
534
535 /*
536  * Schedule a thread that is waiting to run.
537  * Must be called with interrupts off!
538  * The current thread should already have been placed
539  * on whatever queue is appropriate (i.e., either the
540  * run queue if it is still runnable, or a wait queue
541  * if it is waiting for an event to occur).
542  */
543 void Schedule(void)
544 {
545     struct Kernel_Thread* runnable;
546
547     /* Make sure interrupts really are disabled */
548     KASSERT(!Interrupts_Enabled());
549
550     /* Preemption should not be disabled. */
551     KASSERT(!g_preemptionDisabled);
552
553     /* Get next thread to run from the run queue */
554     runnable = Get_Next_Runnable();
555
556     /*
557      * Activate the new thread, saving the context of the current thread.
558      * Eventually, this thread will get re-activated and Switch_To_Thread()
559      * will "return", and then Schedule() will return to wherever
560      * it was called from.
561      */
562     Switch_To_Thread(runnable);
563 }
564
565 /*
566  * Voluntarily give up the CPU to another thread.
567  * Does nothing if no other threads are ready to run.
568  */
569 void Yield(void)
570 {
571     Disable_Interrupts();
572     Make_Runnable(g_currentThread);
573     Schedule();
574     Enable_Interrupts();
575 }
576
577 /*
578  * Exit the current thread.
579  * Calling this function initiates a context switch.
580  */
581 void Exit(int exitCode)
582 {
583     struct Kernel_Thread* current = g_currentThread;
584
585     if (Interrupts_Enabled())
586         Disable_Interrupts();
587
588     /* Thread is dead */
589     current->exitCode = exitCode;
590     current->alive = false;
591
592     /* Clean up any thread-local memory */
593     Tlocal_Exit(g_currentThread);
594
595     /* Notify the thread's owner, if any */
596     Wake_Up(&current->joinQueue);
597
598     /* Remove the thread's implicit reference to itself. */
599     Detach_Thread(g_currentThread);
600
601     /*
602      * Schedule a new thread.
603      * Since the old thread wasn't placed on any
604      * thread queue, it won't get scheduled again.
605      */
606     Schedule();
607
608     /* Shouldn't get here */
609     KASSERT(false);
610     // the build dies on a warning for a 'noreturn' violation
611     // This ensures that this function never returns
612     while(1);
613 }
614
615 /*
616  * Wait for given thread to die.
617  * Interrupts must be enabled.
618  * Returns the thread exit code.
619  */
620 int Join(struct Kernel_Thread* kthread)
621 {
622     int exitCode;
623
624     KASSERT(Interrupts_Enabled());
625
626     /* It is only legal for the owner to join */
627     KASSERT(kthread->owner == g_currentThread);
628
629     Disable_Interrupts();
630
631     /* Wait for it to die */
632     while (kthread->alive) {
633         Wait(&kthread->joinQueue);
634     }
635
636     /* Get thread exit code. */
637     exitCode = kthread->exitCode;
638
639     /* Release our reference to the thread */
640     Detach_Thread(kthread);
641
642     Enable_Interrupts();
643
644     return exitCode;
645 }
646
647 /*
648  * Look up a thread by its process id.
649  * The caller must be the thread's owner.
650  */
651 struct Kernel_Thread* Lookup_Thread(int pid)
652 {
653     struct Kernel_Thread *result = 0;
654
655     bool iflag = Begin_Int_Atomic();
656
657     /*
658      * TODO: we could remove the requirement that the caller
659      * needs to be the thread's owner by specifying that another
660      * reference is added to the thread before it is returned.
661      */
662
663     result = Get_Front_Of_All_Thread_List(&s_allThreadList);
664     while (result != 0) {
665         if (result->pid == pid) {
666             if (g_currentThread != result->owner)
667                 result = 0;
668             break;
669         }
670         result = Get_Next_In_All_Thread_List(result);
671     }
672
673     End_Int_Atomic(iflag);
674
675     return result;
676 }
677
678
679 /*
680  * Wait on given wait queue.
681  * Must be called with interrupts disabled!
682  * Note that the function will return with interrupts
683  * disabled.  This is desirable, because it allows us to
684  * atomically test a condition that can be affected by an interrupt
685  * and wait for it to be satisfied (if necessary).
686  * See the Wait_For_Key() function in keyboard.c
687  * for an example.
688  */
689 void Wait(struct Thread_Queue* waitQueue)
690 {
691     struct Kernel_Thread* current = g_currentThread;
692
693     KASSERT(!Interrupts_Enabled());
694
695     /* Add the thread to the wait queue. */
696     Enqueue_Thread(waitQueue, current);
697
698     /* Find another thread to run. */
699     Schedule();
700 }
701
702 /*
703  * Wake up all threads waiting on given wait queue.
704  * Must be called with interrupts disabled!
705  * See Keyboard_Interrupt_Handler() function in keyboard.c
706  * for an example.
707  */
708 void Wake_Up(struct Thread_Queue* waitQueue)
709 {
710     struct Kernel_Thread *kthread = waitQueue->head, *next;
711
712     KASSERT(!Interrupts_Enabled());
713
714     /*
715      * Walk throught the list of threads in the wait queue,
716      * transferring each one to the run queue.
717      */
718     while (kthread != 0) {
719         next = Get_Next_In_Thread_Queue(kthread);
720         Make_Runnable(kthread);
721         kthread = next;
722     }
723
724     /* The wait queue is now empty. */
725     Clear_Thread_Queue(waitQueue);
726 }
727
728 /*
729  * Wake up a single thread waiting on given wait queue
730  * (if there are any threads waiting).  Chooses the highest priority thread.
731  * Interrupts must be disabled!
732  */
733 void Wake_Up_One(struct Thread_Queue* waitQueue)
734 {
735     struct Kernel_Thread* best;
736
737     KASSERT(!Interrupts_Enabled());
738
739     best = Find_Best(waitQueue);
740
741     if (best != 0) {
742         Remove_Thread(waitQueue, best);
743         Make_Runnable(best);
744         /*Print("Wake_Up_One: waking up %x from %x\n", best, g_currentThread); */
745     }
746 }
747
748 /*
749  * Allocate a key for accessing thread-local data.
750  */
751 int Tlocal_Create(tlocal_key_t *key, tlocal_destructor_t destructor) 
752 {
753     KASSERT(key);
754
755     bool iflag = Begin_Int_Atomic();
756
757     if (s_tlocalKeyCounter == MAX_TLOCAL_KEYS) return -1;
758     s_tlocalDestructors[s_tlocalKeyCounter] = destructor;
759     *key = s_tlocalKeyCounter++;
760
761     End_Int_Atomic(iflag);
762   
763     return 0;
764 }
765
766 /*
767  * Store a value for a thread-local item
768  */
769 void Tlocal_Put(tlocal_key_t k, const void *v) 
770 {
771     const void **pv;
772
773     KASSERT(k < s_tlocalKeyCounter);
774
775     pv = Get_Tlocal_Pointer(k);
776     *pv = v;
777 }
778
779 /*
780  * Acquire a thread-local value
781  */
782 void *Tlocal_Get(tlocal_key_t k) 
783 {
784     const void **pv;
785
786     KASSERT(k < s_tlocalKeyCounter);
787
788     pv = Get_Tlocal_Pointer(k);
789     return (void *)*pv;
790 }
791
792 /*
793  * Print list of all threads in system.
794  * For debugging.
795  */
796 void Dump_All_Thread_List(void)
797 {
798     struct Kernel_Thread *kthread;
799     int count = 0;
800     bool iflag = Begin_Int_Atomic();
801
802     kthread = Get_Front_Of_All_Thread_List(&s_allThreadList);
803
804     Print("[");
805     while (kthread != 0) {
806         ++count;
807         Print("<%lx,%lx,%lx>",
808             (ulong_t) Get_Prev_In_All_Thread_List(kthread),
809             (ulong_t) kthread,
810             (ulong_t) Get_Next_In_All_Thread_List(kthread));
811         KASSERT(kthread != Get_Next_In_All_Thread_List(kthread));
812         kthread = Get_Next_In_All_Thread_List(kthread);
813     }
814     Print("]\n");
815     Print("%d threads are running\n", count);
816
817     End_Int_Atomic(iflag);
818 }