ke(mutex): do optimistic spinning

This commit is contained in:
Loïc Grégoire
2026-06-14 10:59:23 -04:00
parent 68e0f7f8f7
commit 534a7f2e2c
+10 -3
View File
@@ -2,6 +2,9 @@ const std = @import("std");
const ke = @import("root").ke;
const ki = ke.private;
/// Number of spins before blocking.
const optimistic_spins = 10000;
pub const Mutex = struct {
/// The thread currently holding the mutex, null if unlocked.
owner: std.atomic.Value(?*ke.Thread),
@@ -14,12 +17,16 @@ pub const Mutex = struct {
const ipl = ke.ipl.raise(.Dispatch);
const curtd = ki.sched.percpu.local().current_thread.?;
// Fast path: try to acquire without a turnstile.
// Fast path: try to acquire without a turnstile by spinning a bit.
for (0..optimistic_spins) |_| {
if (m.owner.cmpxchgStrong(null, curtd, .acquire, .monotonic) == null) {
ke.ipl.lower(ipl);
return;
}
std.atomic.spinLoopHint();
}
// Slow path: contended, block on a turnstile.
while (true) {
const ts = ki.turnstile.lookup(m);
@@ -35,7 +42,7 @@ pub const Mutex = struct {
}
// Block until woken.
ki.turnstile.block(ts, m, owner.?, .Shared);
ki.turnstile.block(ts, m, owner.?, .Exclusive);
// Re-try acquisition after wakeup.
if (m.owner.cmpxchgStrong(null, curtd, .acquire, .monotonic) == null) {
@@ -62,7 +69,7 @@ pub const Mutex = struct {
// Note: wake up all waiters. This so-called "lock barging" (name from WTF::ParkingLot)
// has been shown to be better because this avoids lock convoys, see this mysterious 70s paper:
// https://dl.acm.org/doi/pdf/10.1145/850657.850659
ki.turnstile.wakeup(ts.?, .Exlusive, ts.?.waiters, null);
ki.turnstile.wakeup(ts.?, .Exclusive, ts.?.waiters, null);
ke.ipl.lower(ipl);
}