forked from Lephenixnoir/gint
101 lines
3.3 KiB
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
|