-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrwlocks.nim
87 lines (73 loc) · 2.28 KB
/
rwlocks.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
## This module implements readers-writer locks.
import std/locks
{.push stacktrace: off.}
type Rwlock* = object
## Readers-writer lock (multiple readers, single writer).
users {.guard: g.}: int # number of readers active, -1 if writer active
waitingWriters {.guard: g.}: int
cond: Cond
g: Lock
proc initLock*(rw: var Rwlock) {.inline.} =
initCond(rw.cond)
initLock(rw.g)
proc deinitLock*(rw: var Rwlock) {.inline.} =
deinitCond(rw.cond)
deinitLock(rw.g)
proc tryAcquireRead*(rw: var Rwlock): bool {.inline.} =
## Tries to acquire the given lock for reading. Returns `true` on success.
withLock(rw.g):
if rw.waitingWriters == 0 and rw.users > -1:
inc(rw.users)
result = true
proc acquireRead*(rw: var Rwlock) {.inline.} =
## Acquires the given lock for reading.
withLock(rw.g):
while rw.waitingWriters > 0 or rw.users == -1:
rw.cond.wait(rw.g)
inc(rw.users)
proc releaseRead*(rw: var Rwlock) {.inline.} =
## Releases the given lock from reading.
withLock(rw.g):
doAssert rw.users > 0
dec(rw.users)
if rw.users == 0:
rw.cond.broadcast()
proc tryAcquireWrite*(rw: var Rwlock): bool {.inline.} =
## Tries to acquire the given lock for writing. Returns `true` on success.
withLock(rw.g):
if rw.users == 0:
dec(rw.users)
result = true
proc acquireWrite*(rw: var Rwlock) {.inline.} =
## Acquires the given lock for writing.
withLock(rw.g):
inc(rw.waitingWriters)
while rw.users != 0:
rw.cond.wait(rw.g)
dec(rw.waitingWriters)
rw.users = -1
proc releaseWrite*(rw: var Rwlock) {.inline.} =
## Releases the given lock from writing.
withLock(rw.g):
doAssert rw.users == -1
rw.users = 0
rw.cond.broadcast()
template withReadLock*(rw: Rwlock, stmt: untyped) =
## Acquires the given lock for reading, executes the statements in body and
## releases the lock after the statements finish executing.
{.locks: [rw].}:
rw.acquireRead()
try:
stmt
finally:
rw.releaseRead()
template withWriteLock*(rw: Rwlock, stmt: untyped) =
## Acquires the given lock for writing, executes the statements in body and
## releases the lock after the statements finish executing.
{.locks: [rw].}:
rw.acquireWrite()
try:
stmt
finally:
rw.releaseWrite()
{.pop.}