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