futex_windows.odin 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. #+private
  2. #+build windows
  3. package sync
  4. import "core:time"
  5. foreign import Synchronization "system:Synchronization.lib"
  6. @(default_calling_convention="system")
  7. foreign Synchronization {
  8. WakeByAddressSingle :: proc(Address: rawptr) ---
  9. WakeByAddressAll :: proc(Address: rawptr) ---
  10. }
  11. foreign import Ntdll "system:Ntdll.lib"
  12. @(default_calling_convention="system")
  13. foreign Ntdll {
  14. RtlWaitOnAddress :: proc(Address: rawptr, CompareAddress: rawptr, AddressSize: uint, Timeout: ^i64) -> i32 ---
  15. RtlNtStatusToDosError :: proc(status: i32) -> u32 ---
  16. SetLastError :: proc(err: u32) ---
  17. }
  18. /*
  19. NOTE(bill, 2022-08-17)
  20. WaitOnAddress is implemented on top of RtlWaitOnAddress
  21. BUT requires taking the return value of it and if it is non-zero
  22. converting that status to a DOS error and then SetLastError
  23. If this is not done, then things don't work as expected when
  24. an error occurs
  25. GODDAMN MICROSOFT!
  26. */
  27. CustomWaitOnAddress :: proc "system" (Address: rawptr, CompareAddress: rawptr, AddressSize: uint, Timeout: ^i64) -> bool {
  28. status := RtlWaitOnAddress(Address, CompareAddress, AddressSize, Timeout)
  29. if status != 0 {
  30. SetLastError(RtlNtStatusToDosError(status))
  31. }
  32. return status == 0
  33. }
  34. _futex_wait :: proc "contextless" (f: ^Futex, expect: u32) -> bool {
  35. expect := expect
  36. return CustomWaitOnAddress(f, &expect, size_of(expect), nil)
  37. }
  38. _futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expect: u32, duration: time.Duration) -> bool {
  39. expect := expect
  40. // NOTE(bill): for some bizarre reason, this has to be a negative number
  41. timeout := -i64(duration / 100)
  42. return CustomWaitOnAddress(f, &expect, size_of(expect), &timeout)
  43. }
  44. _futex_signal :: proc "contextless" (f: ^Futex) {
  45. WakeByAddressSingle(f)
  46. }
  47. _futex_broadcast :: proc "contextless" (f: ^Futex) {
  48. WakeByAddressAll(f)
  49. }