From d19a33c4203bcb4890c4e6e9d129fd7cfe719b97 Mon Sep 17 00:00:00 2001 From: joe-conigliaro Date: Tue, 23 Jun 2020 03:23:42 +1000 Subject: [PATCH] sync: use Event for waitgroup on windows --- vlib/builtin/cfns.c.v | 12 +++++------- vlib/sync/sync_windows.c.v | 4 +++- vlib/sync/waiter_nix.c.v | 22 ++++++++++++++++++++++ vlib/sync/waiter_windows.c.v | 35 +++++++++++++++++++++++++++++++++++ vlib/sync/waitgroup.v | 12 ++++++------ 5 files changed, 71 insertions(+), 14 deletions(-) create mode 100644 vlib/sync/waiter_nix.c.v create mode 100644 vlib/sync/waiter_windows.c.v diff --git a/vlib/builtin/cfns.c.v b/vlib/builtin/cfns.c.v index f4710c873f..08314c1fff 100644 --- a/vlib/builtin/cfns.c.v +++ b/vlib/builtin/cfns.c.v @@ -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 diff --git a/vlib/sync/sync_windows.c.v b/vlib/sync/sync_windows.c.v index df2b714d29..e4da37a2dc 100644 --- a/vlib/sync/sync_windows.c.v +++ b/vlib/sync/sync_windows.c.v @@ -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 diff --git a/vlib/sync/waiter_nix.c.v b/vlib/sync/waiter_nix.c.v new file mode 100644 index 0000000000..80344e34da --- /dev/null +++ b/vlib/sync/waiter_nix.c.v @@ -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 +} diff --git a/vlib/sync/waiter_windows.c.v b/vlib/sync/waiter_windows.c.v new file mode 100644 index 0000000000..4698d0c57d --- /dev/null +++ b/vlib/sync/waiter_windows.c.v @@ -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 + } +} diff --git a/vlib/sync/waitgroup.v b/vlib/sync/waitgroup.v index a72437af2d..4963cd2d1f 100644 --- a/vlib/sync/waitgroup.v +++ b/vlib/sync/waitgroup.v @@ -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 }