| ... | @@ -219,17 +219,23 @@ const WindowsEvent = AtomicEvent(struct { | ... | @@ -219,17 +219,23 @@ const WindowsEvent = AtomicEvent(struct { |
| 219 | return SpinEvent.Futex.wait(ptr, expected, timeout); | 219 | return SpinEvent.Futex.wait(ptr, expected, timeout); |
| 220 | }; | 220 | }; |
| 221 | | 221 | |
| | 222 | // NT uses timeouts in units of 100ns with negative value being relative |
| 222 | var timeout_ptr: ?*windows.LARGE_INTEGER = null; | 223 | var timeout_ptr: ?*windows.LARGE_INTEGER = null; |
| 223 | var timeout_value: windows.LARGE_INTEGER = undefined; | 224 | var timeout_value: windows.LARGE_INTEGER = undefined; |
| 224 | if (timeout) |timeout_ns| { | 225 | if (timeout) |timeout_ns| { |
| 225 | timeout_ptr = &timeout_value; | 226 | timeout_ptr = &timeout_value; |
| 226 | timeout_value = @intCast(windows.LARGE_INTEGER, @divFloor(timeout_ns, time.millisecond)); | 227 | timeout_value = -@intCast(windows.LARGE_INTEGER, timeout_ns / 100); |
| 227 | } | 228 | } |
| 228 | | 229 | |
| 229 | const key = @ptrCast(*const c_void, ptr); | 230 | // NtWaitForKeyedEvent doesnt have spurious wake-ups |
| 230 | while (@atomicLoad(u32, ptr, .Acquire) == expected) { | 231 | if (@atomicLoad(u32, ptr, .Acquire) == expected) { |
| | 232 | const key = @ptrCast(*const c_void, ptr); |
| 231 | const rc = windows.ntdll.NtWaitForKeyedEvent(handle, key, windows.FALSE, timeout_ptr); | 233 | const rc = windows.ntdll.NtWaitForKeyedEvent(handle, key, windows.FALSE, timeout_ptr); |
| 232 | assert(rc == 0); | 234 | switch (rc) { |
| | 235 | 0 => {}, |
| | 236 | windows.WAIT_TIMEOUT => return ResetEvent.WaitError.TimedOut, |
| | 237 | else => unreachable, |
| | 238 | } |
| 233 | } | 239 | } |
| 234 | } | 240 | } |
| 235 | | 241 | |
| ... | @@ -377,10 +383,13 @@ test "std.ResetEvent" { | ... | @@ -377,10 +383,13 @@ test "std.ResetEvent" { |
| 377 | | 383 | |
| 378 | // test waiting timeout | 384 | // test waiting timeout |
| 379 | const delay = 100 * time.millisecond; | 385 | const delay = 100 * time.millisecond; |
| | 386 | const error_margin = 50 * time.millisecond; |
| | 387 | |
| 380 | var timer = time.Timer.start() catch unreachable; | 388 | var timer = time.Timer.start() catch unreachable; |
| 381 | testing.expectError(ResetEvent.WaitError.TimedOut, event.wait(delay)); | 389 | testing.expectError(ResetEvent.WaitError.TimedOut, event.wait(delay)); |
| 382 | const elapsed = timer.read(); | 390 | const elapsed = timer.read(); |
| 383 | testing.expect(elapsed >= delay and elapsed < delay * 2); | 391 | testing.expect(elapsed >= delay - error_margin); |
| | 392 | testing.expect(elapsed <= delay + error_margin); |
| 384 | | 393 | |
| 385 | // test cross thread signaling | 394 | // test cross thread signaling |
| 386 | const Context = struct { | 395 | const Context = struct { |