gint-with-thread/src/thread/scheduler.c

101 lines
3.3 KiB
C

//---
// gint:thread:scheduler - High-level scheduler part
//---
#include <gint/thread.h>
#include <gint/display.h>
/* symbols defined in <gint/thread.thread.c> */
extern struct thread *thread_scheduler_queue;
extern struct thread *thread_scheduler_current;
extern struct thread thread_kernel_idle;
/* thread_schedule(): Schedule thread queue and return the next thread
This function SHOULD NOT be involved manually, it should be be involved only
by the scheduler "handler" (see <gint/thread/kernel.S>). */
struct thread *thread_schedule(void)
{
struct thread *thread;
/* Check potential error. */
if (thread_scheduler_queue == NULL)
return (NULL);
/* if we have no currently running thread, return directly
TODO: stop the scheduler timer until multiple thread is detected. */
thread = thread_scheduler_queue;
if (thread_scheduler_current == NULL) {
thread_scheduler_current = thread;
return (thread);
}
/* Get the potential next thread context. */
thread = thread->private.next;
if (thread == NULL)
thread = thread_scheduler_queue;
/* Check all scheduler thread in the queue by checking their status and
pending signals. */
while (thread != thread_scheduler_current) {
/* Check if the potential next thread is valid
@note:
A thread who has a pending signal which involve user signals
handler is considered like a valid thread, this is why we
deliver signals now. */
if (thread->status == THREAD_STATUS_RUNNING
&& thread_signals_pending_deliver(thread) == 0) {
break;
}
/* Get the potential next thread */
thread = thread->private.next;
if (thread == NULL)
thread = thread_scheduler_queue;
}
/* Check if no thread has been found, check its signals and see if the
context can be loaded again. */
if (thread == thread_scheduler_current) {
if (thread->status == THREAD_STATUS_RUNNING
&& thread_signals_pending_deliver(thread) == 0) {
return (thread);
}
/* If no thread has been found, load idle kernel thread which
will only wait the next scheduler timer intervention.
(see <gint/thread/thread.c> for more information). */
return (&thread_kernel_idle);
}
/* return the next thread */
thread_scheduler_current = thread;
return (thread);
}
#ifdef THREAD_SCHEDULER_DEBUG
/* thread_schedule_debug(): Debug scheduler, involved each context_switch */
void thread_schedule_debug(struct thread *thread)
{
extern uint32_t thread_tmu_interrupt_id;
extern uint32_t thread_tmu_tcr_addr;
extern uint32_t thread_tmu_tcr_mask;
extern uint32_t thread_tmu_tstr_mask;
extern uint32_t thread_tmu_tstr_addr;
dclear(C_WHITE);
dprint(1, 1, C_BLACK, "next process -> %p", thread);
dprint(1, 11, C_BLACK, "|--spc: %p", thread->context.cpu.spc);
dprint(1, 21, C_BLACK, "|--ssr: %p", thread->context.cpu.ssr);
dprint(1, 31, C_BLACK, "|--r15: %p", thread->context.cpu.reg[15]);
dprint(1, 41, C_BLACK, "|--@r0: %p", &thread->context.cpu.reg[0]);
dprint(1, 61, C_BLACK, "|--tmu_event: %#x", thread_tmu_interrupt_id);
dprint(1, 71, C_BLACK, "|--tmu_tcr_addr: %#x", thread_tmu_tcr_addr);
dprint(1, 81, C_BLACK, "|--tmu_tcr_mask: %#x", thread_tmu_tcr_mask);
dprint(1, 91, C_BLACK, "|--tmu_tstr_addr: %#x", thread_tmu_tstr_addr);
dprint(1, 101, C_BLACK, "`--tmu_tstr_mask: %#x", thread_tmu_tstr_mask);
dupdate();
while (1);
}
#endif