| ... | ... | @@ -1,6 +1,23 @@ |
| 1 | 1 | //! A semaphore is an unsigned integer that blocks the kernel thread if |
| 2 | 2 | //! the number would become negative. |
| 3 | 3 | //! This API supports static initialization and does not require deinitialization. |
| 4 | //! |
| 5 | //! Example: |
| 6 | //! ``` |
| 7 | //! var s = Semaphore{}; |
| 8 | //! |
| 9 | //! fn consumer() void { |
| 10 | //! s.wait(); |
| 11 | //! } |
| 12 | //! |
| 13 | //! fn producer() void { |
| 14 | //! s.post(); |
| 15 | //! } |
| 16 | //! |
| 17 | //! const thread = try std.Thread.spawn(.{}, producer, .{}); |
| 18 | //! consumer(); |
| 19 | //! thread.join(); |
| 20 | //! ``` |
| 4 | 21 | |
| 5 | 22 | mutex: Mutex = .{}, |
| 6 | 23 | cond: Condition = .{}, |
| ... | ... | @@ -26,6 +43,26 @@ pub fn wait(sem: *Semaphore) void { |
| 26 | 43 | sem.cond.signal(); |
| 27 | 44 | } |
| 28 | 45 | |
| 46 | pub fn timedWait(sem: *Semaphore, timeout_ns: u64) error{Timeout}!void { |
| 47 | var timeout_timer = std.time.Timer.start() catch unreachable; |
| 48 | |
| 49 | sem.mutex.lock(); |
| 50 | defer sem.mutex.unlock(); |
| 51 | |
| 52 | while (sem.permits == 0) { |
| 53 | const elapsed = timeout_timer.read(); |
| 54 | if (elapsed > timeout_ns) |
| 55 | return error.Timeout; |
| 56 | |
| 57 | const local_timeout_ns = timeout_ns - elapsed; |
| 58 | try sem.cond.timedWait(&sem.mutex, local_timeout_ns); |
| 59 | } |
| 60 | |
| 61 | sem.permits -= 1; |
| 62 | if (sem.permits > 0) |
| 63 | sem.cond.signal(); |
| 64 | } |
| 65 | |
| 29 | 66 | pub fn post(sem: *Semaphore) void { |
| 30 | 67 | sem.mutex.lock(); |
| 31 | 68 | defer sem.mutex.unlock(); |
| ... | ... | @@ -59,3 +96,16 @@ test "Thread.Semaphore" { |
| 59 | 96 | sem.wait(); |
| 60 | 97 | try testing.expect(n == num_threads); |
| 61 | 98 | } |
| 99 | |
| 100 | test "Thread.Semaphore - timedWait" { |
| 101 | var sem = Semaphore{}; |
| 102 | try testing.expectEqual(0, sem.permits); |
| 103 | |
| 104 | try testing.expectError(error.Timeout, sem.timedWait(1)); |
| 105 | |
| 106 | sem.post(); |
| 107 | try testing.expectEqual(1, sem.permits); |
| 108 | |
| 109 | try sem.timedWait(1); |
| 110 | try testing.expectEqual(0, sem.permits); |
| 111 | } |