#include #include #include "thread.h" #include "core.h" #include #ifndef DEBUG_THREAD #define dprintf #endif 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); }