| ... | @@ -1,6 +1,23 @@ | ... | @@ -1,6 +1,23 @@ |
| 1 | //! A semaphore is an unsigned integer that blocks the kernel thread if | 1 | //! A semaphore is an unsigned integer that blocks the kernel thread if |
| 2 | //! the number would become negative. | 2 | //! the number would become negative. |
| 3 | //! This API supports static initialization and does not require deinitialization. | 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 | mutex: Mutex = .{}, | 22 | mutex: Mutex = .{}, |
| 6 | cond: Condition = .{}, | 23 | cond: Condition = .{}, |
| ... | @@ -26,6 +43,26 @@ pub fn wait(sem: *Semaphore) void { | ... | @@ -26,6 +43,26 @@ pub fn wait(sem: *Semaphore) void { |
| 26 | sem.cond.signal(); | 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 | pub fn post(sem: *Semaphore) void { | 66 | pub fn post(sem: *Semaphore) void { |
| 30 | sem.mutex.lock(); | 67 | sem.mutex.lock(); |
| 31 | defer sem.mutex.unlock(); | 68 | defer sem.mutex.unlock(); |
| ... | @@ -59,3 +96,16 @@ test "Thread.Semaphore" { | ... | @@ -59,3 +96,16 @@ test "Thread.Semaphore" { |
| 59 | sem.wait(); | 96 | sem.wait(); |
| 60 | try testing.expect(n == num_threads); | 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 | } |