diff --git a/lib/std/Thread/Semaphore.zig b/lib/std/Thread/Semaphore.zig index 1b182d4c2a..3253d17a8e 100644 --- a/lib/std/Thread/Semaphore.zig +++ b/lib/std/Thread/Semaphore.zig @@ -1,6 +1,23 @@ //! A semaphore is an unsigned integer that blocks the kernel thread if //! the number would become negative. //! This API supports static initialization and does not require deinitialization. +//! +//! Example: +//! ``` +//! var s = Semaphore{}; +//! +//! fn consumer() void { +//! s.wait(); +//! } +//! +//! fn producer() void { +//! s.post(); +//! } +//! +//! const thread = try std.Thread.spawn(.{}, producer, .{}); +//! consumer(); +//! thread.join(); +//! ``` mutex: Mutex = .{}, cond: Condition = .{}, @@ -26,6 +43,26 @@ pub fn wait(sem: *Semaphore) void { sem.cond.signal(); } +pub fn timedWait(sem: *Semaphore, timeout_ns: u64) error{Timeout}!void { + var timeout_timer = std.time.Timer.start() catch unreachable; + + sem.mutex.lock(); + defer sem.mutex.unlock(); + + while (sem.permits == 0) { + const elapsed = timeout_timer.read(); + if (elapsed > timeout_ns) + return error.Timeout; + + const local_timeout_ns = timeout_ns - elapsed; + try sem.cond.timedWait(&sem.mutex, local_timeout_ns); + } + + sem.permits -= 1; + if (sem.permits > 0) + sem.cond.signal(); +} + pub fn post(sem: *Semaphore) void { sem.mutex.lock(); defer sem.mutex.unlock(); @@ -59,3 +96,16 @@ test "Thread.Semaphore" { sem.wait(); try testing.expect(n == num_threads); } + +test "Thread.Semaphore - timedWait" { + var sem = Semaphore{}; + try testing.expectEqual(0, sem.permits); + + try testing.expectError(error.Timeout, sem.timedWait(1)); + + sem.post(); + try testing.expectEqual(1, sem.permits); + + try sem.timedWait(1); + try testing.expectEqual(0, sem.permits); +}