sync: use Event for waitgroup on windows
parent
a4b159a80f
commit
d19a33c420
|
@ -379,20 +379,18 @@ fn C.GetLastError() u32
|
|||
|
||||
fn C.CreateDirectory(byteptr, int) bool
|
||||
|
||||
|
||||
// win crypto
|
||||
fn C.BCryptGenRandom(int, voidptr, int, int) int
|
||||
|
||||
|
||||
// win synchronization
|
||||
fn C.CreateMutex(int, bool, byteptr) voidptr
|
||||
|
||||
|
||||
fn C.WaitForSingleObject(voidptr, int) int
|
||||
|
||||
|
||||
fn C.ReleaseMutex(voidptr) bool
|
||||
fn C.CreateEvent(int, bool, bool, byteptr) voidptr
|
||||
fn C.SetEvent(voidptr) int
|
||||
|
||||
|
||||
// pthread.h
|
||||
|
||||
fn C.pthread_mutex_init(voidptr, voidptr) int
|
||||
fn C.pthread_mutex_lock(voidptr) int
|
||||
fn C.pthread_mutex_unlock(voidptr) int
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
module sync
|
||||
|
||||
// TODO: The suggestion of using CriticalSection instead of mutex
|
||||
// was discussed. Needs consideration.
|
||||
|
||||
// Mutex HANDLE
|
||||
type MHANDLE voidptr
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
module sync
|
||||
|
||||
[ref_only]
|
||||
struct Waiter{
|
||||
mut:
|
||||
mx &Mutex
|
||||
}
|
||||
|
||||
pub fn (mut w Waiter) wait() {
|
||||
w.mx.lock()
|
||||
}
|
||||
|
||||
pub fn (mut w Waiter) stop() {
|
||||
w.mx.unlock()
|
||||
}
|
||||
pub fn new_waiter() &Waiter {
|
||||
w := &Waiter{mx: new_mutex()}
|
||||
return w
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// Copyright (c) 2019 Alexander Medvednikov. All rights reserved.
|
||||
// Use of this source code is governed by an MIT license
|
||||
// that can be found in the LICENSE file.
|
||||
module sync
|
||||
|
||||
// We cannot simply use Mutex.lock() in the waitgroup.wait() method
|
||||
// as it will not block since it's used in the same thread.
|
||||
// docs:
|
||||
// Any thread with a handle to a mutex object can use one of the
|
||||
// wait functions to request ownership of the mutex object.
|
||||
// If the mutex object is owned by another thread, the wait
|
||||
// function blocks the requesting thread until the owning thread
|
||||
// releases the mutex object using the ReleaseMutex function.
|
||||
// Source:
|
||||
// https://docs.microsoft.com/en-us/windows/win32/sync/mutex-objects
|
||||
|
||||
[ref_only]
|
||||
struct Waiter{
|
||||
mut:
|
||||
event MHANDLE
|
||||
}
|
||||
|
||||
pub fn (mut w Waiter) wait() {
|
||||
C.WaitForSingleObject(w.event, C.INFINITE) // infinite wait
|
||||
}
|
||||
|
||||
pub fn (mut w Waiter) stop() {
|
||||
C.SetEvent(w.event)
|
||||
}
|
||||
pub fn new_waiter() &Waiter {
|
||||
unsafe {
|
||||
sm := &Waiter{event: MHANDLE(C.CreateEvent(0, false, true, 0))}
|
||||
return sm
|
||||
}
|
||||
}
|
|
@ -15,13 +15,13 @@ struct WaitGroup {
|
|||
mut:
|
||||
task_count int // current task count
|
||||
task_count_mutex &Mutex = &Mutex(0) // This mutex protects the task_count count in add()
|
||||
wait_blocker &Mutex = &Mutex(0) // This mutex blocks the wait() until released by add()
|
||||
wait_blocker &Waiter = &Waiter(0) // This blocks the wait() until released by add()
|
||||
}
|
||||
|
||||
pub fn new_waitgroup() &WaitGroup {
|
||||
return &WaitGroup{
|
||||
task_count_mutex: new_mutex()
|
||||
wait_blocker: new_mutex()
|
||||
wait_blocker: new_waiter()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,14 +36,14 @@ pub fn (mut wg WaitGroup) add(delta int) {
|
|||
}
|
||||
// If task_count likely to leave zero, set wait() to block
|
||||
if wg.task_count == 0 {
|
||||
wg.wait_blocker.lock()
|
||||
wg.wait_blocker.wait()
|
||||
}
|
||||
wg.task_count += delta
|
||||
if wg.task_count < 0 {
|
||||
panic('Negative number of jobs in waitgroup')
|
||||
}
|
||||
if wg.task_count == 0 { // if no more task_count tasks
|
||||
wg.wait_blocker.unlock() // unblock wait()
|
||||
wg.wait_blocker.stop() // unblock wait()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,6 +54,6 @@ pub fn (mut wg WaitGroup) done() {
|
|||
|
||||
// wait blocks until all tasks are done (task count becomes zero)
|
||||
pub fn (mut wg WaitGroup) wait() {
|
||||
wg.wait_blocker.lock() // blocks until task_count becomes 0
|
||||
wg.wait_blocker.unlock() // allow other wait()s to unblock or reuse wait group
|
||||
wg.wait_blocker.wait() // blocks until task_count becomes 0
|
||||
wg.wait_blocker.stop() // allow other wait()s to unblock or reuse wait group
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue