86 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			V
		
	
	
			
		
		
	
	
			86 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			V
		
	
	
| // 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
 | |
| 
 | |
| // Mutex HANDLE
 | |
| type MHANDLE voidptr
 | |
| 
 | |
| //[init_with=new_mutex] // TODO: implement support for this struct attribute, and disallow Mutex{} from outside the sync.new_mutex() function.
 | |
| pub struct Mutex {
 | |
| mut:
 | |
| 	mx           MHANDLE    // mutex handle
 | |
| 	state        MutexState // mutex state
 | |
| 	cycle_wait   i64        // waiting cycles (implemented only with atomic)
 | |
| 	cycle_woken  i64        // woken cycles    ^
 | |
| 	reader_sem   u32        // reader semarphone
 | |
| 	writer_sem   u32        // writer semaphones
 | |
| }
 | |
| 
 | |
| enum MutexState {
 | |
| 	broken
 | |
| 	waiting
 | |
| 	released
 | |
| 	abandoned
 | |
| 	destroyed
 | |
| }
 | |
| 
 | |
| pub fn new_mutex() &Mutex {
 | |
| 	sm := &Mutex{}
 | |
| 	unsafe {
 | |
| 		mut m := sm
 | |
| 		m.mx = C.CreateMutex(0, false, 0)
 | |
| 		if isnil(m.mx) {
 | |
| 			m.state = .broken // handle broken and mutex state are broken
 | |
| 			return sm
 | |
| 		}
 | |
| 	}
 | |
| 	return sm
 | |
| }
 | |
| 
 | |
| pub fn (m mut Mutex) lock() {
 | |
| 	// if mutex handle not initalized
 | |
| 	if isnil(m.mx) {
 | |
| 		m.mx = C.CreateMutex(0, false, 0)
 | |
| 		if isnil(m.mx) {
 | |
| 			m.state = .broken // handle broken and mutex state are broken
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 	state := C.WaitForSingleObject(m.mx, C.INFINITE) // infinite wait
 | |
| 	/* TODO fix match/enum combo
 | |
| 	m.state = match state {
 | |
| 		C.WAIT_ABANDONED { .abandoned }
 | |
| 		C.WAIT_OBJECT_0  { .waiting }
 | |
| 		else           { .broken }
 | |
| 	}
 | |
| 	*/
 | |
| 	if state == C.WAIT_ABANDONED {
 | |
| 		m.state = .abandoned
 | |
| 	// FIXME Use C constant instead
 | |
| 	} else if state == 0 /* C.WAIT_OBJECT_0 */ {
 | |
| 		m.state = .waiting
 | |
| 	} else {
 | |
| 		m.state = .broken
 | |
| 	}
 | |
| }
 | |
| 
 | |
| pub fn (m mut Mutex) unlock() {
 | |
| 	if m.state == .waiting {
 | |
| 		if C.ReleaseMutex(m.mx) {
 | |
| 			m.state = .broken
 | |
| 			return
 | |
| 		}
 | |
| 	}
 | |
| 	m.state = .released
 | |
| }
 | |
| 
 | |
| pub fn (m mut Mutex) destroy() {
 | |
| 	if m.state == .waiting {
 | |
| 		m.unlock() // unlock mutex before destroying
 | |
| 	}
 | |
| 	C.CloseHandle(m.mx)  // destroy mutex
 | |
| 	m.state = .destroyed // setting up reference to invalid state
 | |
| }
 |