mirror of
https://github.com/rdmsr/zag.git
synced 2026-10-27 13:58:20 +00:00
ke: make getting the current thread atomic
This commit is contained in:
@@ -246,3 +246,10 @@ pub inline fn lower_software_ipl(new: ke.Ipl, old: *ke.Ipl) bool {
|
|||||||
[old_ptr] "r" (old),
|
[old_ptr] "r" (old),
|
||||||
: .{ .rcx = true, .memory = true });
|
: .{ .rcx = true, .memory = true });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub inline fn current_thread() ?*ke.Thread {
|
||||||
|
return @ptrFromInt(asm volatile (
|
||||||
|
\\mov %%gs:current_thread, %[ret]
|
||||||
|
: [ret] "=r" (-> u64),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|||||||
@@ -95,8 +95,8 @@ pub fn ap_entry(cpu_id: u32, booted: *std.atomic.Value(usize)) noreturn {
|
|||||||
|
|
||||||
const sched = kep.sched.percpu.local();
|
const sched = kep.sched.percpu.local();
|
||||||
|
|
||||||
sched.current_thread = pl.impl.smp.start_thread.local().*;
|
kep.sched.current_thread.local().* = pl.impl.smp.start_thread.local().*;
|
||||||
sched.idle_thread = sched.current_thread;
|
sched.idle_thread = kep.thread.current();
|
||||||
|
|
||||||
amd64.sti();
|
amd64.sti();
|
||||||
|
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ fn dispatch_queue(cpu: u32) void {
|
|||||||
kep.shootdown.process_shootdowns();
|
kep.shootdown.process_shootdowns();
|
||||||
|
|
||||||
if (sched_cpu.next_thread != null) {
|
if (sched_cpu.next_thread != null) {
|
||||||
const curtd = sched_cpu.current_thread orelse unreachable;
|
const curtd = ke.thread.current();
|
||||||
|
|
||||||
if (!curtd.smr_sections.is_empty()) {
|
if (!curtd.smr_sections.is_empty()) {
|
||||||
kep.smr.mark_thread_stalled(curtd);
|
kep.smr.mark_thread_stalled(curtd);
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ fn init() linksection(r.init) void {
|
|||||||
kep.cpu.init_cpu(0);
|
kep.cpu.init_cpu(0);
|
||||||
kep.turnstile.init_turnstiles();
|
kep.turnstile.init_turnstiles();
|
||||||
|
|
||||||
kep.sched.percpu.local().current_thread = &thread0;
|
kep.sched.current_thread.local().* = &thread0;
|
||||||
kep.sched.percpu.local().idle_thread = &thread0;
|
kep.sched.percpu.local().idle_thread = &thread0;
|
||||||
|
|
||||||
std.log.info("Zag for {s} ({s}), cmdline is \"{?s}\"", .{
|
std.log.info("Zag for {s} ({s}), cmdline is \"{?s}\"", .{
|
||||||
|
|||||||
@@ -32,9 +32,7 @@ pub const Mutex = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn acquire(m: *Mutex) void {
|
pub fn acquire(m: *Mutex) void {
|
||||||
const ipl = ke.ipl.raise(.Dispatch);
|
const curtd = ke.thread.current();
|
||||||
const curtd = kep.sched.percpu.local().current_thread orelse
|
|
||||||
unreachable;
|
|
||||||
|
|
||||||
if (config.warden) {
|
if (config.warden) {
|
||||||
kep.warden.check(m.wd, .Lock);
|
kep.warden.check(m.wd, .Lock);
|
||||||
@@ -54,7 +52,6 @@ pub const Mutex = struct {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (cur_owner == null) {
|
if (cur_owner == null) {
|
||||||
ke.ipl.lower(ipl);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,10 +71,11 @@ pub const Mutex = struct {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ke.ipl.lower(ipl);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ipl = ke.ipl.raise(.Dispatch);
|
||||||
|
|
||||||
// Slow path: contended, block on a turnstile.
|
// Slow path: contended, block on a turnstile.
|
||||||
while (true) {
|
while (true) {
|
||||||
const ts = kep.turnstile.lookup(m);
|
const ts = kep.turnstile.lookup(m);
|
||||||
|
|||||||
@@ -74,6 +74,13 @@ const ImplSchema = struct {
|
|||||||
_ = old;
|
_ = old;
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return a pointer to the current thread.
|
||||||
|
/// This must be atomic with regards to migration (i.e this should be a
|
||||||
|
/// consistent pointer no matter what).
|
||||||
|
pub fn current_thread() ?*ke.Thread {
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
comptime {
|
comptime {
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ pub const Queue = struct {
|
|||||||
/// This blocks until an item is actually popped.
|
/// This blocks until an item is actually popped.
|
||||||
pub fn remove(self: *Queue, timeout: ?rtl.Duration) !*rtl.List.Entry {
|
pub fn remove(self: *Queue, timeout: ?rtl.Duration) !*rtl.List.Entry {
|
||||||
const ipl = self.hdr.lock.acquire();
|
const ipl = self.hdr.lock.acquire();
|
||||||
const td = kep.sched.percpu.local().current_thread orelse unreachable;
|
const td = ke.thread.current();
|
||||||
|
|
||||||
if (td.queue) |q| {
|
if (td.queue) |q| {
|
||||||
assert(q == self);
|
assert(q == self);
|
||||||
|
|||||||
+14
-12
@@ -208,8 +208,6 @@ pub const PerCpu = struct {
|
|||||||
start_timer: bool,
|
start_timer: bool,
|
||||||
/// The reason why the current thread was preempted.
|
/// The reason why the current thread was preempted.
|
||||||
preemption_reason: PreemptionReason,
|
preemption_reason: PreemptionReason,
|
||||||
/// Currently running thread.
|
|
||||||
current_thread: ?*ke.Thread,
|
|
||||||
/// Per-CPU idle thread.
|
/// Per-CPU idle thread.
|
||||||
idle_thread: ?*ke.Thread,
|
idle_thread: ?*ke.Thread,
|
||||||
/// Thread selected for preemption.
|
/// Thread selected for preemption.
|
||||||
@@ -242,6 +240,11 @@ pub const Accounting = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const percpu = ke.CpuLocalType(PerCpu, undefined);
|
pub const percpu = ke.CpuLocalType(PerCpu, undefined);
|
||||||
|
pub const current_thread = ke.ExportedCpuLocalType(
|
||||||
|
?*ke.Thread,
|
||||||
|
null,
|
||||||
|
"current_thread",
|
||||||
|
);
|
||||||
|
|
||||||
var balance_timer: ke.Timer = undefined;
|
var balance_timer: ke.Timer = undefined;
|
||||||
var balance_dpc = ke.Dpc.init(balance);
|
var balance_dpc = ke.Dpc.init(balance);
|
||||||
@@ -276,7 +279,6 @@ fn init_cpu() linksection(r.init) void {
|
|||||||
.resched_timer = undefined,
|
.resched_timer = undefined,
|
||||||
.start_timer = false,
|
.start_timer = false,
|
||||||
.preemption_reason = .None,
|
.preemption_reason = .None,
|
||||||
.current_thread = null,
|
|
||||||
.idle_thread = null,
|
.idle_thread = null,
|
||||||
.next_thread = null,
|
.next_thread = null,
|
||||||
.pick_offset = 0,
|
.pick_offset = 0,
|
||||||
@@ -1022,7 +1024,7 @@ fn enqueue_on_cpu(c: u32, td: *ke.Thread) void {
|
|||||||
|
|
||||||
attach_load_avg(cpu, td);
|
attach_load_avg(cpu, td);
|
||||||
|
|
||||||
if (cpu.current_thread != null and
|
if (current_thread.local().* != null and
|
||||||
should_preempt_cpu(td, cpu, c != ke.cpu.current()))
|
should_preempt_cpu(td, cpu, c != ke.cpu.current()))
|
||||||
{
|
{
|
||||||
// We can preempt the current thread, first check whether or not there
|
// We can preempt the current thread, first check whether or not there
|
||||||
@@ -1088,8 +1090,8 @@ fn allocate_stack(td: *ke.Thread) ?usize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Execute a context switch on `cpu`.
|
// Execute a context switch on `cpu`.
|
||||||
fn do_switch(cpu: *PerCpu, cur: *ke.Thread, next: *ke.Thread) void {
|
fn do_switch(cur: *ke.Thread, next: *ke.Thread) void {
|
||||||
cpu.current_thread = next;
|
current_thread.local().* = next;
|
||||||
next.last_cpu = ke.cpu.current();
|
next.last_cpu = ke.cpu.current();
|
||||||
|
|
||||||
const time = ke.time.read_time();
|
const time = ke.time.read_time();
|
||||||
@@ -1153,7 +1155,7 @@ fn do_switch(cpu: *PerCpu, cur: *ke.Thread, next: *ke.Thread) void {
|
|||||||
/// Handle preemption.
|
/// Handle preemption.
|
||||||
/// This is called in DPC dispatch when it notices `next_thread` is set.
|
/// This is called in DPC dispatch when it notices `next_thread` is set.
|
||||||
pub fn handle_preemption(cpu: *PerCpu) void {
|
pub fn handle_preemption(cpu: *PerCpu) void {
|
||||||
const cur = cpu.current_thread orelse unreachable;
|
const cur = ke.thread.current();
|
||||||
var next: *ke.Thread = undefined;
|
var next: *ke.Thread = undefined;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -1220,7 +1222,7 @@ pub fn handle_preemption(cpu: *PerCpu) void {
|
|||||||
std.atomic.spinLoopHint();
|
std.atomic.spinLoopHint();
|
||||||
}
|
}
|
||||||
|
|
||||||
do_switch(cpu, cur, next);
|
do_switch(cur, next);
|
||||||
|
|
||||||
// cur.lock dropped
|
// cur.lock dropped
|
||||||
}
|
}
|
||||||
@@ -1230,7 +1232,7 @@ pub fn clock(_: *ke.Dpc, _: ?*anyopaque) void {
|
|||||||
const cpu = percpu.local();
|
const cpu = percpu.local();
|
||||||
assert(kep.ipl.current() == .Dispatch);
|
assert(kep.ipl.current() == .Dispatch);
|
||||||
|
|
||||||
const curtd = cpu.current_thread orelse return;
|
const curtd = current_thread.local().* orelse return;
|
||||||
|
|
||||||
const now = ke.time.read_time();
|
const now = ke.time.read_time();
|
||||||
const now_us = now.to_us();
|
const now_us = now.to_us();
|
||||||
@@ -1292,7 +1294,7 @@ pub fn enqueue(td: *ke.Thread) void {
|
|||||||
/// Yield on the current CPU.
|
/// Yield on the current CPU.
|
||||||
pub fn yield(continuation: ?ke.Continuation) void {
|
pub fn yield(continuation: ?ke.Continuation) void {
|
||||||
const ipl = ke.ipl.raise(.Dispatch);
|
const ipl = ke.ipl.raise(.Dispatch);
|
||||||
const td = percpu.local().current_thread orelse unreachable;
|
const td = ke.thread.current();
|
||||||
|
|
||||||
td.lock.acquire_no_ipl();
|
td.lock.acquire_no_ipl();
|
||||||
td.switching.store(true, .monotonic);
|
td.switching.store(true, .monotonic);
|
||||||
@@ -1317,7 +1319,7 @@ pub fn yield_locked(continuation: ?ke.Continuation) void {
|
|||||||
|
|
||||||
sched_cpu.queues_lock.acquire_no_ipl();
|
sched_cpu.queues_lock.acquire_no_ipl();
|
||||||
|
|
||||||
const cur = sched_cpu.current_thread orelse unreachable;
|
const cur = ke.thread.current();
|
||||||
var next = sched_cpu.next_thread;
|
var next = sched_cpu.next_thread;
|
||||||
|
|
||||||
cur.continuation = continuation;
|
cur.continuation = continuation;
|
||||||
@@ -1386,7 +1388,7 @@ pub fn yield_locked(continuation: ?ke.Continuation) void {
|
|||||||
while (n.switching.load(.monotonic) == true) {
|
while (n.switching.load(.monotonic) == true) {
|
||||||
std.atomic.spinLoopHint();
|
std.atomic.spinLoopHint();
|
||||||
}
|
}
|
||||||
do_switch(sched_cpu, cur, n);
|
do_switch(cur, n);
|
||||||
} else {
|
} else {
|
||||||
// Same thread.
|
// Same thread.
|
||||||
cur.state.store(.Running, .monotonic);
|
cur.state.store(.Running, .monotonic);
|
||||||
|
|||||||
@@ -316,7 +316,7 @@ pub fn exit() void {
|
|||||||
|
|
||||||
/// Return the currently running thread.
|
/// Return the currently running thread.
|
||||||
pub fn current() *ke.Thread {
|
pub fn current() *ke.Thread {
|
||||||
return kep.sched.percpu.local().current_thread orelse unreachable;
|
return kep.impl.current_thread() orelse unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -- Stack allocation and continuations ---------------------------------------
|
// -- Stack allocation and continuations ---------------------------------------
|
||||||
|
|||||||
@@ -443,7 +443,7 @@ pub fn block(
|
|||||||
queue: Queue,
|
queue: Queue,
|
||||||
) void {
|
) void {
|
||||||
const chain = chain_for(obj);
|
const chain = chain_for(obj);
|
||||||
const curtd = kep.sched.percpu.local().current_thread.?;
|
const curtd = ke.thread.current();
|
||||||
const ipl = ke.ipl.current();
|
const ipl = ke.ipl.current();
|
||||||
|
|
||||||
var ts = turnstile;
|
var ts = turnstile;
|
||||||
|
|||||||
Reference in New Issue
Block a user