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