aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFeoramund <161657516+Feoramund@users.noreply.github.com>2024-09-08 17:25:48 -0400
committerFeoramund <161657516+Feoramund@users.noreply.github.com>2024-09-09 16:19:14 -0400
commit74b28f1ff91d4776475f4009fa2bcda71c655cd5 (patch)
treef908d8179e64e303c8aae4b07b9cd0e9922af09c
parent9d6f71fd2ed0a290781e547c7573e86010ff660f (diff)
Fix rare double-join possibility in POSIX `thread._join`
This was occuring about 1/100 times with the test runner's thread pool.
-rw-r--r--core/thread/thread_unix.odin16
1 files changed, 4 insertions, 12 deletions
diff --git a/core/thread/thread_unix.odin b/core/thread/thread_unix.odin
index ddc47244c..d165560ac 100644
--- a/core/thread/thread_unix.odin
+++ b/core/thread/thread_unix.odin
@@ -9,8 +9,6 @@ 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) {
@@ -140,24 +138,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)