| ... | ... | @@ -3,15 +3,12 @@ |
| 3 | 3 | //! This API requires being initialized at runtime, and initialization |
| 4 | 4 | //! can fail. Once initialized, the core operations cannot fail. |
| 5 | 5 | |
| 6 | | impl: Impl, |
| 6 | impl: Impl = .{}, |
| 7 | 7 | |
| 8 | 8 | const RwLock = @This(); |
| 9 | 9 | const std = @import("../std.zig"); |
| 10 | 10 | const builtin = @import("builtin"); |
| 11 | 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 | 13 | pub const Impl = if (builtin.single_threaded) |
| 17 | 14 | SingleThreadedRwLock |
| ... | ... | @@ -20,14 +17,6 @@ else if (std.Thread.use_pthreads) |
| 20 | 17 | else |
| 21 | 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 | 20 | /// Attempts to obtain exclusive lock ownership. |
| 32 | 21 | /// Returns `true` if the lock is obtained, `false` otherwise. |
| 33 | 22 | pub fn tryLock(rwl: *RwLock) bool { |
| ... | ... | @@ -64,20 +53,8 @@ pub fn unlockShared(rwl: *RwLock) void { |
| 64 | 53 | /// Single-threaded applications use this for deadlock checks in |
| 65 | 54 | /// debug mode, and no-ops in release modes. |
| 66 | 55 | pub const SingleThreadedRwLock = struct { |
| 67 | | state: enum { unlocked, locked_exclusive, locked_shared }, |
| 68 | | shared_count: usize, |
| 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 | | } |
| 56 | state: enum { unlocked, locked_exclusive, locked_shared } = .unlocked, |
| 57 | shared_count: usize = 0, |
| 81 | 58 | |
| 82 | 59 | /// Attempts to obtain exclusive lock ownership. |
| 83 | 60 | /// Returns `true` if the lock is obtained, `false` otherwise. |
| ... | ... | @@ -152,55 +129,41 @@ pub const SingleThreadedRwLock = struct { |
| 152 | 129 | }; |
| 153 | 130 | |
| 154 | 131 | pub const PthreadRwLock = struct { |
| 155 | | rwlock: 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 | | } |
| 132 | rwlock: std.c.pthread_rwlock_t = .{}, |
| 170 | 133 | |
| 171 | 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 | 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 | 140 | assert(rc == .SUCCESS); |
| 178 | 141 | } |
| 179 | 142 | |
| 180 | 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 | 145 | assert(rc == .SUCCESS); |
| 183 | 146 | } |
| 184 | 147 | |
| 185 | 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 | 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 | 154 | assert(rc == .SUCCESS); |
| 192 | 155 | } |
| 193 | 156 | |
| 194 | 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 | 159 | assert(rc == .SUCCESS); |
| 197 | 160 | } |
| 198 | 161 | }; |
| 199 | 162 | |
| 200 | 163 | pub const DefaultRwLock = struct { |
| 201 | | state: usize, |
| 202 | | mutex: Mutex, |
| 203 | | semaphore: Semaphore, |
| 164 | state: usize = 0, |
| 165 | mutex: std.Thread.Mutex = .{}, |
| 166 | semaphore: std.Thread.Semaphore = .{}, |
| 204 | 167 | |
| 205 | 168 | const IS_WRITING: usize = 1; |
| 206 | 169 | const WRITER: usize = 1 << 1; |
| ... | ... | @@ -209,20 +172,6 @@ pub const DefaultRwLock = struct { |
| 209 | 172 | const READER_MASK: usize = std.math.maxInt(Count) << @ctz(usize, READER); |
| 210 | 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 | 175 | pub fn tryLock(rwl: *DefaultRwLock) bool { |
| 227 | 176 | if (rwl.mutex.tryLock()) { |
| 228 | 177 | const state = @atomicLoad(usize, &rwl.state, .SeqCst); |