mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-05 07:08:48 +00:00
Merge pull request #4148 from Feoramund/tls-cleaner
Add API for freeing `thread_local` state
This commit is contained in:
@@ -0,0 +1,34 @@
|
|||||||
|
package runtime
|
||||||
|
|
||||||
|
Thread_Local_Cleaner :: #type proc "odin" ()
|
||||||
|
|
||||||
|
@(private="file")
|
||||||
|
thread_local_cleaners: [8]Thread_Local_Cleaner
|
||||||
|
|
||||||
|
// Add a procedure that will be run at the end of a thread for the purpose of
|
||||||
|
// deallocating state marked as `thread_local`.
|
||||||
|
//
|
||||||
|
// Intended to be called in an `init` procedure of a package with
|
||||||
|
// dynamically-allocated memory that is stored in `thread_local` variables.
|
||||||
|
add_thread_local_cleaner :: proc "contextless" (p: Thread_Local_Cleaner) {
|
||||||
|
for &v in thread_local_cleaners {
|
||||||
|
if v == nil {
|
||||||
|
v = p
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic_contextless("There are no more thread-local cleaner slots available.")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run all of the thread-local cleaner procedures.
|
||||||
|
//
|
||||||
|
// Intended to be called by the internals of a threading API at the end of a
|
||||||
|
// thread's lifetime.
|
||||||
|
run_thread_local_cleaners :: proc "odin" () {
|
||||||
|
for p in thread_local_cleaners {
|
||||||
|
if p == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
p()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -61,3 +61,8 @@ TEMP_ALLOCATOR_GUARD :: #force_inline proc(loc := #caller_location) -> (runtime.
|
|||||||
global_default_temp_allocator_index = (global_default_temp_allocator_index+1)%MAX_TEMP_ARENA_COUNT
|
global_default_temp_allocator_index = (global_default_temp_allocator_index+1)%MAX_TEMP_ARENA_COUNT
|
||||||
return tmp, loc
|
return tmp, loc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(init, private)
|
||||||
|
init_thread_local_cleaner :: proc() {
|
||||||
|
runtime.add_thread_local_cleaner(temp_allocator_fini)
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
// +private
|
// +private
|
||||||
package thread
|
package thread
|
||||||
|
|
||||||
|
import "base:runtime"
|
||||||
import "core:sync"
|
import "core:sync"
|
||||||
import "core:sys/unix"
|
import "core:sys/unix"
|
||||||
import "core:time"
|
import "core:time"
|
||||||
@@ -55,7 +56,10 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
|
|||||||
// Here on Unix, we start the OS thread in a running state, and so we manually have it wait on a condition
|
// Here on Unix, we start the OS thread in a running state, and so we manually have it wait on a condition
|
||||||
// variable above. We must perform that waiting BEFORE we select the context!
|
// variable above. We must perform that waiting BEFORE we select the context!
|
||||||
context = _select_context_for_thread(init_context)
|
context = _select_context_for_thread(init_context)
|
||||||
defer _maybe_destroy_default_temp_allocator(init_context)
|
defer {
|
||||||
|
_maybe_destroy_default_temp_allocator(init_context)
|
||||||
|
runtime.run_thread_local_cleaners()
|
||||||
|
}
|
||||||
|
|
||||||
t.procedure(t)
|
t.procedure(t)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
package thread
|
package thread
|
||||||
|
|
||||||
import "base:intrinsics"
|
import "base:intrinsics"
|
||||||
|
import "base:runtime"
|
||||||
import "core:sync"
|
import "core:sync"
|
||||||
import win32 "core:sys/windows"
|
import win32 "core:sys/windows"
|
||||||
|
|
||||||
@@ -39,7 +40,10 @@ _create :: proc(procedure: Thread_Proc, priority: Thread_Priority) -> ^Thread {
|
|||||||
// Here on Windows, the thread is created in a suspended state, and so we can select the context anywhere before the call
|
// Here on Windows, the thread is created in a suspended state, and so we can select the context anywhere before the call
|
||||||
// to t.procedure().
|
// to t.procedure().
|
||||||
context = _select_context_for_thread(init_context)
|
context = _select_context_for_thread(init_context)
|
||||||
defer _maybe_destroy_default_temp_allocator(init_context)
|
defer {
|
||||||
|
_maybe_destroy_default_temp_allocator(init_context)
|
||||||
|
runtime.run_thread_local_cleaners()
|
||||||
|
}
|
||||||
|
|
||||||
t.procedure(t)
|
t.procedure(t)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user