futex_linux.odin 2.0 KB

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