mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
std.Io.Threaded: tune requestCancel
On a heavily loaded Linux 6.17.5, I observed a maximum of 20 attempts not acknowledged before the timeout (including exponential backoff) was sufficient, despite the heavy load. The time wasted here sleeping is mitigated by the fact that, later on, the system will likely wait for the canceled task, causing it to indefinitely yield until the canceled task finishes, and the task must acknowledge the cancel before it proceeds to that point.
This commit is contained in:
parent
29e418cbfb
commit
d60760d61e
1 changed files with 22 additions and 5 deletions
|
|
@ -201,8 +201,22 @@ const Closure = struct {
|
||||||
// We can send a signal to interrupt the syscall, but if it arrives before
|
// We can send a signal to interrupt the syscall, but if it arrives before
|
||||||
// the syscall instruction, it will be missed. Therefore, this code tries
|
// the syscall instruction, it will be missed. Therefore, this code tries
|
||||||
// again until the cancellation request is acknowledged.
|
// again until the cancellation request is acknowledged.
|
||||||
const max_attempts = 3;
|
|
||||||
for (0..max_attempts) |_| {
|
// 1 << 10 ns is about 1 microsecond, approximately syscall overhead.
|
||||||
|
// 1 << 20 ns is about 1 millisecond.
|
||||||
|
// 1 << 30 ns is about 1 second.
|
||||||
|
//
|
||||||
|
// On a heavily loaded Linux 6.17.5, I observed a maximum of 20
|
||||||
|
// attempts not acknowledged before the timeout (including exponential
|
||||||
|
// backoff) was sufficient, despite the heavy load.
|
||||||
|
//
|
||||||
|
// The time wasted here sleeping is mitigated by the fact that, later
|
||||||
|
// on, the system will likely wait for the canceled task, causing it
|
||||||
|
// to indefinitely yield until the canceled task finishes, and the
|
||||||
|
// task must acknowledge the cancel before it proceeds to that point.
|
||||||
|
const max_attempts = 22;
|
||||||
|
|
||||||
|
for (0..max_attempts) |attempt_index| {
|
||||||
if (std.Thread.use_pthreads) {
|
if (std.Thread.use_pthreads) {
|
||||||
const rc = std.c.pthread_kill(signal_id, .IO);
|
const rc = std.c.pthread_kill(signal_id, .IO);
|
||||||
if (is_debug) assert(rc == 0);
|
if (is_debug) assert(rc == 0);
|
||||||
|
|
@ -219,11 +233,14 @@ const Closure = struct {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO make this a nanosleep with 1 << attempt duration
|
var timespec: posix.timespec = .{
|
||||||
std.Thread.yield() catch {};
|
.sec = 0,
|
||||||
|
.nsec = @as(isize, 1) << @intCast(attempt_index),
|
||||||
|
};
|
||||||
|
_ = posix.system.nanosleep(×pec, ×pec);
|
||||||
|
|
||||||
switch (@atomicRmw(CancelStatus, &closure.cancel_status, .Xchg, .requested, .monotonic).unpack()) {
|
switch (@atomicRmw(CancelStatus, &closure.cancel_status, .Xchg, .requested, .monotonic).unpack()) {
|
||||||
.requested => continue,
|
.requested => continue, // Retry needed in case other thread hasn't yet entered the syscall.
|
||||||
.none, .acknowledged => return,
|
.none, .acknowledged => return,
|
||||||
.signal_id => |new_signal_id| signal_id = new_signal_id,
|
.signal_id => |new_signal_id| signal_id = new_signal_id,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue