92 lines
2.0 KiB
C
92 lines
2.0 KiB
C
#include <klibc/compiler.h>
|
|
#include <sys/cpu.h>
|
|
#include "thread.h"
|
|
#include "core.h"
|
|
#include <dprintf.h>
|
|
|
|
void (*sched_hook_func)(void);
|
|
|
|
/*
|
|
* __schedule() should only be called with interrupts locked out!
|
|
*/
|
|
void __schedule(void)
|
|
{
|
|
static bool in_sched_hook;
|
|
struct thread *curr = current();
|
|
struct thread *st, *nt, *best;
|
|
|
|
#if DEBUG
|
|
if (__unlikely(irq_state() & 0x200)) {
|
|
dprintf("In __schedule with interrupts on!\n");
|
|
kaboom();
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Are we called from inside sched_hook_func()? If so we'll
|
|
* schedule anyway on the way out.
|
|
*/
|
|
if (in_sched_hook)
|
|
return;
|
|
|
|
dprintf("Schedule ");
|
|
|
|
/* Possibly update the information on which we make
|
|
* scheduling decisions.
|
|
*/
|
|
if (sched_hook_func) {
|
|
in_sched_hook = true;
|
|
sched_hook_func();
|
|
in_sched_hook = false;
|
|
}
|
|
|
|
/*
|
|
* The unusual form of this walk is because we have to start with
|
|
* the thread *following* curr, and curr may not actually be part
|
|
* of the list anymore (in the case of __exit_thread).
|
|
*/
|
|
best = NULL;
|
|
nt = st = container_of(curr->list.next, struct thread, list);
|
|
do {
|
|
if (__unlikely(nt->thread_magic != THREAD_MAGIC)) {
|
|
dprintf("Invalid thread on thread list %p magic = 0x%08x\n",
|
|
nt, nt->thread_magic);
|
|
kaboom();
|
|
}
|
|
|
|
dprintf("Thread %p (%s) ", nt, nt->name);
|
|
if (!nt->blocked) {
|
|
dprintf("runnable priority %d\n", nt->prio);
|
|
if (!best || nt->prio < best->prio)
|
|
best = nt;
|
|
} else {
|
|
dprintf("blocked\n");
|
|
}
|
|
nt = container_of(nt->list.next, struct thread, list);
|
|
} while (nt != st);
|
|
|
|
if (!best)
|
|
kaboom(); /* No runnable thread */
|
|
|
|
if (best != curr) {
|
|
uint64_t tsc;
|
|
|
|
asm volatile("rdtsc" : "=A" (tsc));
|
|
|
|
dprintf("@ %llu -> %p (%s)\n", tsc, best, best->name);
|
|
__switch_to(best);
|
|
} else {
|
|
dprintf("no change\n");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* This can be called from "normal" code...
|
|
*/
|
|
void thread_yield(void)
|
|
{
|
|
irq_state_t irq = irq_save();
|
|
__schedule();
|
|
irq_restore(irq);
|
|
}
|