sync_windows.odin 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. // +build windows
  2. package sync
  3. import win32 "core:sys/windows"
  4. import "core:time"
  5. current_thread_id :: proc "contextless" () -> int {
  6. return int(win32.GetCurrentThreadId());
  7. }
  8. // When waited upon, blocks until the internal count is greater than zero, then subtracts one.
  9. // Posting to the semaphore increases the count by one, or the provided amount.
  10. Semaphore :: struct {
  11. _handle: win32.HANDLE,
  12. }
  13. semaphore_init :: proc(s: ^Semaphore, initial_count := 0) {
  14. s._handle = win32.CreateSemaphoreW(nil, i32(initial_count), 1<<31-1, nil);
  15. }
  16. semaphore_destroy :: proc(s: ^Semaphore) {
  17. win32.CloseHandle(s._handle);
  18. }
  19. semaphore_post :: proc(s: ^Semaphore, count := 1) {
  20. win32.ReleaseSemaphore(s._handle, i32(count), nil);
  21. }
  22. semaphore_wait_for :: proc(s: ^Semaphore) {
  23. // NOTE(tetra, 2019-10-30): wait_for_single_object decrements the count before it returns.
  24. result := win32.WaitForSingleObject(s._handle, win32.INFINITE);
  25. assert(result != win32.WAIT_FAILED);
  26. }
  27. Mutex :: struct {
  28. _critical_section: win32.CRITICAL_SECTION,
  29. }
  30. mutex_init :: proc(m: ^Mutex, spin_count := 0) {
  31. win32.InitializeCriticalSectionAndSpinCount(&m._critical_section, u32(spin_count));
  32. }
  33. mutex_destroy :: proc(m: ^Mutex) {
  34. win32.DeleteCriticalSection(&m._critical_section);
  35. }
  36. mutex_lock :: proc(m: ^Mutex) {
  37. win32.EnterCriticalSection(&m._critical_section);
  38. }
  39. mutex_try_lock :: proc(m: ^Mutex) -> bool {
  40. return bool(win32.TryEnterCriticalSection(&m._critical_section));
  41. }
  42. mutex_unlock :: proc(m: ^Mutex) {
  43. win32.LeaveCriticalSection(&m._critical_section);
  44. }
  45. Blocking_Mutex :: struct {
  46. _handle: win32.SRWLOCK,
  47. }
  48. blocking_mutex_init :: proc(m: ^Blocking_Mutex) {
  49. win32.InitializeSRWLock(&m._handle);
  50. }
  51. blocking_mutex_destroy :: proc(m: ^Blocking_Mutex) {
  52. //
  53. }
  54. blocking_mutex_lock :: proc(m: ^Blocking_Mutex) {
  55. win32.AcquireSRWLockExclusive(&m._handle);
  56. }
  57. blocking_mutex_try_lock :: proc(m: ^Blocking_Mutex) -> bool {
  58. return bool(win32.TryAcquireSRWLockExclusive(&m._handle));
  59. }
  60. blocking_mutex_unlock :: proc(m: ^Blocking_Mutex) {
  61. win32.ReleaseSRWLockExclusive(&m._handle);
  62. }
  63. // Blocks until signalled.
  64. // When signalled, awakens exactly one waiting thread.
  65. Condition :: struct {
  66. _handle: win32.CONDITION_VARIABLE,
  67. mutex: Condition_Mutex_Ptr,
  68. }
  69. condition_init :: proc(c: ^Condition, mutex: Condition_Mutex_Ptr) -> bool {
  70. assert(mutex != nil);
  71. win32.InitializeConditionVariable(&c._handle);
  72. c.mutex = mutex;
  73. return true;
  74. }
  75. condition_destroy :: proc(c: ^Condition) {
  76. //
  77. }
  78. condition_signal :: proc(c: ^Condition) -> bool {
  79. if c._handle.ptr == nil {
  80. return false;
  81. }
  82. win32.WakeConditionVariable(&c._handle);
  83. return true;
  84. }
  85. condition_broadcast :: proc(c: ^Condition) -> bool {
  86. if c._handle.ptr == nil {
  87. return false;
  88. }
  89. win32.WakeAllConditionVariable(&c._handle);
  90. return true;
  91. }
  92. condition_wait_for :: proc(c: ^Condition) -> bool {
  93. switch m in &c.mutex {
  94. case ^Mutex:
  95. return cast(bool)win32.SleepConditionVariableCS(&c._handle, &m._critical_section, win32.INFINITE);
  96. case ^Blocking_Mutex:
  97. return cast(bool)win32.SleepConditionVariableSRW(&c._handle, &m._handle, win32.INFINITE, 0);
  98. }
  99. return false;
  100. }
  101. condition_wait_for_timeout :: proc(c: ^Condition, duration: time.Duration) -> bool {
  102. ms := win32.DWORD((max(time.duration_nanoseconds(duration), 0) + 999999)/1000000);
  103. switch m in &c.mutex {
  104. case ^Mutex:
  105. return cast(bool)win32.SleepConditionVariableCS(&c._handle, &m._critical_section, ms);
  106. case ^Blocking_Mutex:
  107. return cast(bool)win32.SleepConditionVariableSRW(&c._handle, &m._handle, ms, 0);
  108. }
  109. return false;
  110. }
  111. RW_Lock :: struct {
  112. _handle: win32.SRWLOCK,
  113. }
  114. rw_lock_init :: proc(l: ^RW_Lock) {
  115. l._handle = win32.SRWLOCK_INIT;
  116. }
  117. rw_lock_destroy :: proc(l: ^RW_Lock) {
  118. //
  119. }
  120. rw_lock_read :: proc(l: ^RW_Lock) {
  121. win32.AcquireSRWLockShared(&l._handle);
  122. }
  123. rw_lock_try_read :: proc(l: ^RW_Lock) -> bool {
  124. return bool(win32.TryAcquireSRWLockShared(&l._handle));
  125. }
  126. rw_lock_write :: proc(l: ^RW_Lock) {
  127. win32.AcquireSRWLockExclusive(&l._handle);
  128. }
  129. rw_lock_try_write :: proc(l: ^RW_Lock) -> bool {
  130. return bool(win32.TryAcquireSRWLockExclusive(&l._handle));
  131. }
  132. rw_lock_read_unlock :: proc(l: ^RW_Lock) {
  133. win32.ReleaseSRWLockShared(&l._handle);
  134. }
  135. rw_lock_write_unlock :: proc(l: ^RW_Lock) {
  136. win32.ReleaseSRWLockExclusive(&l._handle);
  137. }
  138. thread_yield :: proc() {
  139. win32.SwitchToThread();
  140. }