Browse Source

Fix `RtlWaitOnAddress` behaviour with `SetLastError(RtlNtStatusToDosError(status))` if an error occurred

gingerBill 3 years ago
parent
commit
82765ca96e
1 changed files with 24 additions and 2 deletions
  1. 24 2
      core/sync/futex_windows.odin

+ 24 - 2
core/sync/futex_windows.odin

@@ -15,18 +15,40 @@ foreign import Ntdll "system:Ntdll.lib"
 @(default_calling_convention="stdcall")
 foreign Ntdll {
 	RtlWaitOnAddress :: proc(Address: rawptr, CompareAddress: rawptr, AddressSize: uint, Timeout: ^i64) -> i32 ---
+	RtlNtStatusToDosError :: proc(status: i32) -> u32 ---
+	SetLastError :: proc(err: u32) ---
 }
 
+
+/*
+	NOTE(bill, 2022-08-17)
+	WaitOnAddress is implemented on top of RtlWaitOnAddress
+	BUT requires taking the return value of it and if it is non-zero
+	converting that status to a DOS error and then SetLastError
+	If this is not done, then things don't work as expected when
+	and error occurs
+
+	GODDAMN MICROSOFT!
+*/
+CustomWaitOnAddress :: proc "stdcall" (Address: rawptr, CompareAddress: rawptr, AddressSize: uint, Timeout: ^i64) -> bool {
+	status := RtlWaitOnAddress(Address, CompareAddress, AddressSize, Timeout)
+	if status != 0 {
+		SetLastError(RtlNtStatusToDosError(status))
+	}
+	return status == 0
+}
+
+
 _futex_wait :: proc(f: ^Futex, expect: u32) -> bool {
 	expect := expect
-	return 0 == RtlWaitOnAddress(f, &expect, size_of(expect), nil)
+	return CustomWaitOnAddress(f, &expect, size_of(expect), nil)
 }
 
 _futex_wait_with_timeout :: proc(f: ^Futex, expect: u32, duration: time.Duration) -> bool {
 	expect := expect
 	// NOTE(bill): for some bizarre reason, this has be a negative number
 	timeout := -i64(duration / 100)
-	return 0 == RtlWaitOnAddress(f, &expect, size_of(expect), &timeout)
+	return CustomWaitOnAddress(f, &expect, size_of(expect), &timeout)
 }
 
 _futex_signal :: proc(f: ^Futex) {