sync: use Event for waitgroup on windows

pull/5460/head
joe-conigliaro 2020-06-23 03:23:42 +10:00
parent a4b159a80f
commit d19a33c420
No known key found for this signature in database
GPG Key ID: C12F7136C08206F1
5 changed files with 71 additions and 14 deletions

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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
}