1 #include <klibc/compiler.h>
2 #include <sys/cpu.h>
3 #include "thread.h"
4 #include "core.h"
5 #include <dprintf.h>
6 
7 void (*sched_hook_func)(void);
8 
9 /*
10  * __schedule() should only be called with interrupts locked out!
11  */
__schedule(void)12 void __schedule(void)
13 {
14     static bool in_sched_hook;
15     struct thread *curr = current();
16     struct thread *st, *nt, *best;
17 
18 #if DEBUG
19     if (__unlikely(irq_state() & 0x200)) {
20 	dprintf("In __schedule with interrupts on!\n");
21 	kaboom();
22     }
23 #endif
24 
25     /*
26      * Are we called from inside sched_hook_func()?  If so we'll
27      * schedule anyway on the way out.
28      */
29     if (in_sched_hook)
30 	return;
31 
32     dprintf("Schedule ");
33 
34     /* Possibly update the information on which we make
35      * scheduling decisions.
36      */
37     if (sched_hook_func) {
38 	in_sched_hook = true;
39 	sched_hook_func();
40 	in_sched_hook = false;
41     }
42 
43     /*
44      * The unusual form of this walk is because we have to start with
45      * the thread *following* curr, and curr may not actually be part
46      * of the list anymore (in the case of __exit_thread).
47      */
48     best = NULL;
49     nt = st = container_of(curr->list.next, struct thread, list);
50     do {
51 	if (__unlikely(nt->thread_magic != THREAD_MAGIC)) {
52 	    dprintf("Invalid thread on thread list %p magic = 0x%08x\n",
53 		    nt, nt->thread_magic);
54 	    kaboom();
55 	}
56 
57 	dprintf("Thread %p (%s) ", nt, nt->name);
58 	if (!nt->blocked) {
59 	    dprintf("runnable priority %d\n", nt->prio);
60 	    if (!best || nt->prio < best->prio)
61 		best = nt;
62 	} else {
63 	    dprintf("blocked\n");
64 	}
65 	nt = container_of(nt->list.next, struct thread, list);
66     } while (nt != st);
67 
68     if (!best)
69 	kaboom();		/* No runnable thread */
70 
71     if (best != curr) {
72 	uint64_t tsc;
73 
74 	asm volatile("rdtsc" : "=A" (tsc));
75 
76 	dprintf("@ %llu -> %p (%s)\n", tsc, best, best->name);
77 	__switch_to(best);
78     } else {
79 	dprintf("no change\n");
80     }
81 }
82 
83 /*
84  * This can be called from "normal" code...
85  */
thread_yield(void)86 void thread_yield(void)
87 {
88     irq_state_t irq = irq_save();
89     __schedule();
90     irq_restore(irq);
91 }
92