| ... | @@ -3,15 +3,12 @@ | ... | @@ -3,15 +3,12 @@ |
| 3 | //! This API requires being initialized at runtime, and initialization | 3 | //! This API requires being initialized at runtime, and initialization |
| 4 | //! can fail. Once initialized, the core operations cannot fail. | 4 | //! can fail. Once initialized, the core operations cannot fail. |
| 5 | | 5 | |
| 6 | impl: Impl, | 6 | impl: Impl = .{}, |
| 7 | | 7 | |
| 8 | const RwLock = @This(); | 8 | const RwLock = @This(); |
| 9 | const std = @import("../std.zig"); | 9 | const std = @import("../std.zig"); |
| 10 | const builtin = @import("builtin"); | 10 | const builtin = @import("builtin"); |
| 11 | const assert = std.debug.assert; | 11 | const assert = std.debug.assert; |
| 12 | const Mutex = std.Thread.Mutex; | | |
| 13 | const Semaphore = std.Semaphore; | | |
| 14 | const CondVar = std.CondVar; | | |
| 15 | | 12 | |
| 16 | pub const Impl = if (builtin.single_threaded) | 13 | pub const Impl = if (builtin.single_threaded) |
| 17 | SingleThreadedRwLock | 14 | SingleThreadedRwLock |
| ... | @@ -20,14 +17,6 @@ else if (std.Thread.use_pthreads) | ... | @@ -20,14 +17,6 @@ else if (std.Thread.use_pthreads) |
| 20 | else | 17 | else |
| 21 | DefaultRwLock; | 18 | DefaultRwLock; |
| 22 | | 19 | |
| 23 | pub fn init(rwl: *RwLock) void { | | |
| 24 | return rwl.impl.init(); | | |
| 25 | } | | |
| 26 | | | |
| 27 | pub fn deinit(rwl: *RwLock) void { | | |
| 28 | return rwl.impl.deinit(); | | |
| 29 | } | | |
| 30 | | | |
| 31 | /// Attempts to obtain exclusive lock ownership. | 20 | /// Attempts to obtain exclusive lock ownership. |
| 32 | /// Returns `true` if the lock is obtained, `false` otherwise. | 21 | /// Returns `true` if the lock is obtained, `false` otherwise. |
| 33 | pub fn tryLock(rwl: *RwLock) bool { | 22 | pub fn tryLock(rwl: *RwLock) bool { |
| ... | @@ -64,20 +53,8 @@ pub fn unlockShared(rwl: *RwLock) void { | ... | @@ -64,20 +53,8 @@ pub fn unlockShared(rwl: *RwLock) void { |
| 64 | /// Single-threaded applications use this for deadlock checks in | 53 | /// Single-threaded applications use this for deadlock checks in |
| 65 | /// debug mode, and no-ops in release modes. | 54 | /// debug mode, and no-ops in release modes. |
| 66 | pub const SingleThreadedRwLock = struct { | 55 | pub const SingleThreadedRwLock = struct { |
| 67 | state: enum { unlocked, locked_exclusive, locked_shared }, | 56 | state: enum { unlocked, locked_exclusive, locked_shared } = .unlocked, |
| 68 | shared_count: usize, | 57 | shared_count: usize = 0, |
| 69 | | | |
| 70 | pub fn init(rwl: *SingleThreadedRwLock) void { | | |
| 71 | rwl.* = .{ | | |
| 72 | .state = .unlocked, | | |
| 73 | .shared_count = 0, | | |
| 74 | }; | | |
| 75 | } | | |
| 76 | | | |
| 77 | pub fn deinit(rwl: *SingleThreadedRwLock) void { | | |
| 78 | assert(rwl.state == .unlocked); | | |
| 79 | assert(rwl.shared_count == 0); | | |
| 80 | } | | |
| 81 | | 58 | |
| 82 | /// Attempts to obtain exclusive lock ownership. | 59 | /// Attempts to obtain exclusive lock ownership. |
| 83 | /// Returns `true` if the lock is obtained, `false` otherwise. | 60 | /// Returns `true` if the lock is obtained, `false` otherwise. |
| ... | @@ -152,55 +129,41 @@ pub const SingleThreadedRwLock = struct { | ... | @@ -152,55 +129,41 @@ pub const SingleThreadedRwLock = struct { |
| 152 | }; | 129 | }; |
| 153 | | 130 | |
| 154 | pub const PthreadRwLock = struct { | 131 | pub const PthreadRwLock = struct { |
| 155 | rwlock: pthread_rwlock_t, | 132 | rwlock: std.c.pthread_rwlock_t = .{}, |
| 156 | | | |
| 157 | pub fn init(rwl: *PthreadRwLock) void { | | |
| 158 | rwl.* = .{ .rwlock = .{} }; | | |
| 159 | } | | |
| 160 | | | |
| 161 | pub fn deinit(rwl: *PthreadRwLock) void { | | |
| 162 | const safe_rc: std.os.E = switch (builtin.os.tag) { | | |
| 163 | .dragonfly, .netbsd => .AGAIN, | | |
| 164 | else => .SUCCESS, | | |
| 165 | }; | | |
| 166 | const rc = std.c.pthread_rwlock_destroy(&rwl.rwlock); | | |
| 167 | assert(rc == .SUCCESS or rc == safe_rc); | | |
| 168 | rwl.* = undefined; | | |
| 169 | } | | |
| 170 | | 133 | |
| 171 | pub fn tryLock(rwl: *PthreadRwLock) bool { | 134 | pub fn tryLock(rwl: *PthreadRwLock) bool { |
| 172 | return pthread_rwlock_trywrlock(&rwl.rwlock) == .SUCCESS; | 135 | return std.c.pthread_rwlock_trywrlock(&rwl.rwlock) == .SUCCESS; |
| 173 | } | 136 | } |
| 174 | | 137 | |
| 175 | pub fn lock(rwl: *PthreadRwLock) void { | 138 | pub fn lock(rwl: *PthreadRwLock) void { |
| 176 | const rc = pthread_rwlock_wrlock(&rwl.rwlock); | 139 | const rc = std.c.pthread_rwlock_wrlock(&rwl.rwlock); |
| 177 | assert(rc == .SUCCESS); | 140 | assert(rc == .SUCCESS); |
| 178 | } | 141 | } |
| 179 | | 142 | |
| 180 | pub fn unlock(rwl: *PthreadRwLock) void { | 143 | pub fn unlock(rwl: *PthreadRwLock) void { |
| 181 | const rc = pthread_rwlock_unlock(&rwl.rwlock); | 144 | const rc = std.c.pthread_rwlock_unlock(&rwl.rwlock); |
| 182 | assert(rc == .SUCCESS); | 145 | assert(rc == .SUCCESS); |
| 183 | } | 146 | } |
| 184 | | 147 | |
| 185 | pub fn tryLockShared(rwl: *PthreadRwLock) bool { | 148 | pub fn tryLockShared(rwl: *PthreadRwLock) bool { |
| 186 | return pthread_rwlock_tryrdlock(&rwl.rwlock) == .SUCCESS; | 149 | return std.c.pthread_rwlock_tryrdlock(&rwl.rwlock) == .SUCCESS; |
| 187 | } | 150 | } |
| 188 | | 151 | |
| 189 | pub fn lockShared(rwl: *PthreadRwLock) void { | 152 | pub fn lockShared(rwl: *PthreadRwLock) void { |
| 190 | const rc = pthread_rwlock_rdlock(&rwl.rwlock); | 153 | const rc = std.c.pthread_rwlock_rdlock(&rwl.rwlock); |
| 191 | assert(rc == .SUCCESS); | 154 | assert(rc == .SUCCESS); |
| 192 | } | 155 | } |
| 193 | | 156 | |
| 194 | pub fn unlockShared(rwl: *PthreadRwLock) void { | 157 | pub fn unlockShared(rwl: *PthreadRwLock) void { |
| 195 | const rc = pthread_rwlock_unlock(&rwl.rwlock); | 158 | const rc = std.c.pthread_rwlock_unlock(&rwl.rwlock); |
| 196 | assert(rc == .SUCCESS); | 159 | assert(rc == .SUCCESS); |
| 197 | } | 160 | } |
| 198 | }; | 161 | }; |
| 199 | | 162 | |
| 200 | pub const DefaultRwLock = struct { | 163 | pub const DefaultRwLock = struct { |
| 201 | state: usize, | 164 | state: usize = 0, |
| 202 | mutex: Mutex, | 165 | mutex: std.Thread.Mutex = .{}, |
| 203 | semaphore: Semaphore, | 166 | semaphore: std.Thread.Semaphore = .{}, |
| 204 | | 167 | |
| 205 | const IS_WRITING: usize = 1; | 168 | const IS_WRITING: usize = 1; |
| 206 | const WRITER: usize = 1 << 1; | 169 | const WRITER: usize = 1 << 1; |
| ... | @@ -209,20 +172,6 @@ pub const DefaultRwLock = struct { | ... | @@ -209,20 +172,6 @@ pub const DefaultRwLock = struct { |
| 209 | const READER_MASK: usize = std.math.maxInt(Count) << @ctz(usize, READER); | 172 | const READER_MASK: usize = std.math.maxInt(Count) << @ctz(usize, READER); |
| 210 | const Count = std.meta.Int(.unsigned, @divFloor(std.meta.bitCount(usize) - 1, 2)); | 173 | const Count = std.meta.Int(.unsigned, @divFloor(std.meta.bitCount(usize) - 1, 2)); |
| 211 | | 174 | |
| 212 | pub fn init(rwl: *DefaultRwLock) void { | | |
| 213 | rwl.* = .{ | | |
| 214 | .state = 0, | | |
| 215 | .mutex = Mutex.init(), | | |
| 216 | .semaphore = Semaphore.init(0), | | |
| 217 | }; | | |
| 218 | } | | |
| 219 | | | |
| 220 | pub fn deinit(rwl: *DefaultRwLock) void { | | |
| 221 | rwl.semaphore.deinit(); | | |
| 222 | rwl.mutex.deinit(); | | |
| 223 | rwl.* = undefined; | | |
| 224 | } | | |
| 225 | | | |
| 226 | pub fn tryLock(rwl: *DefaultRwLock) bool { | 175 | pub fn tryLock(rwl: *DefaultRwLock) bool { |
| 227 | if (rwl.mutex.tryLock()) { | 176 | if (rwl.mutex.tryLock()) { |
| 228 | const state = @atomicLoad(usize, &rwl.state, .SeqCst); | 177 | const state = @atomicLoad(usize, &rwl.state, .SeqCst); |