diff options
| author | Karl Zylinski <karl@zylinski.se> | 2024-09-17 19:36:17 +0200 |
|---|---|---|
| committer | Karl Zylinski <karl@zylinski.se> | 2024-09-17 19:36:17 +0200 |
| commit | 093ade050445b3e348177e30fb1fc9d726f7b289 (patch) | |
| tree | 5122cfefa5fefbab9d27d5d8adacd8739eeeb5de /core/thread | |
| parent | 3d7b92426081cd9f3197b13f7384a52dbac5379a (diff) | |
| parent | 6ef779cd5c8260b2e6979e676d28489fd53dd599 (diff) | |
Merge branch 'master' into file-tags-without-comments
Diffstat (limited to 'core/thread')
| -rw-r--r-- | core/thread/thread.odin | 12 | ||||
| -rw-r--r-- | core/thread/thread_pool.odin | 1 | ||||
| -rw-r--r-- | core/thread/thread_unix.odin | 32 | ||||
| -rw-r--r-- | core/thread/thread_windows.odin | 6 |
4 files changed, 18 insertions, 33 deletions
diff --git a/core/thread/thread.odin b/core/thread/thread.odin index 17ba1a0a2..c1cbceb42 100644 --- a/core/thread/thread.odin +++ b/core/thread/thread.odin @@ -272,7 +272,7 @@ create_and_start :: proc(fn: proc(), init_context: Maybe(runtime.Context) = nil, t := create(thread_proc, priority) t.data = rawptr(fn) if self_cleanup { - t.flags += {.Self_Cleanup} + intrinsics.atomic_or(&t.flags, {.Self_Cleanup}) } t.init_context = init_context start(t) @@ -307,7 +307,7 @@ create_and_start_with_data :: proc(data: rawptr, fn: proc(data: rawptr), init_co t.user_index = 1 t.user_args[0] = data if self_cleanup { - t.flags += {.Self_Cleanup} + intrinsics.atomic_or(&t.flags, {.Self_Cleanup}) } t.init_context = init_context start(t) @@ -347,7 +347,7 @@ create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_contex mem.copy(&t.user_args[0], &data, size_of(T)) if self_cleanup { - t.flags += {.Self_Cleanup} + intrinsics.atomic_or(&t.flags, {.Self_Cleanup}) } t.init_context = init_context @@ -394,7 +394,7 @@ create_and_start_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), _ = copy(user_args[n:], mem.ptr_to_bytes(&arg2)) if self_cleanup { - t.flags += {.Self_Cleanup} + intrinsics.atomic_or(&t.flags, {.Self_Cleanup}) } t.init_context = init_context @@ -443,7 +443,7 @@ create_and_start_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: pr _ = copy(user_args[n:], mem.ptr_to_bytes(&arg3)) if self_cleanup { - t.flags += {.Self_Cleanup} + intrinsics.atomic_or(&t.flags, {.Self_Cleanup}) } t.init_context = init_context @@ -494,7 +494,7 @@ create_and_start_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: _ = copy(user_args[n:], mem.ptr_to_bytes(&arg4)) if self_cleanup { - t.flags += {.Self_Cleanup} + intrinsics.atomic_or(&t.flags, {.Self_Cleanup}) } t.init_context = init_context diff --git a/core/thread/thread_pool.odin b/core/thread/thread_pool.odin index 9bcc42968..d9166b450 100644 --- a/core/thread/thread_pool.odin +++ b/core/thread/thread_pool.odin @@ -60,6 +60,7 @@ pool_thread_runner :: proc(t: ^Thread) { if task, ok := pool_pop_waiting(pool); ok { data.task = task pool_do_work(pool, task) + sync.guard(&pool.mutex) data.task = {} } } diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin index 2e196c3e6..9576a3040 100644 --- a/core/thread/thread_unix.odin +++ b/core/thread/thread_unix.odin @@ -5,18 +5,14 @@ package thread import "base:runtime" import "core:sync" import "core:sys/unix" -import "core:time" _IS_SUPPORTED :: true -CAS :: sync.atomic_compare_exchange_strong - // NOTE(tetra): Aligned here because of core/unix/pthread_linux.odin/pthread_t. // Also see core/sys/darwin/mach_darwin.odin/semaphore_t. Thread_Os_Specific :: struct #align(16) { unix_thread: unix.pthread_t, // NOTE: very large on Darwin, small on Linux. - cond: sync.Cond, - mutex: sync.Mutex, + start_ok: sync.Sema, } // // Creates a thread which will run the given procedure. @@ -29,14 +25,10 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { // We need to give the thread a moment to start up before we enable cancellation. can_set_thread_cancel_state := unix.pthread_setcancelstate(unix.PTHREAD_CANCEL_ENABLE, nil) == 0 - sync.lock(&t.mutex) - t.id = sync.current_thread_id() - for (.Started not_in sync.atomic_load(&t.flags)) { - // HACK: use a timeout so in the event that the condition is signalled at THIS comment's exact point - // (after checking flags, before starting the wait) it gets itself out of that deadlock after a ms. - sync.wait_with_timeout(&t.cond, &t.mutex, time.Millisecond) + if .Started not_in sync.atomic_load(&t.flags) { + sync.wait(&t.start_ok) } if .Joined in sync.atomic_load(&t.flags) { @@ -66,8 +58,6 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { sync.atomic_or(&t.flags, { .Done }) - sync.unlock(&t.mutex) - if .Self_Cleanup in sync.atomic_load(&t.flags) { res := unix.pthread_detach(t.unix_thread) assert_contextless(res == 0) @@ -132,7 +122,7 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { _start :: proc(t: ^Thread) { sync.atomic_or(&t.flags, { .Started }) - sync.signal(&t.cond) + sync.post(&t.start_ok) } _is_done :: proc(t: ^Thread) -> bool { @@ -140,24 +130,18 @@ _is_done :: proc(t: ^Thread) -> bool { } _join :: proc(t: ^Thread) { - // sync.guard(&t.mutex) - if unix.pthread_equal(unix.pthread_self(), t.unix_thread) { return } - // Preserve other flags besides `.Joined`, like `.Started`. - unjoined := sync.atomic_load(&t.flags) - {.Joined} - joined := unjoined + {.Joined} - - // Try to set `t.flags` from unjoined to joined. If it returns joined, - // it means the previous value had that flag set and we can return. - if res, ok := CAS(&t.flags, unjoined, joined); res == joined && !ok { + // If the previous value was already `Joined`, then we can return. + if .Joined in sync.atomic_or(&t.flags, {.Joined}) { return } + // Prevent non-started threads from blocking main thread with initial wait // condition. - if .Started not_in unjoined { + if .Started not_in sync.atomic_load(&t.flags) { _start(t) } unix.pthread_join(t.unix_thread, nil) diff --git a/core/thread/thread_windows.odin b/core/thread/thread_windows.odin index 300673191..cc73a2d6a 100644 --- a/core/thread/thread_windows.odin +++ b/core/thread/thread_windows.odin @@ -27,7 +27,7 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { __windows_thread_entry_proc :: proc "system" (t_: rawptr) -> win32.DWORD { t := (^Thread)(t_) - if .Joined in t.flags { + if .Joined in sync.atomic_load(&t.flags) { return 0 } @@ -48,9 +48,9 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread { t.procedure(t) } - intrinsics.atomic_store(&t.flags, t.flags + {.Done}) + intrinsics.atomic_or(&t.flags, {.Done}) - if .Self_Cleanup in t.flags { + if .Self_Cleanup in sync.atomic_load(&t.flags) { win32.CloseHandle(t.win32_thread) t.win32_thread = win32.INVALID_HANDLE // NOTE(ftphikari): It doesn't matter which context 'free' received, right? |