1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

sync: use Event for waitgroup on windows

This commit is contained in:
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 fn C.CreateDirectory(byteptr, int) bool
// win crypto
fn C.BCryptGenRandom(int, voidptr, int, int) int fn C.BCryptGenRandom(int, voidptr, int, int) int
// win synchronization
fn C.CreateMutex(int, bool, byteptr) voidptr fn C.CreateMutex(int, bool, byteptr) voidptr
fn C.WaitForSingleObject(voidptr, int) int fn C.WaitForSingleObject(voidptr, int) int
fn C.ReleaseMutex(voidptr) bool fn C.ReleaseMutex(voidptr) bool
fn C.CreateEvent(int, bool, bool, byteptr) voidptr
fn C.SetEvent(voidptr) int
// pthread.h // pthread.h
fn C.pthread_mutex_init(voidptr, voidptr) int fn C.pthread_mutex_init(voidptr, voidptr) int
fn C.pthread_mutex_lock(voidptr) int fn C.pthread_mutex_lock(voidptr) int
fn C.pthread_mutex_unlock(voidptr) int fn C.pthread_mutex_unlock(voidptr) int

View File

@ -1,9 +1,11 @@
// Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved. // Copyright (c) 2019-2020 Alexander Medvednikov. All rights reserved.
// Use of this source code is governed by an MIT license // Use of this source code is governed by an MIT license
// that can be found in the LICENSE file. // that can be found in the LICENSE file.
module sync module sync
// TODO: The suggestion of using CriticalSection instead of mutex
// was discussed. Needs consideration.
// Mutex HANDLE // Mutex HANDLE
type MHANDLE voidptr type MHANDLE voidptr

22
vlib/sync/waiter_nix.c.v Normal file
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: mut:
task_count int // current task count task_count int // current task count
task_count_mutex &Mutex = &Mutex(0) // This mutex protects the task_count count in add() 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 { pub fn new_waitgroup() &WaitGroup {
return &WaitGroup{ return &WaitGroup{
task_count_mutex: new_mutex() 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 task_count likely to leave zero, set wait() to block
if wg.task_count == 0 { if wg.task_count == 0 {
wg.wait_blocker.lock() wg.wait_blocker.wait()
} }
wg.task_count += delta wg.task_count += delta
if wg.task_count < 0 { if wg.task_count < 0 {
panic('Negative number of jobs in waitgroup') panic('Negative number of jobs in waitgroup')
} }
if wg.task_count == 0 { // if no more task_count tasks 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) // wait blocks until all tasks are done (task count becomes zero)
pub fn (mut wg WaitGroup) wait() { pub fn (mut wg WaitGroup) wait() {
wg.wait_blocker.lock() // blocks until task_count becomes 0 wg.wait_blocker.wait() // blocks until task_count becomes 0
wg.wait_blocker.unlock() // allow other wait()s to unblock or reuse wait group wg.wait_blocker.stop() // allow other wait()s to unblock or reuse wait group
} }