|
const std = @import("../std.zig");
const builtin = @import("builtin");
const assert = std.debug.assert;
const testing = std.testing;
const mem = std.mem;
const Loop = std.event.Loop;
|
LockThread-safe async/await lock. Functions which are waiting for the lock are suspended, and are resumed when the lock is released, in order. Allows only one actor to hold the lock. TODO: make this API also work in blocking I/O mode. |
pub const Lock = struct {
mutex: std.Thread.Mutex = std.Thread.Mutex{},
head: usize = UNLOCKED,
const UNLOCKED = 0;
const LOCKED = 1;
const global_event_loop = Loop.instance orelse
@compileError("std.event.Lock currently only works with event-based I/O");
const Waiter = struct {
// forced Waiter alignment to ensure it doesn't clash with LOCKED
next: ?*Waiter align(2),
tail: *Waiter,
node: Loop.NextTickNode,
};
|
initLocked() |
pub fn initLocked() Lock {
return Lock{ .head = LOCKED };
}
|
acquire() |
pub fn acquire(self: *Lock) Held {
self.mutex.lock();
// self.head transitions from multiple stages depending on the value:
// UNLOCKED -> LOCKED:
// acquire Lock ownership when there are no waiters
// LOCKED -> |
release() |
pub fn release(self: Held) void {
const waiter = blk: {
self.lock.mutex.lock();
defer self.lock.mutex.unlock();
// self.head goes through the reverse transition from acquire():
// -> |
Test:std.event.Lock |
test "std.event.Lock" {
if (!std.io.is_async) return error.SkipZigTest;
// TODO https://github.com/ziglang/zig/issues/1908
if (builtin.single_threaded) return error.SkipZigTest;
// TODO https://github.com/ziglang/zig/issues/3251
if (builtin.os.tag == .freebsd) return error.SkipZigTest;
var lock = Lock{};
testLock(&lock);
const expected_result = [1]i32{3 * @as(i32, @intCast(shared_test_data.len))} ** shared_test_data.len;
try testing.expectEqualSlices(i32, &expected_result, &shared_test_data);
}
fn testLock(lock: *Lock) void {
var handle1 = async lockRunner(lock);
var handle2 = async lockRunner(lock);
var handle3 = async lockRunner(lock);
await handle1;
await handle2;
await handle3;
}
var shared_test_data = [1]i32{0} ** 10;
var shared_test_index: usize = 0;
fn lockRunner(lock: *Lock) void {
Lock.global_event_loop.yield();
var i: usize = 0;
while (i < shared_test_data.len) : (i += 1) {
const handle = lock.acquire();
defer handle.release();
shared_test_index = 0;
while (shared_test_index < shared_test_data.len) : (shared_test_index += 1) {
shared_test_data[shared_test_index] = shared_test_data[shared_test_index] + 1;
}
}
}
|
| Generated by zstd-browse2 on 2023-11-04 14:12:31 -0400. |