futex_linux.odin 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. //+private
  2. //+build linux
  3. package sync
  4. import "core:c"
  5. import "core:time"
  6. import "core:intrinsics"
  7. import "core:sys/unix"
  8. FUTEX_WAIT :: 0
  9. FUTEX_WAKE :: 1
  10. FUTEX_PRIVATE_FLAG :: 128
  11. FUTEX_WAIT_PRIVATE :: (FUTEX_WAIT | FUTEX_PRIVATE_FLAG)
  12. FUTEX_WAKE_PRIVATE :: (FUTEX_WAKE | FUTEX_PRIVATE_FLAG)
  13. ESUCCESS :: 0
  14. EINTR :: -4
  15. EAGAIN :: -11
  16. EFAULT :: -14
  17. EINVAL :: -22
  18. ETIMEDOUT :: -110
  19. get_errno :: proc(r: int) -> int {
  20. if -4096 < r && r < 0 {
  21. return r
  22. }
  23. return 0
  24. }
  25. internal_futex :: proc(f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> int {
  26. code := int(intrinsics.syscall(unix.SYS_futex, uintptr(f), uintptr(op), uintptr(val), uintptr(timeout), 0, 0))
  27. return get_errno(code)
  28. }
  29. _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
  30. err := internal_futex(f, FUTEX_WAIT_PRIVATE | FUTEX_WAIT, expected, nil)
  31. switch err {
  32. case ESUCCESS, EINTR, EAGAIN, EINVAL:
  33. // okay
  34. case ETIMEDOUT:
  35. return false
  36. case EFAULT:
  37. fallthrough
  38. case:
  39. panic("futex_wait failure")
  40. }
  41. return true
  42. }
  43. _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
  44. if duration <= 0 {
  45. return false
  46. }
  47. timespec_t :: struct {
  48. tv_sec: c.long,
  49. tv_nsec: c.long,
  50. }
  51. err := internal_futex(f, FUTEX_WAIT_PRIVATE | FUTEX_WAIT, expected, &timespec_t{
  52. tv_sec = (c.long)(duration/1e9),
  53. tv_nsec = (c.long)(duration%1e9),
  54. })
  55. switch err {
  56. case ESUCCESS, EINTR, EAGAIN, EINVAL:
  57. // okay
  58. case ETIMEDOUT:
  59. return false
  60. case EFAULT:
  61. fallthrough
  62. case:
  63. panic("futex_wait_with_timeout failure")
  64. }
  65. return true
  66. }
  67. _futex_signal :: proc(f: ^Futex) {
  68. err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, 1, nil)
  69. switch err {
  70. case ESUCCESS, EINVAL, EFAULT:
  71. // okay
  72. case:
  73. panic("futex_wake_single failure")
  74. }
  75. }
  76. _futex_broadcast :: proc(f: ^Futex) {
  77. err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, u32(max(i32)), nil)
  78. switch err {
  79. case ESUCCESS, EINVAL, EFAULT:
  80. // okay
  81. case:
  82. panic("_futex_wake_all failure")
  83. }
  84. }