Remove thread stuff from sync2; Cleanup package thread

This commit is contained in:
gingerBill
2021-04-11 18:25:56 +01:00
parent 52c193316b
commit 1156bd9dd0
7 changed files with 103 additions and 570 deletions
+40 -29
View File
@@ -26,6 +26,46 @@ Thread :: struct {
#assert(size_of(Thread{}.user_index) == size_of(uintptr));
Thread_Priority :: enum {
Normal,
Low,
High,
}
create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^Thread {
return _create(procedure, priority);
}
destroy :: proc(thread: ^Thread) {
_destroy(thread);
}
start :: proc(thread: ^Thread) {
_start(thread);
}
is_done :: proc(thread: ^Thread) -> bool {
return _is_done(thread);
}
join :: proc(thread: ^Thread) {
_join(thread);
}
join_mulitple :: proc(threads: ..^Thread) {
_join_multiple(..threads);
}
terminate :: proc(thread: ^Thread, exit_code: int) {
_terminate(thread, exit_code);
}
yield :: proc() {
_yield();
}
run :: proc(fn: proc(), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal) {
thread_proc :: proc(t: ^Thread) {
@@ -39,7 +79,6 @@ run :: proc(fn: proc(), init_context: Maybe(runtime.Context) = nil, priority :=
start(t);
}
run_with_data :: proc(data: rawptr, fn: proc(data: rawptr), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal) {
thread_proc :: proc(t: ^Thread) {
fn := cast(proc(rawptr))t.data;
@@ -152,31 +191,3 @@ create_and_start :: proc(fn: Thread_Proc, init_context: Maybe(runtime.Context) =
start(t);
return t;
}
Once :: struct {
m: sync.Blocking_Mutex,
done: bool,
}
once_init :: proc(o: ^Once) {
sync.blocking_mutex_init(&o.m);
intrinsics.atomic_store_rel(&o.done, false);
}
once_destroy :: proc(o: ^Once) {
sync.blocking_mutex_destroy(&o.m);
}
once_do :: proc(o: ^Once, fn: proc()) {
if intrinsics.atomic_load(&o.done) == false {
_once_do_slow(o, fn);
}
}
_once_do_slow :: proc(o: ^Once, fn: proc()) {
sync.blocking_mutex_lock(&o.m);
defer sync.blocking_mutex_unlock(&o.m);
if !o.done {
fn();
intrinsics.atomic_store_rel(&o.done, true);
}
}
+26 -32
View File
@@ -1,9 +1,10 @@
// +build linux, darwin, freebsd
package thread;
// +private
package thread
import "core:runtime"
import "core:intrinsics"
import "core:sync"
import sync "core:sync/sync2"
import "core:sys/unix"
// NOTE(tetra): Aligned here because of core/unix/pthread_linux.odin/pthread_t.
@@ -19,7 +20,7 @@ Thread_Os_Specific :: struct #align 16 {
// in a suspended state, we have it wait on this gate, which we
// signal to start it.
// destroyed after thread is started.
start_gate: sync.Condition,
start_gate: sync.Cond,
start_mutex: sync.Mutex,
// if true, the thread has been started and the start_gate has been destroyed.
@@ -31,25 +32,16 @@ Thread_Os_Specific :: struct #align 16 {
// See the comment in `join`.
already_joined: bool,
}
Thread_Priority :: enum {
Normal,
Low,
High,
}
//
// Creates a thread which will run the given procedure.
// It then waits for `start` to be called.
//
create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^Thread {
_create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^Thread {
__linux_thread_entry_proc :: proc "c" (t: rawptr) -> rawptr {
context = runtime.default_context();
t := (^Thread)(t);
sync.condition_wait_for(&t.start_gate);
sync.condition_destroy(&t.start_gate);
sync.mutex_destroy(&t.start_mutex);
sync.cond_wait(&t.start_gate, &t.start_mutex);
t.start_gate = {};
t.start_mutex = {};
@@ -67,7 +59,7 @@ create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^T
}
}
sync.atomic_store(&t.done, true, .Sequentially_Consistent);
intrinsics.atomic_store(&t.done, true);
return nil;
}
@@ -104,8 +96,6 @@ create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^T
res = unix.pthread_attr_setschedparam(&attrs, &params);
assert(res == 0);
sync.mutex_init(&thread.start_mutex);
sync.condition_init(&thread.start_gate, &thread.start_mutex);
if unix.pthread_create(&thread.unix_thread, &attrs, __linux_thread_entry_proc, thread) != 0 {
free(thread, thread.creation_allocator);
return nil;
@@ -115,18 +105,18 @@ create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^T
return thread;
}
start :: proc(t: ^Thread) {
if sync.atomic_swap(&t.started, true, .Sequentially_Consistent) {
_start :: proc(t: ^Thread) {
if intrinsics.atomic_xchg(&t.started, true) {
return;
}
sync.condition_signal(&t.start_gate);
sync.cond_signal(&t.start_gate);
}
is_done :: proc(t: ^Thread) -> bool {
return sync.atomic_load(&t.done, .Sequentially_Consistent);
_is_done :: proc(t: ^Thread) -> bool {
return intrinsics.atomic_load(&t.done);
}
join :: proc(t: ^Thread) {
_join :: proc(t: ^Thread) {
if unix.pthread_equal(unix.pthread_self(), t.unix_thread) {
return;
}
@@ -138,9 +128,9 @@ join :: proc(t: ^Thread) {
// See note on `already_joined` field.
// TODO(tetra): I'm not sure if we should do this, or panic, since I'm not
// sure it makes sense to need to join from multiple threads?
if sync.atomic_swap(&t.already_joined, true, .Sequentially_Consistent) {
if intrinsics.atomic_xchg(&t.already_joined, true) {
for {
if sync.atomic_load(&t.done, .Sequentially_Consistent) {
if intrinsics.atomic_load(&t.done) {
return;
}
intrinsics.cpu_relax();
@@ -152,31 +142,35 @@ join :: proc(t: ^Thread) {
// We do this instead because I don't know if there is a danger
// that you may join a different thread from the one you called join on,
// if the thread handle is reused.
if sync.atomic_load(&t.done, .Sequentially_Consistent) {
if intrinsics.atomic_load(&t.done) {
return;
}
ret_val: rawptr;
_ = unix.pthread_join(t.unix_thread, &ret_val);
if !sync.atomic_load(&t.done, .Sequentially_Consistent) {
if !intrinsics.atomic_load(&t.done) {
panic("thread not done after join");
}
}
join_multiple :: proc(threads: ..^Thread) {
_join_multiple :: proc(threads: ..^Thread) {
for t in threads {
join(t);
_join(t);
}
}
destroy :: proc(t: ^Thread) {
join(t);
_destroy :: proc(t: ^Thread) {
_join(t);
t.unix_thread = {};
free(t, t.creation_allocator);
}
yield :: proc() {
_terminate :: proc(t: ^Thread, exit_code: int) {
// TODO(bill)
}
_yield :: proc() {
unix.sched_yield();
}
+13 -18
View File
@@ -1,3 +1,5 @@
//+build windows
//+private
package thread
import "core:runtime"
@@ -10,20 +12,13 @@ Thread_Os_Specific :: struct {
done: bool, // see note in `is_done`
}
Thread_Priority :: enum {
Normal,
Low,
High,
}
_thread_priority_map := [Thread_Priority]i32{
.Normal = 0,
.Low = -2,
.High = +2,
};
create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^Thread {
_create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^Thread {
win32_thread_id: win32.DWORD;
__windows_thread_entry_proc :: proc "stdcall" (t_: rawptr) -> win32.DWORD {
@@ -70,18 +65,18 @@ create :: proc(procedure: Thread_Proc, priority := Thread_Priority.Normal) -> ^T
return thread;
}
start :: proc(using thread: ^Thread) {
win32.ResumeThread(win32_thread);
_start :: proc(thread: ^Thread) {
win32.ResumeThread(thread.win32_thread);
}
is_done :: proc(using thread: ^Thread) -> bool {
_is_done :: proc(using thread: ^Thread) -> bool {
// NOTE(tetra, 2019-10-31): Apparently using wait_for_single_object and
// checking if it didn't time out immediately, is not good enough,
// so we do it this way instead.
return sync.atomic_load(&done, .Sequentially_Consistent);
}
join :: proc(using thread: ^Thread) {
_join :: proc(using thread: ^Thread) {
if win32_thread != win32.INVALID_HANDLE {
win32.WaitForSingleObject(win32_thread, win32.INFINITE);
win32.CloseHandle(win32_thread);
@@ -89,7 +84,7 @@ join :: proc(using thread: ^Thread) {
}
}
join_multiple :: proc(threads: ..^Thread) {
_join_multiple :: proc(threads: ..^Thread) {
MAXIMUM_WAIT_OBJECTS :: 64;
handles: [MAXIMUM_WAIT_OBJECTS]win32.HANDLE;
@@ -113,16 +108,16 @@ join_multiple :: proc(threads: ..^Thread) {
}
}
destroy :: proc(thread: ^Thread) {
join(thread);
_destroy :: proc(thread: ^Thread) {
_join(thread);
free(thread, thread.creation_allocator);
}
terminate :: proc(using thread : ^Thread, exit_code: u32) {
win32.TerminateThread(win32_thread, exit_code);
_terminate :: proc(using thread : ^Thread, exit_code: int) {
win32.TerminateThread(win32_thread, u32(exit_code));
}
yield :: proc() {
_yield :: proc() {
win32.SwitchToThread();
}