miniOS
x86_64 hobby kernel with SMP, VFS, and POSIX process model
Loading...
Searching...
No Matches
sched.h
Go to the documentation of this file.
1// MIT License
2//
3// Copyright (c) 2026 Christian Spoo
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21// SOFTWARE.
22
23#ifndef _MINIOS_SCHED_SCHED_H_
24#define _MINIOS_SCHED_SCHED_H_
25
26#include <miniOS/types.h>
27
30#include <miniOS/fs/vfs.h>
31#include <miniOS/signal.h>
32
33#define THREAD_STACK_SIZE 16384 /* 16 KB kernel stack per thread */
34
35/* SCHED_MAX_THREADS: thread pool size. Must accommodate MAX_CPUS idle threads
36 plus user threads. Set to MAX_CPUS + 16 for headroom.
37 MAX_CPUS is defined by the build system (arch/kernel CMakeLists.txt),
38 defaulting to 8 if not provided at compile time. */
39#ifndef MAX_CPUS
40#define MAX_CPUS 8
41#endif
42#define SCHED_MAX_THREADS (MAX_CPUS + 8)
43
44#define USER_STACK_TOP 0x7FFFFFFFE000ULL /* top of user stack */
45#define USER_STACK_PAGES 16 /* 16 x 4 KiB = 64 KiB user stack */
46
47typedef enum {
51 THREAD_WAITING = 3, /* blocked in sched_wait() until child exits */
52 THREAD_BLOCKED = 4, /* not yet ready to run (setup in progress) */
53 THREAD_FUTEX_WAIT = 5, /* blocked in sys_futex FUTEX_WAIT */
54 THREAD_STOPPED = 6, /* stopped by SIGSTOP/SIGTSTP; resumes on SIGCONT */
56
57typedef void (*thread_func_t)(void *arg);
58
59#define MMAP_BASE 0x70000000000ULL /* anonymous mmap high base; grows downward */
60#define MMAP_MAX_REGIONS 64
61
62#define MMAP_REGION_ANON 0 /* anonymous private mapping (MAP_ANONYMOUS|MAP_PRIVATE) */
63#define MMAP_REGION_FILE 1 /* file-backed private mapping (MAP_PRIVATE, fd >= 3) */
64
65typedef struct {
66 uint64_t virt_addr; /* base VA of the mapping; 0 = free slot */
67 uint64_t len; /* length in bytes (multiple of PAGE_SIZE) */
68 int prot; /* PROT_* flags as passed by caller */
69 int region_type; /* MMAP_REGION_ANON or MMAP_REGION_FILE */
70 int lazy; /* 1 = pages not yet mapped; allocate on first #PF */
71 /* File-backed mapping metadata (MMAP_REGION_FILE + lazy=1 only) */
72 uint32_t file_inode; /* inode number of the mapped file */
73 uint64_t file_offset; /* file offset corresponding to virt_addr */
74 uint64_t file_size; /* bytes of real file data (tail pages zero-padded) */
75 vfs_ops_t *file_ops; /* filesystem ops; stable static pointer */
77
78/* ---- Thread group (shared state for CLONE_VM|CLONE_FILES threads) ---- */
79#define THREAD_GROUP_MAX 4
80
81typedef struct thread_group {
82 int in_use;
83 int ref_count; /* number of threads pointing at this group */
87 uint64_t brk_base; /* lower bound of heap (ELF image end); set once at execve */
91 uint64_t pml4_phys; /* shared address space (vmm_new_address_space()) */
93
95
96struct thread {
99 struct task_cpu_context ctx; /* saved register state (used when not running) */
100 uint8_t *stack_base; /* kmalloc'd kernel stack buffer base */
101 struct thread *next; /* intrusive linked list for run queue */
102
103 /* User-mode stack -- NULL/0 for kernel-only threads */
104 uint64_t user_stack_phys_base; /* physical base of first user stack page (for cleanup) */
105 uint64_t user_stack_virt_top; /* virtual address of stack top (passed in RSP via iretq) */
106 uint8_t user_stack_pages; /* number of pages allocated (USER_STACK_PAGES) */
107
108 /* Per-task open file table (VFS) */
110
111 /* Fork/wait support */
112 uint32_t parent_tid; /* tid of parent thread; 0 if none */
113 int exit_code; /* exit code set by SYS_exit, read by parent's SYS_wait */
114
115 /* POSIX process identity */
116 uint32_t pid; /* process ID — equals tid at task creation */
117 uint32_t ppid; /* parent process ID — parent->pid at fork, 0 for root tasks */
118 uint32_t pgid; /* process group ID — default = pid; mutable via SYS_setpgid */
119 uint32_t sid; /* session ID — default = pid at creation; set via SYS_setsid */
120
121 /* Saved user-mode registers across context switches (used for fork child sysret) */
122 uint64_t saved_user_rsp; /* user RSP at syscall entry */
123 uint64_t saved_user_rip; /* user RIP at syscall entry (rcx from SYSCALL) */
124 uint64_t saved_user_rfl; /* user RFLAGS at syscall entry (r11 from SYSCALL) */
125
126 /* Callee-saved user registers at syscall entry (SYSCALL doesn't save these;
127 * fork_child_trampoline must restore them so the child's stack frame is intact) */
134
135 /* Argument registers for execve: set to argc/argv before sysretq to ELF entry.
136 * Zero-initialised by sched_create_user_task; set by SYS_execve. */
137 uint64_t saved_user_rdi; /* argc for new process */
138 uint64_t saved_user_rsi; /* pointer to argv array for new process */
139 uint64_t saved_user_rdx; /* pointer to envp array for new process */
140
141 /* Heap break for SYS_brk / Newlib malloc support.
142 * Initialised to 0; set to ELF load end by SYS_execve.
143 * sys_brk() maps pages up to this address on each call. */
145 uint64_t brk_base; /* ELF image end = lowest valid heap VA; set once at task creation */
146
147 /* Anonymous mmap region tracking.
148 * mmap_next is the allocation cursor, initialised to MMAP_BASE at task creation.
149 * Grows downward: each new mapping is placed below the previous one.
150 * mmap_regions[] tracks up to MMAP_MAX_REGIONS active mappings; virt_addr==0 = free slot. */
153
154 /* Signal delivery */
155 uint32_t pending_signals; /* bitmask: bit N set if signal N is pending (signals 1-31) */
156 mini_sigaction_t signal_actions[32]; /* per-signal disposition; index 0 unused; default = SIG_DFL */
157
158 /* Interval timer — ITIMER_REAL */
159 uint64_t itimer_real_deadline_ticks; /* lapic tick count when alarm fires; 0 = inactive */
160 uint64_t itimer_real_interval_ticks; /* reload interval in ticks; 0 = one-shot */
161 uint8_t itimer_real_active; /* 1 = armed, 0 = disarmed */
162
163 /* SA_RESTART syscall replay state */
164 uint64_t syscall_restart_nr; /* syscall number of interrupted syscall */
165 uint64_t syscall_restart_args[6]; /* all 6 arguments at syscall entry */
166 uint64_t syscall_restart_saved_rip; /* user RIP to restore in sigreturn */
167 uint8_t syscall_restart_pending; /* 1 = interrupted syscall may restart */
168 uint8_t syscall_last_signal; /* signal number dispatched, for SA_RESTART lookup */
169 uint8_t _restart_pad[6]; /* pad to 8-byte boundary */
170 uint64_t signal_trampoline_va; /* userspace trampoline VA, set by SYS_register_sigtrampoline */
171 /* Snapshot of syscall_restart_* taken at ring3_invoke_handler() time.
172 * SYS_sigreturn uses these so syscalls inside the handler cannot corrupt
173 * the pre-handler return state. */
174 uint64_t signal_ctx_rip; /* saved_user_rip at handler-dispatch time */
175 uint64_t signal_ctx_rsp; /* saved_user_rsp at handler-dispatch time (restored by sigreturn) */
176 uint64_t signal_ctx_restart_rip; /* copy of syscall_restart_saved_rip */
177 uint64_t signal_ctx_restart_nr; /* copy of syscall_restart_nr */
178 uint64_t signal_ctx_restart_args[6]; /* copy of syscall_restart_args */
179 uint8_t signal_ctx_restart_pending; /* copy of syscall_restart_pending */
180 uint8_t _signal_ctx_pad[7]; /* pad to 8-byte boundary */
181
182 /* Current working directory.
183 * Initialized to "/" at task creation; updated by SYS_chdir.
184 * Inherited (copied) by sched_fork(). Max length: VFS_PATH_MAX-1 chars. */
186
187 /* Thread group (CLONE_VM|CLONE_FILES threads). NULL = single-threaded. */
189 uint32_t tgid; /* thread group ID (= pid of group leader); 0 if not in group */
191
192 /* Per-process address space (vmm_new_address_space()). Every thread not in a
193 * group owns its own; grouped threads share tg->pml4_phys via THREAD_PML4(). */
195
196 /* futex: uaddr being waited on, NULL if not in FUTEX_WAIT */
198
199 /* clone CLONE_CHILD_CLEARTID / set_tid_address: clear this VA on exit then FUTEX_WAKE 1 */
201
202 /* /proc/<pid> support. comm = basename of the exec'd binary (TASK_COMM_LEN-style,
203 * truncated). cmdline = NUL-separated argv as execve() received it, cmdline_len
204 * bytes total (including each arg's NUL). utime_ticks = LAPIC ticks charged to
205 * this thread while it was cpu->current_thread (approximate; no user/kernel split). */
206 char comm[16];
207 char cmdline[128];
210
211 /* Job control: signal number that put this thread into THREAD_STOPPED
212 * (SIGSTOP or SIGTSTP), for WSTOPSIG() via wait4's status word. Also
213 * used for ptrace stops (always SIGTRAP) — wait4's existing THREAD_STOPPED
214 * reporting path is shared by both job control and ptrace. */
216
217 /* ptrace(2) — PTRACE_TRACEME only (no PTRACE_ATTACH to an unrelated running
218 * process). ptrace_traced/ptrace_tracer_tid identify the tracer; a traced
219 * thread's SYS_execve raises an initial PTRACE_EVENT_EXEC-equivalent stop
220 * (see syscall_proc.c). ptrace_trace_syscalls arms PTRACE_SYSCALL
221 * entry/exit stops in syscall_dispatch(). ptrace_stop_reason records why
222 * the thread is (or was last) THREAD_STOPPED for ptrace's benefit, and
223 * ptrace_syscall_nr/ptrace_syscall_ret let GETREGS report orig_rax/rax at
224 * a syscall stop (rax otherwise never leaves the CPU register file at
225 * that point — syscall_restart_nr/args capture the entry-time values). */
228 uint8_t ptrace_stop_reason; /* PTRACE_STOP_* below */
232
233 /* Set to the #DB handler's local interrupt-frame pointer while stopped
234 * for PTRACE_STOP_SINGLESTEP, NULL otherwise. miniOS has two distinct
235 * "return to userspace" paths — sysretq (SYSCALL entry, resumes from
236 * saved_user_rip/rfl/rsp) and iretq (interrupt/exception entry, resumes
237 * from this per-trap stack-local context) — and a ptrace stop can
238 * legitimately happen via either one (a syscall stop always resumes via
239 * sysretq; a singlestep #DB stop always resumes via iretq). Whichever
240 * one applies, PTRACE_CONT/PTRACE_SINGLESTEP must set the TF flag (or
241 * not) on the correct copy, or the resumed thread won't actually
242 * single-step. NULL means "resumes via sysretq, use saved_user_rfl".
243 * Never dereferenced by anything other than the thread's own #DB
244 * handler and its own tracer, and only while genuinely stopped. */
246};
247
248/* Why a traced thread is (or was last) THREAD_STOPPED. Shared by
249 * syscall.c (entry/exit stops), syscall_proc.c (TRACEME's initial exec
250 * stop), and the #DB handler in exceptions.c (singlestep stops). */
251#define PTRACE_STOP_SYSCALL_ENTRY 1
252#define PTRACE_STOP_SYSCALL_EXIT 2
253#define PTRACE_STOP_EXEC 3
254#define PTRACE_STOP_SINGLESTEP 4
255
256/* Resolve the active fd_table, brk, mmap_next, mmap_regions, cwd for thread t.
257 * Threads in a group share all these via tg; single-threaded tasks use own fields. */
258#define THREAD_FDT(t) ((t)->tg ? (t)->tg->fd_table : (t)->fd_table)
259#define THREAD_BRK_PTR(t) ((t)->tg ? &(t)->tg->brk : &(t)->brk)
260#define THREAD_BRK_BASE_PTR(t) ((t)->tg ? &(t)->tg->brk_base : &(t)->brk_base)
261#define THREAD_MMAP_PTR(t) ((t)->tg ? &(t)->tg->mmap_next : &(t)->mmap_next)
262#define THREAD_MMAPR(t) ((t)->tg ? (t)->tg->mmap_regions : (t)->mmap_regions)
263#define THREAD_CWD(t) ((t)->tg ? (t)->tg->cwd : (t)->cwd)
264#define THREAD_PML4(t) ((t)->tg ? (t)->tg->pml4_phys : (t)->pml4_phys)
265
266/* idle_loop: per-CPU idle function; runs sti;hlt in a loop. Not static so
267 sched_init_cpu() can wire it as the per-AP idle thread entry point. */
268void __attribute__((noreturn)) idle_loop(void *arg);
269
277void sched_init(void);
278
292
305struct thread *sched_create_thread(thread_func_t func, void *arg);
306
316void sched_tick(void);
317
323struct thread *sched_current(void);
324
334struct thread *sched_next(void);
335
342void sched_yield(void);
343
355struct thread *sched_create_user_task(uint64_t entry_rip);
356
366void sched_exit_current(int code);
367
373bool sched_has_user_threads(void);
374
387struct thread *sched_fork(void);
388
401int sched_wait(uint32_t child_tid, int *exit_code);
402
415struct thread *sched_clone(uint64_t child_stack, uint64_t tls, uint32_t *child_tid);
416
427void sched_balance_enqueue(struct thread *t);
428
438void sched_signal_thread(struct thread *t, int sig);
439
453
465void sched_ptrace_stop(int reason);
466
475
487void sched_work_steal(void);
488
489/* Expose thread_pool for sched_wait iteration */
490extern struct thread thread_pool[SCHED_MAX_THREADS];
491
492/* sched_tick_count: LAPIC timer ticks since boot, incremented by sched_tick().
493 * Used as a coarse jiffies-equivalent (e.g. /proc/stat's "cpu" line). */
494extern volatile uint64_t sched_tick_count;
495
496/* Exposed for sched_balance.c — guards thread_pool[], run queues, thread_count */
498
508void sched_activate_task(struct thread *t);
509
520extern void context_switch_asm(struct task_cpu_context *old_ctx,
521 struct task_cpu_context *new_ctx);
522
523#endif /* _MINIOS_SCHED_SCHED_H_ */
bool sched_has_user_threads(void)
Definition sched.c:320
void sched_activate_task(struct thread *t)
Definition sched.c:667
void sched_ptrace_stop(int reason)
Definition sched.c:382
void sched_wake_tid(uint32_t tid)
Definition sched.c:404
void sched_signal_thread(struct thread *t, int sig)
Definition sched.c:338
void sched_stop_current(int stop_signal)
Definition sched.c:364
struct thread * sched_create_user_task(uint64_t entry_rip)
Definition sched.c:557
void sched_tick(void)
Definition sched.c:481
struct thread * sched_create_thread(thread_func_t func, void *arg)
Definition sched.c:167
void sched_yield(void)
Definition sched.c:536
struct thread_group thread_group_t
#define SCHED_MAX_THREADS
Definition sched.h:42
thread_group_t thread_group_pool[THREAD_GROUP_MAX]
struct thread * sched_current(void)
Definition sched.c:277
struct thread * sched_next(void)
Definition sched.c:296
thread_state_t
Definition sched.h:47
@ THREAD_DEAD
Definition sched.h:50
@ THREAD_WAITING
Definition sched.h:51
@ THREAD_BLOCKED
Definition sched.h:52
@ THREAD_FUTEX_WAIT
Definition sched.h:53
@ THREAD_STOPPED
Definition sched.h:54
@ THREAD_RUNNABLE
Definition sched.h:48
@ THREAD_RUNNING
Definition sched.h:49
#define THREAD_GROUP_MAX
Definition sched.h:79
void sched_init(void)
Definition sched.c:104
void(* thread_func_t)(void *arg)
Definition sched.h:57
void sched_init_cpu(uint32_t cpu_id)
spinlock_t thread_pool_lock
void sched_work_steal(void)
Definition sched_balance.c:85
void sched_balance_enqueue(struct thread *t)
Definition sched_balance.c:42
struct mini_sigaction mini_sigaction_t
Definition sched.h:65
uint64_t virt_addr
Definition sched.h:66
uint32_t file_inode
Definition sched.h:72
int lazy
Definition sched.h:70
uint64_t file_offset
Definition sched.h:73
uint64_t len
Definition sched.h:67
uint64_t file_size
Definition sched.h:74
int region_type
Definition sched.h:69
vfs_ops_t * file_ops
Definition sched.h:75
int prot
Definition sched.h:68
Definition spinlock.h:50
Definition context.h:28
Definition sched.h:81
uint64_t pml4_phys
Definition sched.h:91
uint64_t brk_base
Definition sched.h:87
int in_use
Definition sched.h:82
spinlock_t lock
Definition sched.h:84
char cwd[VFS_PATH_MAX]
Definition sched.h:90
uint64_t brk
Definition sched.h:86
uint64_t mmap_next
Definition sched.h:88
mmap_region_t * mmap_regions
Definition sched.h:89
vfs_file_t * fd_table
Definition sched.h:85
int ref_count
Definition sched.h:83
Definition sched.h:96
volatile uint32_t * futex_uaddr
Definition sched.h:197
uint32_t pgid
Definition sched.h:118
uint32_t cmdline_len
Definition sched.h:208
uint64_t syscall_restart_args[6]
Definition sched.h:165
uint32_t tid
Definition sched.h:97
uint64_t signal_trampoline_va
Definition sched.h:170
uint64_t saved_user_rsi
Definition sched.h:138
uint64_t brk
Definition sched.h:144
struct thread_group * tg
Definition sched.h:188
int64_t ptrace_syscall_ret
Definition sched.h:231
uint64_t saved_user_rfl
Definition sched.h:124
uint64_t itimer_real_interval_ticks
Definition sched.h:160
uint32_t ptrace_tracer_tid
Definition sched.h:229
uint8_t signal_ctx_restart_pending
Definition sched.h:179
struct task_cpu_context ctx
Definition sched.h:99
uint32_t pid
Definition sched.h:116
thread_state_t state
Definition sched.h:98
uint64_t signal_ctx_restart_nr
Definition sched.h:177
uint8_t syscall_restart_pending
Definition sched.h:167
uint64_t itimer_real_deadline_ticks
Definition sched.h:159
uint64_t brk_base
Definition sched.h:145
uint32_t tgid
Definition sched.h:189
uint32_t _tg_pad
Definition sched.h:190
uint64_t syscall_restart_nr
Definition sched.h:164
uint64_t signal_ctx_restart_args[6]
Definition sched.h:178
uint64_t mmap_next
Definition sched.h:151
uint64_t saved_user_r15
Definition sched.h:133
volatile uint32_t * clear_tid_addr
Definition sched.h:200
mmap_region_t * mmap_regions
Definition sched.h:152
uint32_t pending_signals
Definition sched.h:155
struct task_cpu_context * ptrace_trap_ctx
Definition sched.h:245
int exit_code
Definition sched.h:113
uint8_t _signal_ctx_pad[7]
Definition sched.h:180
char cmdline[128]
Definition sched.h:207
uint64_t pml4_phys
Definition sched.h:194
uint64_t user_stack_phys_base
Definition sched.h:104
uint8_t _restart_pad[6]
Definition sched.h:169
uint64_t saved_user_rdx
Definition sched.h:139
char comm[16]
Definition sched.h:206
uint8_t itimer_real_active
Definition sched.h:161
uint8_t stop_signal
Definition sched.h:215
uint64_t signal_ctx_rsp
Definition sched.h:175
struct thread * next
Definition sched.h:101
uint64_t signal_ctx_restart_rip
Definition sched.h:176
uint64_t saved_user_r12
Definition sched.h:130
uint8_t ptrace_stop_reason
Definition sched.h:228
uint32_t sid
Definition sched.h:119
uint8_t ptrace_trace_syscalls
Definition sched.h:227
uint8_t syscall_last_signal
Definition sched.h:168
uint64_t utime_ticks
Definition sched.h:209
uint64_t saved_user_rsp
Definition sched.h:122
char cwd[VFS_PATH_MAX]
Definition sched.h:185
uint32_t parent_tid
Definition sched.h:112
uint64_t ptrace_syscall_nr
Definition sched.h:230
uint64_t user_stack_virt_top
Definition sched.h:105
uint64_t saved_user_rbp
Definition sched.h:128
uint64_t saved_user_rip
Definition sched.h:123
vfs_file_t * fd_table
Definition sched.h:109
uint8_t user_stack_pages
Definition sched.h:106
uint64_t syscall_restart_saved_rip
Definition sched.h:166
uint64_t signal_ctx_rip
Definition sched.h:174
uint8_t ptrace_traced
Definition sched.h:226
uint64_t saved_user_rdi
Definition sched.h:137
uint8_t * stack_base
Definition sched.h:100
mini_sigaction_t signal_actions[32]
Definition sched.h:156
uint64_t saved_user_r14
Definition sched.h:132
uint32_t ppid
Definition sched.h:117
uint64_t saved_user_r13
Definition sched.h:131
uint64_t saved_user_rbx
Definition sched.h:129
unsigned int uint32_t
Definition types.h:34
signed long int int64_t
Definition types.h:36
unsigned long int uint64_t
Definition types.h:37
unsigned char uint8_t
Definition types.h:28
struct vfs_ops vfs_ops_t
#define VFS_PATH_MAX
Definition vfs.h:32
struct vfs_file vfs_file_t
typedef __attribute__