update RwLock to use static initialization (#10838)

This commit is contained in:
billzez 2022-02-08 23:35:48 -05:00 committed by Andrew Kelley
parent 45d4e2f816
commit bf6af1963c
2 changed files with 14 additions and 64 deletions

View File

@ -16,6 +16,7 @@ pub const StaticResetEvent = @import("Thread/StaticResetEvent.zig");
pub const Mutex = @import("Thread/Mutex.zig"); pub const Mutex = @import("Thread/Mutex.zig");
pub const Semaphore = @import("Thread/Semaphore.zig"); pub const Semaphore = @import("Thread/Semaphore.zig");
pub const Condition = @import("Thread/Condition.zig"); pub const Condition = @import("Thread/Condition.zig");
pub const RwLock = @import("Thread/RwLock.zig");
pub const use_pthreads = target.os.tag != .windows and target.os.tag != .wasi and builtin.link_libc; pub const use_pthreads = target.os.tag != .windows and target.os.tag != .wasi and builtin.link_libc;
const is_gnu = target.abi.isGnu(); const is_gnu = target.abi.isGnu();

View File

@ -3,15 +3,12 @@
//! This API requires being initialized at runtime, and initialization //! This API requires being initialized at runtime, and initialization
//! can fail. Once initialized, the core operations cannot fail. //! can fail. Once initialized, the core operations cannot fail.
impl: Impl, impl: Impl = .{},
const RwLock = @This(); const RwLock = @This();
const std = @import("../std.zig"); const std = @import("../std.zig");
const builtin = @import("builtin"); const builtin = @import("builtin");
const assert = std.debug.assert; const assert = std.debug.assert;
const Mutex = std.Thread.Mutex;
const Semaphore = std.Semaphore;
const CondVar = std.CondVar;
pub const Impl = if (builtin.single_threaded) pub const Impl = if (builtin.single_threaded)
SingleThreadedRwLock SingleThreadedRwLock
@ -20,14 +17,6 @@ else if (std.Thread.use_pthreads)
else else
DefaultRwLock; DefaultRwLock;
pub fn init(rwl: *RwLock) void {
return rwl.impl.init();
}
pub fn deinit(rwl: *RwLock) void {
return rwl.impl.deinit();
}
/// Attempts to obtain exclusive lock ownership. /// Attempts to obtain exclusive lock ownership.
/// Returns `true` if the lock is obtained, `false` otherwise. /// Returns `true` if the lock is obtained, `false` otherwise.
pub fn tryLock(rwl: *RwLock) bool { pub fn tryLock(rwl: *RwLock) bool {
@ -64,20 +53,8 @@ pub fn unlockShared(rwl: *RwLock) void {
/// Single-threaded applications use this for deadlock checks in /// Single-threaded applications use this for deadlock checks in
/// debug mode, and no-ops in release modes. /// debug mode, and no-ops in release modes.
pub const SingleThreadedRwLock = struct { pub const SingleThreadedRwLock = struct {
state: enum { unlocked, locked_exclusive, locked_shared }, state: enum { unlocked, locked_exclusive, locked_shared } = .unlocked,
shared_count: usize, shared_count: usize = 0,
pub fn init(rwl: *SingleThreadedRwLock) void {
rwl.* = .{
.state = .unlocked,
.shared_count = 0,
};
}
pub fn deinit(rwl: *SingleThreadedRwLock) void {
assert(rwl.state == .unlocked);
assert(rwl.shared_count == 0);
}
/// Attempts to obtain exclusive lock ownership. /// Attempts to obtain exclusive lock ownership.
/// Returns `true` if the lock is obtained, `false` otherwise. /// Returns `true` if the lock is obtained, `false` otherwise.
@ -152,55 +129,41 @@ pub const SingleThreadedRwLock = struct {
}; };
pub const PthreadRwLock = struct { pub const PthreadRwLock = struct {
rwlock: pthread_rwlock_t, rwlock: std.c.pthread_rwlock_t = .{},
pub fn init(rwl: *PthreadRwLock) void {
rwl.* = .{ .rwlock = .{} };
}
pub fn deinit(rwl: *PthreadRwLock) void {
const safe_rc: std.os.E = switch (builtin.os.tag) {
.dragonfly, .netbsd => .AGAIN,
else => .SUCCESS,
};
const rc = std.c.pthread_rwlock_destroy(&rwl.rwlock);
assert(rc == .SUCCESS or rc == safe_rc);
rwl.* = undefined;
}
pub fn tryLock(rwl: *PthreadRwLock) bool { pub fn tryLock(rwl: *PthreadRwLock) bool {
return pthread_rwlock_trywrlock(&rwl.rwlock) == .SUCCESS; return std.c.pthread_rwlock_trywrlock(&rwl.rwlock) == .SUCCESS;
} }
pub fn lock(rwl: *PthreadRwLock) void { pub fn lock(rwl: *PthreadRwLock) void {
const rc = pthread_rwlock_wrlock(&rwl.rwlock); const rc = std.c.pthread_rwlock_wrlock(&rwl.rwlock);
assert(rc == .SUCCESS); assert(rc == .SUCCESS);
} }
pub fn unlock(rwl: *PthreadRwLock) void { pub fn unlock(rwl: *PthreadRwLock) void {
const rc = pthread_rwlock_unlock(&rwl.rwlock); const rc = std.c.pthread_rwlock_unlock(&rwl.rwlock);
assert(rc == .SUCCESS); assert(rc == .SUCCESS);
} }
pub fn tryLockShared(rwl: *PthreadRwLock) bool { pub fn tryLockShared(rwl: *PthreadRwLock) bool {
return pthread_rwlock_tryrdlock(&rwl.rwlock) == .SUCCESS; return std.c.pthread_rwlock_tryrdlock(&rwl.rwlock) == .SUCCESS;
} }
pub fn lockShared(rwl: *PthreadRwLock) void { pub fn lockShared(rwl: *PthreadRwLock) void {
const rc = pthread_rwlock_rdlock(&rwl.rwlock); const rc = std.c.pthread_rwlock_rdlock(&rwl.rwlock);
assert(rc == .SUCCESS); assert(rc == .SUCCESS);
} }
pub fn unlockShared(rwl: *PthreadRwLock) void { pub fn unlockShared(rwl: *PthreadRwLock) void {
const rc = pthread_rwlock_unlock(&rwl.rwlock); const rc = std.c.pthread_rwlock_unlock(&rwl.rwlock);
assert(rc == .SUCCESS); assert(rc == .SUCCESS);
} }
}; };
pub const DefaultRwLock = struct { pub const DefaultRwLock = struct {
state: usize, state: usize = 0,
mutex: Mutex, mutex: std.Thread.Mutex = .{},
semaphore: Semaphore, semaphore: std.Thread.Semaphore = .{},
const IS_WRITING: usize = 1; const IS_WRITING: usize = 1;
const WRITER: usize = 1 << 1; const WRITER: usize = 1 << 1;
@ -209,20 +172,6 @@ pub const DefaultRwLock = struct {
const READER_MASK: usize = std.math.maxInt(Count) << @ctz(usize, READER); const READER_MASK: usize = std.math.maxInt(Count) << @ctz(usize, READER);
const Count = std.meta.Int(.unsigned, @divFloor(std.meta.bitCount(usize) - 1, 2)); const Count = std.meta.Int(.unsigned, @divFloor(std.meta.bitCount(usize) - 1, 2));
pub fn init(rwl: *DefaultRwLock) void {
rwl.* = .{
.state = 0,
.mutex = Mutex.init(),
.semaphore = Semaphore.init(0),
};
}
pub fn deinit(rwl: *DefaultRwLock) void {
rwl.semaphore.deinit();
rwl.mutex.deinit();
rwl.* = undefined;
}
pub fn tryLock(rwl: *DefaultRwLock) bool { pub fn tryLock(rwl: *DefaultRwLock) bool {
if (rwl.mutex.tryLock()) { if (rwl.mutex.tryLock()) {
const state = @atomicLoad(usize, &rwl.state, .SeqCst); const state = @atomicLoad(usize, &rwl.state, .SeqCst);