miniOS
x86_64 hobby kernel with SMP, VFS, and POSIX process model
Loading...
Searching...
No Matches
sched.c File Reference
Include dependency graph for sched.c:

Functions

static uint64_t sched_rdtsc (void)
void per_cpu_update_rsp0 (uint64_t rsp0)
 Update this CPU's TSS RSP0 and cpu_t.kstack_top.
void __attribute__ ((noreturn))
void sched_init (void)
struct threadsched_create_thread (thread_func_t func, void *arg)
struct threadsched_current (void)
struct threadsched_next (void)
bool sched_has_user_threads (void)
void sched_signal_thread (struct thread *t, int sig)
void sched_stop_current (int stop_signal)
void sched_ptrace_stop (int reason)
void sched_wake_tid (uint32_t tid)
static void sched_schedule (void)
void sched_tick (void)
void sched_yield (void)
struct threadsched_create_user_task (uint64_t entry_rip)
void sched_activate_task (struct thread *t)

Function Documentation

◆ __attribute__()

void __attribute__ ( (noreturn) )
extern

◆ sched_activate_task()

void sched_activate_task ( struct thread * t)

sched_activate_task() - Transfer "current" ownership to @t without context_switch_asm. @t: Thread to activate. Must currently be in THREAD_BLOCKED state.

Sets g_current->state = THREAD_RUNNABLE, then sets g_current = t and t->state = THREAD_RUNNING. Used by kernel_main before enter_ring3() so the user task is correctly identified as "current" when it issues its first syscall or triggers a preemptive switch back to the idle thread.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sched_create_thread()

struct thread * sched_create_thread ( thread_func_t func,
void * arg )

sched_create_thread() - Allocate and initialise a kernel thread. @func: Entry function pointer.

  • : Argument passed to @func in RDI (first parameter register).

Scans thread_pool[] for the first slot with state == THREAD_DEAD (or unused). Allocates a 16 KiB kernel stack via kmalloc. Sets initial context: RIP=func, RSP=stack_top-8, RDI=arg, CS=0x08, SS=0x10, RFLAGS=0x202. Appends thread to run queue at tail (before idle) for round-robin fairness. Thread starts THREAD_BLOCKED; caller sets THREAD_RUNNABLE when ready.

Returns
: Thread pointer, or NULL on OOM (kmalloc failed or pool exhausted).
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sched_create_user_task()

struct thread * sched_create_user_task ( uint64_t entry_rip)

sched_create_user_task() - Create a ring-3 user thread. @entry_rip: User-mode entry point virtual address.

Calls sched_create_thread() for the kernel scaffolding, then maps USER_STACK_PAGES (64) 4 KiB pages into the user virtual address space just below USER_STACK_TOP=0x7FFFFFFFE000 using vmm_map_page with PAGE_PRESENT|PAGE_WRITE|PAGE_USER flags. Stores the physical base of the first page in user_stack_phys_base for cleanup by sched_exit_current. Sets up TSS RSP0 via tss_set_rsp0() so syscall entries use the thread's kernel stack.

Returns
: Pointer to the new user thread, or NULL on OOM.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sched_current()

struct thread * sched_current ( void )

sched_current() - Return pointer to the currently running thread.

Returns the global g_current pointer. Called from syscall handlers and context switch paths to identify the active task.

Returns
: Pointer to the current thread (never NULL after sched_init).
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sched_has_user_threads()

bool sched_has_user_threads ( void )

sched_has_user_threads() - Check if any non-idle thread is still alive.

Returns true if at least one thread slot with index > 0 (i.e., not the idle thread) has a state other than THREAD_DEAD. Used by bsp_idle_resume to decide whether to call qemu_exit or continue halting.

Here is the caller graph for this function:

◆ sched_init()

void sched_init ( void )

sched_init() - Initialise the scheduler.

Initialises thread_pool, sets up the run queue (circular singly-linked list with tail pointer), and captures the current boot context as the idle thread. Idle thread uses static storage (not kmalloc'd stack) and the boot stack. Sets g_current = &idle, state = THREAD_RUNNING.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sched_next()

struct thread * sched_next ( void )

sched_next() - Select the next RUNNABLE thread via round-robin.

Starts from current_thread->next and walks the circular run queue, returning the first thread in THREAD_RUNNABLE state. Starting after the current thread (not from run_queue_head) ensures fair round-robin: threads that arrive later in the queue are not starved by earlier threads that are frequently RUNNABLE (e.g. idle, net_poll busy-loop).

If no runnable thread is found after a full traversal, returns the idle thread. Does not modify current_thread.

Returns
: Next thread to run (never NULL; falls back to idle).
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sched_ptrace_stop()

void sched_ptrace_stop ( int reason)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sched_rdtsc()

uint64_t sched_rdtsc ( void )
inlinestatic
Here is the caller graph for this function:

◆ sched_schedule()

void sched_schedule ( void )
static
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sched_signal_thread()

void sched_signal_thread ( struct thread * t,
int sig )

sched_signal_thread() - Deliver a signal to a thread, waking it if blocked. @t: Target thread. @sig: Signal number (1-31).

Sets the pending bit and, if the thread is THREAD_WAITING, transitions it to THREAD_RUNNABLE so the scheduler will pick it up. This enables waitpid and other blocking waits to return -EINTR when signalled.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sched_stop_current()

void sched_stop_current ( int stop_signal)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sched_tick()

void sched_tick ( void )

sched_tick() - LAPIC timer ISR callback; advance the scheduler.

Increments the global tick counter. Calls sched_schedule() to perform a context switch when the current thread's quantum expires (or immediately when a higher-priority thread becomes runnable). EOI is sent by the LAPIC timer ISR before calling this function; the context switch is safe.

Context: Must only be called from the LAPIC timer ISR with interrupts disabled via the interrupt gate mechanism. Must not allocate.

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sched_wake_tid()

void sched_wake_tid ( uint32_t tid)
Here is the call graph for this function:
Here is the caller graph for this function:

◆ sched_yield()

void sched_yield ( void )

sched_yield() - Voluntarily yield to the next runnable thread.

Disables interrupts around sched_schedule() to prevent the LAPIC timer from firing inside context_switch_asm during a cooperative yield.

Without this guard, the cooperative path (sched_yield from SYS_fork / sched_wait) runs with IF=1 (sti was issued in syscall_entry before syscall_dispatch). If a timer fires after sched_schedule sets current_thread=next but before context_switch_asm finishes restoring the new thread's registers, the nested sched_schedule saves wrong register values into next->ctx, corrupting the thread on re-schedule.

The preemptive path (sched_tick from the timer ISR) is always called with IF=0 (interrupt gates clear IF on entry), so it is not affected.

Here is the call graph for this function:
Here is the caller graph for this function: