mirror of
https://github.com/rdmsr/zag.git
synced 2026-11-01 23:58:21 +00:00
ke: fix livelock in turnstile
This commit is contained in:
+23
-5
@@ -135,9 +135,11 @@ fn reboost(ts: *Turnstile, to: *ke.Thread) void {
|
|||||||
/// successive owner until one is already at least as high.
|
/// successive owner until one is already at least as high.
|
||||||
///
|
///
|
||||||
/// Locking:
|
/// Locking:
|
||||||
/// - `root` is held by the caller throughout and never dropped here.
|
/// - `root` is held by the caller on entry and is held again on return.
|
||||||
/// - Any other chain bucket is taken with trylock, failure means restart. At
|
/// - If another chain bucket cannot be trylocked, we drop the current thread
|
||||||
/// most one such bucket is held at a time.
|
/// lock and `root`, then reacquire `root` and restart from `curtd`.
|
||||||
|
/// - Any other chain bucket is taken with trylock. At most one such bucket is
|
||||||
|
/// held at a time.
|
||||||
fn propagate(curtd: *ke.Thread, root: *Chain) void {
|
fn propagate(curtd: *ke.Thread, root: *Chain) void {
|
||||||
var donate = curtd.priority;
|
var donate = curtd.priority;
|
||||||
var thread = curtd;
|
var thread = curtd;
|
||||||
@@ -150,10 +152,26 @@ fn propagate(curtd: *ke.Thread, root: *Chain) void {
|
|||||||
const bucket = &chains[hash_obj(obj)];
|
const bucket = &chains[hash_obj(obj)];
|
||||||
|
|
||||||
// Lock `bucket` and confirm `thread` didn't move before we got it.
|
// Lock `bucket` and confirm `thread` didn't move before we got it.
|
||||||
// If either fails, restart below.
|
// If the trylock fails, drop root and restart from curtd.
|
||||||
|
// If validation fails, restart while still holding root.
|
||||||
const restart = blk: {
|
const restart = blk: {
|
||||||
if (bucket != root) {
|
if (bucket != root) {
|
||||||
if (!bucket.lock.try_acquire_no_ipl()) break :blk true;
|
if (!bucket.lock.try_acquire_no_ipl()) {
|
||||||
|
std.debug.assert(held == null);
|
||||||
|
|
||||||
|
// Drop everything and try again. This avoids a livelock
|
||||||
|
// between two PI walks holding different roots and trying to
|
||||||
|
// acquire each other.
|
||||||
|
thread.lock.release_no_ipl();
|
||||||
|
root.lock.release_no_ipl();
|
||||||
|
|
||||||
|
root.lock.acquire_no_ipl();
|
||||||
|
curtd.lock.acquire_no_ipl();
|
||||||
|
|
||||||
|
thread = curtd;
|
||||||
|
donate = curtd.priority;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
held = bucket;
|
held = bucket;
|
||||||
}
|
}
|
||||||
break :blk thread.waiting_on != obj;
|
break :blk thread.waiting_on != obj;
|
||||||
|
|||||||
Reference in New Issue
Block a user