Add sync.Parker

This commit is contained in:
gingerBill
2022-04-30 12:37:39 +01:00
parent d5886c1572
commit 78a8da5fea
+56
View File
@@ -297,3 +297,59 @@ once_do :: proc(o: ^Once, fn: proc()) {
do_slow(o, fn)
}
}
// A Parker is an associated token which is initially not present:
// * The `park` procedure blocks the current thread unless or until the token
// is available, at which point the token is consumed.
// * The `park_with_timeout` procedures works the same as `park` but only
// blocks for the specified duration.
// * The `unpark` procedure automatically makes the token available if it
// was not already.
Parker :: struct {
state: Futex,
}
// Blocks the current thread until the token is made available.
//
// Assumes this is only called by the thread that owns the Parker.
park :: proc(p: ^Parker) {
EMPTY :: 0
NOTIFIED :: 1
PARKED :: max(u32)
if atomic_sub_explicit(&p.state, 1, .Acquire) == NOTIFIED {
return
}
for {
futex_wait(&p.state, PARKED)
if _, ok := atomic_compare_exchange_strong_explicit(&p.state, NOTIFIED, EMPTY, .Acquire, .Acquire); ok {
return
}
}
}
// Blocks the current thread until the token is made available, but only
// for a limited duration.
//
// Assumes this is only called by the thread that owns the Parker
park_with_timeout :: proc(p: ^Parker, duration: time.Duration) {
EMPTY :: 0
NOTIFIED :: 1
PARKED :: max(u32)
if atomic_sub_explicit(&p.state, 1, .Acquire) == NOTIFIED {
return
}
futex_wait_with_timeout(&p.state, PARKED, duration)
atomic_exchange_explicit(&p.state, EMPTY, .Acquire)
}
// Automatically makes thee token available if it was not already.
unpark :: proc(p: ^Parker) {
EMPTY :: 0
NOTIFIED :: 1
PARKED :: max(Futex)
if atomic_exchange_explicit(&p.state, NOTIFIED, .Release) == PARKED {
futex_signal(&p.state)
}
}