| ... | ... | @@ -201,8 +201,22 @@ const Closure = struct { |
| 201 | 201 | // We can send a signal to interrupt the syscall, but if it arrives before |
| 202 | 202 | // the syscall instruction, it will be missed. Therefore, this code tries |
| 203 | 203 | // again until the cancellation request is acknowledged. |
| 204 | | const max_attempts = 3; |
| 205 | | for (0..max_attempts) |_| { |
| 204 | |
| 205 | // 1 << 10 ns is about 1 microsecond, approximately syscall overhead. |
| 206 | // 1 << 20 ns is about 1 millisecond. |
| 207 | // 1 << 30 ns is about 1 second. |
| 208 | // |
| 209 | // On a heavily loaded Linux 6.17.5, I observed a maximum of 20 |
| 210 | // attempts not acknowledged before the timeout (including exponential |
| 211 | // backoff) was sufficient, despite the heavy load. |
| 212 | // |
| 213 | // The time wasted here sleeping is mitigated by the fact that, later |
| 214 | // on, the system will likely wait for the canceled task, causing it |
| 215 | // to indefinitely yield until the canceled task finishes, and the |
| 216 | // task must acknowledge the cancel before it proceeds to that point. |
| 217 | const max_attempts = 22; |
| 218 | |
| 219 | for (0..max_attempts) |attempt_index| { |
| 206 | 220 | if (std.Thread.use_pthreads) { |
| 207 | 221 | const rc = std.c.pthread_kill(signal_id, .IO); |
| 208 | 222 | if (is_debug) assert(rc == 0); |
| ... | ... | @@ -219,11 +233,14 @@ const Closure = struct { |
| 219 | 233 | return; |
| 220 | 234 | } |
| 221 | 235 | |
| 222 | | // TODO make this a nanosleep with 1 << attempt duration |
| 223 | | std.Thread.yield() catch {}; |
| 236 | var timespec: posix.timespec = .{ |
| 237 | .sec = 0, |
| 238 | .nsec = @as(isize, 1) << @intCast(attempt_index), |
| 239 | }; |
| 240 | _ = posix.system.nanosleep(&timespec, &timespec); |
| 224 | 241 | |
| 225 | 242 | switch (@atomicRmw(CancelStatus, &closure.cancel_status, .Xchg, .requested, .monotonic).unpack()) { |
| 226 | | .requested => continue, |
| 243 | .requested => continue, // Retry needed in case other thread hasn't yet entered the syscall. |
| 227 | 244 | .none, .acknowledged => return, |
| 228 | 245 | .signal_id => |new_signal_id| signal_id = new_signal_id, |
| 229 | 246 | } |