miniOS
x86_64 hobby kernel with SMP, VFS, and POSIX process model
Loading...
Searching...
No Matches
sched.h File Reference
Include dependency graph for sched.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  mmap_region_t
struct  thread_group
struct  thread

Macros

#define THREAD_STACK_SIZE   16384 /* 16 KB kernel stack per thread */
#define MAX_CPUS   8
#define SCHED_MAX_THREADS   (MAX_CPUS + 8)
#define USER_STACK_TOP   0x7FFFFFFFE000ULL /* top of user stack */
#define USER_STACK_PAGES   16 /* 16 x 4 KiB = 64 KiB user stack */
#define MMAP_BASE   0x70000000000ULL /* anonymous mmap high base; grows downward */
#define MMAP_MAX_REGIONS   64
#define MMAP_REGION_ANON   0 /* anonymous private mapping (MAP_ANONYMOUS|MAP_PRIVATE) */
#define MMAP_REGION_FILE   1 /* file-backed private mapping (MAP_PRIVATE, fd >= 3) */
#define THREAD_GROUP_MAX   4
#define PTRACE_STOP_SYSCALL_ENTRY   1
#define PTRACE_STOP_SYSCALL_EXIT   2
#define PTRACE_STOP_EXEC   3
#define PTRACE_STOP_SINGLESTEP   4
#define THREAD_FDT(t)
#define THREAD_BRK_PTR(t)
#define THREAD_BRK_BASE_PTR(t)
#define THREAD_MMAP_PTR(t)
#define THREAD_MMAPR(t)
#define THREAD_CWD(t)
#define THREAD_PML4(t)

Typedefs

typedef void(* thread_func_t) (void *arg)
typedef struct thread_group thread_group_t

Enumerations

enum  thread_state_t {
  THREAD_RUNNABLE = 0 , THREAD_RUNNING = 1 , THREAD_DEAD = 2 , THREAD_WAITING = 3 ,
  THREAD_BLOCKED = 4 , THREAD_FUTEX_WAIT = 5 , THREAD_STOPPED = 6
}

Functions

void __attribute__ ((noreturn)) idle_loop(void *arg)
void sched_init (void)
void sched_init_cpu (uint32_t cpu_id)
struct threadsched_create_thread (thread_func_t func, void *arg)
void sched_tick (void)
struct threadsched_current (void)
struct threadsched_next (void)
void sched_yield (void)
struct threadsched_create_user_task (uint64_t entry_rip)

Variables

thread_group_t thread_group_pool [THREAD_GROUP_MAX]

Macro Definition Documentation

◆ MAX_CPUS

#define MAX_CPUS   8

◆ MMAP_BASE

#define MMAP_BASE   0x70000000000ULL /* anonymous mmap high base; grows downward */

◆ MMAP_MAX_REGIONS

#define MMAP_MAX_REGIONS   64

◆ MMAP_REGION_ANON

#define MMAP_REGION_ANON   0 /* anonymous private mapping (MAP_ANONYMOUS|MAP_PRIVATE) */

◆ MMAP_REGION_FILE

#define MMAP_REGION_FILE   1 /* file-backed private mapping (MAP_PRIVATE, fd >= 3) */

◆ PTRACE_STOP_EXEC

#define PTRACE_STOP_EXEC   3

◆ PTRACE_STOP_SINGLESTEP

#define PTRACE_STOP_SINGLESTEP   4

◆ PTRACE_STOP_SYSCALL_ENTRY

#define PTRACE_STOP_SYSCALL_ENTRY   1

◆ PTRACE_STOP_SYSCALL_EXIT

#define PTRACE_STOP_SYSCALL_EXIT   2

◆ SCHED_MAX_THREADS

#define SCHED_MAX_THREADS   (MAX_CPUS + 8)

◆ THREAD_BRK_BASE_PTR

#define THREAD_BRK_BASE_PTR ( t)
Value:
((t)->tg ? &(t)->tg->brk_base : &(t)->brk_base)

◆ THREAD_BRK_PTR

#define THREAD_BRK_PTR ( t)
Value:
((t)->tg ? &(t)->tg->brk : &(t)->brk)

◆ THREAD_CWD

#define THREAD_CWD ( t)
Value:
((t)->tg ? (t)->tg->cwd : (t)->cwd)

◆ THREAD_FDT

#define THREAD_FDT ( t)
Value:
((t)->tg ? (t)->tg->fd_table : (t)->fd_table)

◆ THREAD_GROUP_MAX

#define THREAD_GROUP_MAX   4

◆ THREAD_MMAP_PTR

#define THREAD_MMAP_PTR ( t)
Value:
((t)->tg ? &(t)->tg->mmap_next : &(t)->mmap_next)

◆ THREAD_MMAPR

#define THREAD_MMAPR ( t)
Value:
((t)->tg ? (t)->tg->mmap_regions : (t)->mmap_regions)

◆ THREAD_PML4

#define THREAD_PML4 ( t)
Value:
((t)->tg ? (t)->tg->pml4_phys : (t)->pml4_phys)

◆ THREAD_STACK_SIZE

#define THREAD_STACK_SIZE   16384 /* 16 KB kernel stack per thread */

◆ USER_STACK_PAGES

#define USER_STACK_PAGES   16 /* 16 x 4 KiB = 64 KiB user stack */

◆ USER_STACK_TOP

#define USER_STACK_TOP   0x7FFFFFFFE000ULL /* top of user stack */

Typedef Documentation

◆ thread_func_t

typedef void(* thread_func_t) (void *arg)

◆ thread_group_t

typedef struct thread_group thread_group_t

Enumeration Type Documentation

◆ thread_state_t

Enumerator
THREAD_RUNNABLE 
THREAD_RUNNING 
THREAD_DEAD 
THREAD_WAITING 
THREAD_BLOCKED 
THREAD_FUTEX_WAIT 
THREAD_STOPPED 

Function Documentation

◆ __attribute__()

void __attribute__ ( (noreturn) )
Here is the call graph for this function:

◆ sched_create_thread()

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

sched_create_thread() - Create a new kernel thread. @func: Entry function; called with

  • as its sole argument.
  • : Opaque argument forwarded to @func.

Allocates a thread slot from thread_pool and a 16 KiB kernel stack via kmalloc. The thread is enqueued as THREAD_BLOCKED; the caller must set state = THREAD_RUNNABLE once the context is fully initialised to avoid a race with the LAPIC timer ISR.

Returns
: Pointer to the new thread on success, NULL on OOM.

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 new ring-3 user thread. @entry_rip: Virtual address of the user-mode entry point.

Allocates USER_STACK_PAGES (64) pages of user stack just below USER_STACK_TOP (0x7FFFFFFFE000), with an implicit guard page below. The thread starts at ring-3 with RIP=@entry_rip, RSP=USER_STACK_TOP-8, RFLAGS=0x202 (interrupts enabled).

Returns
: Pointer to the new thread on success, NULL on OOM.

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 the currently running thread.

Returns
: Pointer to the thread currently executing on the CPU.

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_init()

void sched_init ( void )

sched_init() - Initialise the scheduler and create the idle thread.

Captures the current execution context (boot stack, boot code) as the idle thread. Must be called with interrupts disabled, before the first call to sched_tick().

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_init_cpu()

void sched_init_cpu ( uint32_t cpu_id)

sched_init_cpu() - Create the idle thread for CPU @cpu_id. @cpu_id: Logical CPU index (0=BSP, 1..N-1=APs).

Creates a per-CPU idle thread using sched_create_thread(idle_loop, NULL), sets its state to THREAD_RUNNING (since the CPU is currently "running" it), and assigns it to g_cpus[cpu_id].idle_thread.

For cpu_id == 0 (BSP): called after sched_init() as a no-op (BSP idle is already set up by sched_init via idle_thread_storage). For cpu_id > 0 (APs): creates a fresh idle thread in thread_pool[].

Here is the caller graph for this function:

◆ sched_next()

struct thread * sched_next ( void )

sched_next() - Pick the next RUNNABLE thread (round-robin).

Walks the run queue to find the next thread in THREAD_RUNNABLE state. Falls back to the idle thread if no runnable thread is found. Does NOT perform the actual CPU context switch — that is done by context_switch_asm.

Returns
: Pointer to the next thread to run (never NULL).

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_tick()

void sched_tick ( void )

sched_tick() - Advance the scheduler from the LAPIC timer ISR.

Increments the tick counter and calls the internal scheduler to switch to the next runnable thread when the quantum expires.

Context: Must only be called from the LAPIC timer ISR with interrupts disabled. Must not sleep or allocate memory.

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_yield()

void sched_yield ( void )

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

Marks the calling thread as THREAD_RUNNABLE and invokes the internal scheduler to switch to the next thread immediately.

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:

Variable Documentation

◆ thread_group_pool

thread_group_t thread_group_pool[THREAD_GROUP_MAX]
extern