|
@@ -12,39 +12,39 @@ Sema :: struct {
|
|
}
|
|
}
|
|
|
|
|
|
sema_reset :: proc "contextless" (s: ^Sema) {
|
|
sema_reset :: proc "contextless" (s: ^Sema) {
|
|
- intrinsics.atomic_store(&s.count, 0);
|
|
|
|
|
|
+ intrinsics.atomic_store(&s.count, 0)
|
|
}
|
|
}
|
|
sema_wait :: proc "contextless" (s: ^Sema) {
|
|
sema_wait :: proc "contextless" (s: ^Sema) {
|
|
for {
|
|
for {
|
|
- original_count := s.count;
|
|
|
|
|
|
+ original_count := s.count
|
|
for original_count == 0 {
|
|
for original_count == 0 {
|
|
win32.WaitOnAddress(
|
|
win32.WaitOnAddress(
|
|
&s.count,
|
|
&s.count,
|
|
&original_count,
|
|
&original_count,
|
|
size_of(original_count),
|
|
size_of(original_count),
|
|
win32.INFINITE,
|
|
win32.INFINITE,
|
|
- );
|
|
|
|
- original_count = s.count;
|
|
|
|
|
|
+ )
|
|
|
|
+ original_count = s.count
|
|
}
|
|
}
|
|
if original_count == intrinsics.atomic_cxchg(&s.count, original_count-1, original_count) {
|
|
if original_count == intrinsics.atomic_cxchg(&s.count, original_count-1, original_count) {
|
|
- return;
|
|
|
|
|
|
+ return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
sema_post :: proc "contextless" (s: ^Sema, count := 1) {
|
|
sema_post :: proc "contextless" (s: ^Sema, count := 1) {
|
|
- intrinsics.atomic_add(&s.count, i32(count));
|
|
|
|
|
|
+ intrinsics.atomic_add(&s.count, i32(count))
|
|
if count == 1 {
|
|
if count == 1 {
|
|
- win32.WakeByAddressSingle(&s.count);
|
|
|
|
|
|
+ win32.WakeByAddressSingle(&s.count)
|
|
} else {
|
|
} else {
|
|
- win32.WakeByAddressAll(&s.count);
|
|
|
|
|
|
+ win32.WakeByAddressAll(&s.count)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
-Thread_Proc :: #type proc(^Thread);
|
|
|
|
|
|
+Thread_Proc :: #type proc(^Thread)
|
|
|
|
|
|
-MAX_USER_ARGUMENTS :: 8;
|
|
|
|
|
|
+MAX_USER_ARGUMENTS :: 8
|
|
|
|
|
|
Thread :: struct {
|
|
Thread :: struct {
|
|
using specific: Thread_Os_Specific,
|
|
using specific: Thread_Os_Specific,
|
|
@@ -67,66 +67,66 @@ Thread_Os_Specific :: struct {
|
|
|
|
|
|
thread_create :: proc(procedure: Thread_Proc) -> ^Thread {
|
|
thread_create :: proc(procedure: Thread_Proc) -> ^Thread {
|
|
__windows_thread_entry_proc :: proc "stdcall" (t_: rawptr) -> win32.DWORD {
|
|
__windows_thread_entry_proc :: proc "stdcall" (t_: rawptr) -> win32.DWORD {
|
|
- t := (^Thread)(t_);
|
|
|
|
- context = t.init_context.? or_else runtime.default_context();
|
|
|
|
|
|
+ t := (^Thread)(t_)
|
|
|
|
+ context = t.init_context.? or_else runtime.default_context()
|
|
|
|
|
|
- t.procedure(t);
|
|
|
|
|
|
+ t.procedure(t)
|
|
|
|
|
|
if t.init_context == nil {
|
|
if t.init_context == nil {
|
|
if context.temp_allocator.data == &runtime.global_default_temp_allocator_data {
|
|
if context.temp_allocator.data == &runtime.global_default_temp_allocator_data {
|
|
- runtime.default_temp_allocator_destroy(auto_cast context.temp_allocator.data);
|
|
|
|
|
|
+ runtime.default_temp_allocator_destroy(auto_cast context.temp_allocator.data)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- intrinsics.atomic_store(&t.done, true);
|
|
|
|
- return 0;
|
|
|
|
|
|
+ intrinsics.atomic_store(&t.done, true)
|
|
|
|
+ return 0
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
- thread := new(Thread);
|
|
|
|
|
|
+ thread := new(Thread)
|
|
if thread == nil {
|
|
if thread == nil {
|
|
- return nil;
|
|
|
|
|
|
+ return nil
|
|
}
|
|
}
|
|
- thread.creation_allocator = context.allocator;
|
|
|
|
|
|
+ thread.creation_allocator = context.allocator
|
|
|
|
|
|
- win32_thread_id: win32.DWORD;
|
|
|
|
- win32_thread := win32.CreateThread(nil, 0, __windows_thread_entry_proc, thread, win32.CREATE_SUSPENDED, &win32_thread_id);
|
|
|
|
|
|
+ win32_thread_id: win32.DWORD
|
|
|
|
+ win32_thread := win32.CreateThread(nil, 0, __windows_thread_entry_proc, thread, win32.CREATE_SUSPENDED, &win32_thread_id)
|
|
if win32_thread == nil {
|
|
if win32_thread == nil {
|
|
- free(thread, thread.creation_allocator);
|
|
|
|
- return nil;
|
|
|
|
|
|
+ free(thread, thread.creation_allocator)
|
|
|
|
+ return nil
|
|
}
|
|
}
|
|
- thread.procedure = procedure;
|
|
|
|
- thread.win32_thread = win32_thread;
|
|
|
|
- thread.win32_thread_id = win32_thread_id;
|
|
|
|
- thread.init_context = context;
|
|
|
|
|
|
+ thread.procedure = procedure
|
|
|
|
+ thread.win32_thread = win32_thread
|
|
|
|
+ thread.win32_thread_id = win32_thread_id
|
|
|
|
+ thread.init_context = context
|
|
|
|
|
|
- return thread;
|
|
|
|
|
|
+ return thread
|
|
}
|
|
}
|
|
|
|
|
|
thread_start :: proc "contextless" (thread: ^Thread) {
|
|
thread_start :: proc "contextless" (thread: ^Thread) {
|
|
- win32.ResumeThread(thread.win32_thread);
|
|
|
|
|
|
+ win32.ResumeThread(thread.win32_thread)
|
|
}
|
|
}
|
|
|
|
|
|
thread_join_and_destroy :: proc(thread: ^Thread) {
|
|
thread_join_and_destroy :: proc(thread: ^Thread) {
|
|
if thread.win32_thread != win32.INVALID_HANDLE {
|
|
if thread.win32_thread != win32.INVALID_HANDLE {
|
|
- win32.WaitForSingleObject(thread.win32_thread, win32.INFINITE);
|
|
|
|
- win32.CloseHandle(thread.win32_thread);
|
|
|
|
- thread.win32_thread = win32.INVALID_HANDLE;
|
|
|
|
|
|
+ win32.WaitForSingleObject(thread.win32_thread, win32.INFINITE)
|
|
|
|
+ win32.CloseHandle(thread.win32_thread)
|
|
|
|
+ thread.win32_thread = win32.INVALID_HANDLE
|
|
}
|
|
}
|
|
- free(thread, thread.creation_allocator);
|
|
|
|
|
|
+ free(thread, thread.creation_allocator)
|
|
}
|
|
}
|
|
|
|
|
|
thread_terminate :: proc "contextless" (thread: ^Thread, exit_code: int) {
|
|
thread_terminate :: proc "contextless" (thread: ^Thread, exit_code: int) {
|
|
- win32.TerminateThread(thread.win32_thread, u32(exit_code));
|
|
|
|
|
|
+ win32.TerminateThread(thread.win32_thread, u32(exit_code))
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-global_threaded_runner_semaphore: Sema;
|
|
|
|
-global_exception_handler: rawptr;
|
|
|
|
-global_current_thread: ^Thread;
|
|
|
|
-global_current_t: ^T;
|
|
|
|
|
|
+global_threaded_runner_semaphore: Sema
|
|
|
|
+global_exception_handler: rawptr
|
|
|
|
+global_current_thread: ^Thread
|
|
|
|
+global_current_t: ^T
|
|
|
|
|
|
run_internal_test :: proc(t: ^T, it: Internal_Test) {
|
|
run_internal_test :: proc(t: ^T, it: Internal_Test) {
|
|
thread := thread_create(proc(thread: ^Thread) {
|
|
thread := thread_create(proc(thread: ^Thread) {
|
|
@@ -140,47 +140,47 @@ run_internal_test :: proc(t: ^T, it: Internal_Test) {
|
|
win32.EXCEPTION_ARRAY_BOUNDS_EXCEEDED,
|
|
win32.EXCEPTION_ARRAY_BOUNDS_EXCEEDED,
|
|
win32.EXCEPTION_STACK_OVERFLOW:
|
|
win32.EXCEPTION_STACK_OVERFLOW:
|
|
|
|
|
|
- sema_post(&global_threaded_runner_semaphore);
|
|
|
|
- return win32.EXCEPTION_EXECUTE_HANDLER;
|
|
|
|
|
|
+ sema_post(&global_threaded_runner_semaphore)
|
|
|
|
+ return win32.EXCEPTION_EXECUTE_HANDLER
|
|
}
|
|
}
|
|
|
|
|
|
- return win32.EXCEPTION_CONTINUE_SEARCH;
|
|
|
|
|
|
+ return win32.EXCEPTION_CONTINUE_SEARCH
|
|
}
|
|
}
|
|
- global_exception_handler = win32.AddVectoredExceptionHandler(0, exception_handler_proc);
|
|
|
|
|
|
+ global_exception_handler = win32.AddVectoredExceptionHandler(0, exception_handler_proc)
|
|
|
|
|
|
context.assertion_failure_proc = proc(prefix, message: string, loc: runtime.Source_Code_Location) -> ! {
|
|
context.assertion_failure_proc = proc(prefix, message: string, loc: runtime.Source_Code_Location) -> ! {
|
|
- errorf(t=global_current_t, format="%s %s", args={prefix, message}, loc=loc);
|
|
|
|
- intrinsics.trap();
|
|
|
|
- };
|
|
|
|
|
|
+ errorf(t=global_current_t, format="%s %s", args={prefix, message}, loc=loc)
|
|
|
|
+ intrinsics.trap()
|
|
|
|
+ }
|
|
|
|
|
|
- thread.it.p(thread.t);
|
|
|
|
|
|
+ thread.it.p(thread.t)
|
|
|
|
|
|
- thread.success = true;
|
|
|
|
- sema_post(&global_threaded_runner_semaphore);
|
|
|
|
- });
|
|
|
|
|
|
+ thread.success = true
|
|
|
|
+ sema_post(&global_threaded_runner_semaphore)
|
|
|
|
+ })
|
|
|
|
|
|
- sema_reset(&global_threaded_runner_semaphore);
|
|
|
|
- global_current_t = t;
|
|
|
|
|
|
+ sema_reset(&global_threaded_runner_semaphore)
|
|
|
|
+ global_current_t = t
|
|
|
|
|
|
t._fail_now = proc() -> ! {
|
|
t._fail_now = proc() -> ! {
|
|
- intrinsics.trap();
|
|
|
|
- };
|
|
|
|
|
|
+ intrinsics.trap()
|
|
|
|
+ }
|
|
|
|
|
|
- thread.t = t;
|
|
|
|
- thread.it = it;
|
|
|
|
- thread.success = false;
|
|
|
|
|
|
+ thread.t = t
|
|
|
|
+ thread.it = it
|
|
|
|
+ thread.success = false
|
|
|
|
|
|
- thread_start(thread);
|
|
|
|
|
|
+ thread_start(thread)
|
|
|
|
|
|
- sema_wait(&global_threaded_runner_semaphore);
|
|
|
|
- thread_terminate(thread, int(!thread.success));
|
|
|
|
- thread_join_and_destroy(thread);
|
|
|
|
|
|
+ sema_wait(&global_threaded_runner_semaphore)
|
|
|
|
+ thread_terminate(thread, int(!thread.success))
|
|
|
|
+ thread_join_and_destroy(thread)
|
|
|
|
|
|
- win32.RemoveVectoredExceptionHandler(global_exception_handler);
|
|
|
|
|
|
+ win32.RemoveVectoredExceptionHandler(global_exception_handler)
|
|
|
|
|
|
if !thread.success && t.error_count == 0 {
|
|
if !thread.success && t.error_count == 0 {
|
|
- t.error_count += 1;
|
|
|
|
|
|
+ t.error_count += 1
|
|
}
|
|
}
|
|
|
|
|
|
- return;
|
|
|
|
|
|
+ return
|
|
}
|
|
}
|