ps+ke: add thread reaping

This commit is contained in:
Loïc Grégoire
2026-06-29 17:12:46 -04:00
parent bf08a9fef2
commit a9c933114d
10 changed files with 140 additions and 46 deletions
+4
View File
@@ -33,6 +33,9 @@ pub const ipl = struct {
pub const thread = struct {
pub const init = p.thread.init;
pub const exit = p.thread.exit;
pub const current = p.thread.current;
pub const reaper_list = &p.thread.reaper_list;
};
pub const dpc = struct {
@@ -51,6 +54,7 @@ pub const sched = struct {
pub const block = p.sched.block;
pub const unblock = p.sched.unblock;
pub const late_init = p.sched.late_init;
pub const yield = p.sched.yield;
};
pub const timer = struct {
+59 -38
View File
@@ -231,6 +231,27 @@ pub fn enqueue(td: *ke.Thread) void {
td.lock.release(ipl);
}
/// Yield on the current CPU.
pub fn yield() void {
const ipl = ke.ipl.raise(.Dispatch);
const td = percpu.local().current_thread.?;
td.lock.acquire_no_ipl();
const cpu = percpu.local();
if (td != cpu.idle_thread and td.state.load(.monotonic) == .Running) {
cpu.queues_lock.acquire_no_ipl();
insert_in_queue(cpu, td, false);
td.cpu = ke.cpu.current();
cpu.queues_lock.release_no_ipl();
}
yield_locked();
// td lock released
ke.ipl.lower(ipl);
}
/// Block the currently running thread.
pub fn block() void {
const ipl = ke.ipl.raise(.Dispatch);
@@ -249,7 +270,44 @@ pub fn block_locked(curtd: *ke.Thread) void {
curtd.sleep_start = ke.time.read_time();
curtd.runq = null;
yield(ke.cpu.current());
yield_locked();
}
/// Yield the current CPU with the current thread already locked at Dispatch IPL.
pub fn yield_locked() void {
const sched_cpu = percpu.local();
sched_cpu.queues_lock.acquire_no_ipl();
const cur = sched_cpu.current_thread;
var next = sched_cpu.next_thread;
if (next != null) {
sched_cpu.next_thread = null;
} else {
// Pick a new thread to run.
next = select_thread(null, sched_cpu, false);
}
if (next == null) {
// Nothing to run, go idle.
next = sched_cpu.idle_thread;
sched_cpu.steal_work = true;
}
sched_cpu.queues_lock.release_no_ipl();
if (next != null and cur.? != next.?) {
// Switch into the thread. Take its lock here to ensure it is not still on its stack.
next.?.lock.acquire_no_ipl();
next.?.lock.release_no_ipl();
do_switch(sched_cpu, cur.?, next.?);
} else {
cur.?.lock.release_no_ipl();
}
// cur lock dropped
}
pub fn unblock_locked(td: *ke.Thread) void {
@@ -856,43 +914,6 @@ fn do_switch(cpu: *PerCpu, cur: *ke.Thread, next: *ke.Thread) void {
cur.context.switch_to(&next.context);
}
// Yield on `cpu`
fn yield(cpu: u32) void {
const sched_cpu = percpu.remote(cpu);
sched_cpu.queues_lock.acquire_no_ipl();
const cur = sched_cpu.current_thread;
var next = sched_cpu.next_thread;
if (next != null) {
sched_cpu.next_thread = null;
} else {
// Pick a new thread to run.
next = select_thread(null, sched_cpu, false);
}
if (next == null) {
// Nothing to run, go idle.
next = sched_cpu.idle_thread;
sched_cpu.steal_work = true;
}
sched_cpu.queues_lock.release_no_ipl();
if (next != null and cur.? != next.?) {
// Switch into the thread. Take its lock here to ensure it is not still on its stack.
next.?.lock.acquire_no_ipl();
next.?.lock.release_no_ipl();
do_switch(sched_cpu, cur.?, next.?);
} else {
cur.?.lock.release_no_ipl();
}
// cur lock dropped
}
fn find_most_loaded(exclude: ?*ke.CpuMask) ?u32 {
var most: ?u32 = null;
var most_load: usize = 0;
+27
View File
@@ -108,6 +108,8 @@ pub const Thread = struct {
/// Queue this thread is associated with.
queue: ?*ke.Queue,
queue_item: ?*rtl.List.Entry,
/// Base of the stack.
stack: r.VAddr,
/// Initialize a thread.
/// - `stack`: Address of the **base** of the stack on which the initial context for the thread is built
@@ -142,6 +144,7 @@ pub const Thread = struct {
.waiting_on = null,
.queue = null,
.queue_item = null,
.stack = stack,
};
thread.turnstiles_owned.init();
@@ -167,3 +170,27 @@ pub const Thread = struct {
return self.priority >= Priority.low_interactive and self.priority <= Priority.high_interactive;
}
};
/// HandoffList of threads waiting to be reaped.
/// This is managed by the process subsystem.
pub var reaper_list: rtl.HandoffList = undefined;
/// Terminate the currently running thread.
/// This does not return.
pub fn exit() void {
_ = ke.ipl.raise(.Dispatch);
const curtd = current();
curtd.lock.acquire_no_ipl();
curtd.state.store(.Zombie, .monotonic);
// Reuse the runq linkage to put on reaper list.
reaper_list.insert(@ptrCast(&curtd.runq_link.next));
ki.sched.yield_locked();
}
/// Return the currently running thread.
pub fn current() *ke.Thread {
return ki.sched.percpu.local().current_thread.?;
}