aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaytan Laats <laytanlaats@hotmail.com>2023-11-09 12:12:01 +0100
committerLaytan Laats <laytanlaats@hotmail.com>2023-11-15 19:08:03 +0100
commit9078ddaf5a89b1b8d46f0fa7d86dee027f686f5a (patch)
treebb55433d4685d3a57f4c63cd98857f923e4a9d5e
parent8028033513d21219886516a4d356949ebbd7489b (diff)
Allow larger thread poly data
The poly data currently has the restriction of being less than a pointer's size, but there is much more space in the `Thread.user_args` array which can be utilized, this commit allows you to pass types that are larger than pointer length as long as the total size of the poly data is less than that of the `Thread.user_args`.
-rw-r--r--core/thread/thread.odin93
-rw-r--r--tests/core/Makefile5
-rw-r--r--tests/core/build.bat5
-rw-r--r--tests/core/thread/test_core_thread.odin80
4 files changed, 144 insertions, 39 deletions
diff --git a/core/thread/thread.odin b/core/thread/thread.odin
index 9ba03203f..9fcc5b84f 100644
--- a/core/thread/thread.odin
+++ b/core/thread/thread.odin
@@ -116,26 +116,21 @@ run_with_data :: proc(data: rawptr, fn: proc(data: rawptr), init_context: Maybe(
}
run_with_poly_data :: proc(data: $T, fn: proc(data: T), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal)
- where size_of(T) <= size_of(rawptr) {
+ where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
create_and_start_with_poly_data(data, fn, init_context, priority, true)
}
run_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal)
- where size_of(T1) <= size_of(rawptr),
- size_of(T2) <= size_of(rawptr) {
+ where size_of(T1) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
create_and_start_with_poly_data2(arg1, arg2, fn, init_context, priority, true)
}
run_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: proc(arg1: T1, arg2: T2, arg3: T3), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal)
- where size_of(T1) <= size_of(rawptr),
- size_of(T2) <= size_of(rawptr),
- size_of(T3) <= size_of(rawptr) {
+ where size_of(T1) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
create_and_start_with_poly_data3(arg1, arg2, arg3, fn, init_context, priority, true)
}
run_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: $T4, fn: proc(arg1: T1, arg2: T2, arg3: T3, arg4: T4), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal)
- where size_of(T1) <= size_of(rawptr),
- size_of(T2) <= size_of(rawptr),
- size_of(T3) <= size_of(rawptr) {
+ where size_of(T1) + size_of(T2) + size_of(T3) + size_of(T4) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
create_and_start_with_poly_data4(arg1, arg2, arg3, arg4, fn, init_context, priority, true)
}
@@ -178,7 +173,7 @@ create_and_start_with_data :: proc(data: rawptr, fn: proc(data: rawptr), init_co
}
create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread
- where size_of(T) <= size_of(rawptr) {
+ where size_of(T) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
thread_proc :: proc(t: ^Thread) {
fn := cast(proc(T))t.data
assert(t.user_index >= 1)
@@ -188,96 +183,118 @@ create_and_start_with_poly_data :: proc(data: $T, fn: proc(data: T), init_contex
t := create(thread_proc, priority)
t.data = rawptr(fn)
t.user_index = 1
+
data := data
- mem.copy(&t.user_args[0], &data, size_of(data))
+
+ mem.copy(&t.user_args[0], &data, size_of(T))
+
if self_cleanup {
t.flags += {.Self_Cleanup}
}
+
t.init_context = init_context
start(t)
return t
}
create_and_start_with_poly_data2 :: proc(arg1: $T1, arg2: $T2, fn: proc(T1, T2), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread
- where size_of(T1) <= size_of(rawptr),
- size_of(T2) <= size_of(rawptr) {
+ where size_of(T1) + size_of(T2) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
thread_proc :: proc(t: ^Thread) {
fn := cast(proc(T1, T2))t.data
assert(t.user_index >= 2)
- arg1 := (^T1)(&t.user_args[0])^
- arg2 := (^T2)(&t.user_args[1])^
+
+ user_args := mem.slice_to_bytes(t.user_args[:])
+ arg1 := (^T1)(raw_data(user_args))^
+ arg2 := (^T2)(raw_data(user_args[size_of(T1):]))^
+
fn(arg1, arg2)
}
t := create(thread_proc, priority)
t.data = rawptr(fn)
t.user_index = 2
+
arg1, arg2 := arg1, arg2
- mem.copy(&t.user_args[0], &arg1, size_of(arg1))
- mem.copy(&t.user_args[1], &arg2, size_of(arg2))
+ user_args := mem.slice_to_bytes(t.user_args[:])
+
+ n := copy(user_args, mem.ptr_to_bytes(&arg1))
+ _ = copy(user_args[n:], mem.ptr_to_bytes(&arg2))
+
if self_cleanup {
t.flags += {.Self_Cleanup}
}
+
t.init_context = init_context
start(t)
return t
}
create_and_start_with_poly_data3 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, fn: proc(arg1: T1, arg2: T2, arg3: T3), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread
- where size_of(T1) <= size_of(rawptr),
- size_of(T2) <= size_of(rawptr),
- size_of(T3) <= size_of(rawptr) {
+ where size_of(T1) + size_of(T2) + size_of(T3) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
thread_proc :: proc(t: ^Thread) {
fn := cast(proc(T1, T2, T3))t.data
assert(t.user_index >= 3)
- arg1 := (^T1)(&t.user_args[0])^
- arg2 := (^T2)(&t.user_args[1])^
- arg3 := (^T3)(&t.user_args[2])^
+
+ user_args := mem.slice_to_bytes(t.user_args[:])
+ arg1 := (^T1)(raw_data(user_args))^
+ arg2 := (^T2)(raw_data(user_args[size_of(T1):]))^
+ arg3 := (^T3)(raw_data(user_args[size_of(T1) + size_of(T2):]))^
+
fn(arg1, arg2, arg3)
}
t := create(thread_proc, priority)
t.data = rawptr(fn)
t.user_index = 3
+
arg1, arg2, arg3 := arg1, arg2, arg3
- mem.copy(&t.user_args[0], &arg1, size_of(arg1))
- mem.copy(&t.user_args[1], &arg2, size_of(arg2))
- mem.copy(&t.user_args[2], &arg3, size_of(arg3))
+ user_args := mem.slice_to_bytes(t.user_args[:])
+
+ n := copy(user_args, mem.ptr_to_bytes(&arg1))
+ n += copy(user_args[n:], mem.ptr_to_bytes(&arg2))
+ _ = copy(user_args[n:], mem.ptr_to_bytes(&arg3))
+
if self_cleanup {
t.flags += {.Self_Cleanup}
}
+
t.init_context = init_context
start(t)
return t
}
create_and_start_with_poly_data4 :: proc(arg1: $T1, arg2: $T2, arg3: $T3, arg4: $T4, fn: proc(arg1: T1, arg2: T2, arg3: T3, arg4: T4), init_context: Maybe(runtime.Context) = nil, priority := Thread_Priority.Normal, self_cleanup := false) -> ^Thread
- where size_of(T1) <= size_of(rawptr),
- size_of(T2) <= size_of(rawptr),
- size_of(T3) <= size_of(rawptr) {
+ where size_of(T1) + size_of(T2) + size_of(T3) + size_of(T4) <= size_of(rawptr) * MAX_USER_ARGUMENTS {
thread_proc :: proc(t: ^Thread) {
fn := cast(proc(T1, T2, T3, T4))t.data
assert(t.user_index >= 4)
- arg1 := (^T1)(&t.user_args[0])^
- arg2 := (^T2)(&t.user_args[1])^
- arg3 := (^T3)(&t.user_args[2])^
- arg4 := (^T4)(&t.user_args[3])^
+
+ user_args := mem.slice_to_bytes(t.user_args[:])
+ arg1 := (^T1)(raw_data(user_args))^
+ arg2 := (^T2)(raw_data(user_args[size_of(T1):]))^
+ arg3 := (^T3)(raw_data(user_args[size_of(T1) + size_of(T2):]))^
+ arg4 := (^T4)(raw_data(user_args[size_of(T1) + size_of(T2) + size_of(T3):]))^
+
fn(arg1, arg2, arg3, arg4)
}
t := create(thread_proc, priority)
t.data = rawptr(fn)
t.user_index = 4
+
arg1, arg2, arg3, arg4 := arg1, arg2, arg3, arg4
- mem.copy(&t.user_args[0], &arg1, size_of(arg1))
- mem.copy(&t.user_args[1], &arg2, size_of(arg2))
- mem.copy(&t.user_args[2], &arg3, size_of(arg3))
- mem.copy(&t.user_args[3], &arg4, size_of(arg4))
+ user_args := mem.slice_to_bytes(t.user_args[:])
+
+ n := copy(user_args, mem.ptr_to_bytes(&arg1))
+ n += copy(user_args[n:], mem.ptr_to_bytes(&arg2))
+ n += copy(user_args[n:], mem.ptr_to_bytes(&arg3))
+ _ = copy(user_args[n:], mem.ptr_to_bytes(&arg4))
+
if self_cleanup {
t.flags += {.Self_Cleanup}
}
+
t.init_context = init_context
start(t)
return t
}
-
_select_context_for_thread :: proc(init_context: Maybe(runtime.Context)) -> runtime.Context {
ctx, ok := init_context.?
if !ok {
diff --git a/tests/core/Makefile b/tests/core/Makefile
index 919262f85..3fdadc246 100644
--- a/tests/core/Makefile
+++ b/tests/core/Makefile
@@ -3,7 +3,7 @@ PYTHON=$(shell which python3)
all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \
math_test linalg_glsl_math_test filepath_test reflect_test os_exit_test i18n_test match_test c_libc_test net_test \
- fmt_test
+ fmt_test thread_test
download_test_assets:
$(PYTHON) download_assets.py
@@ -61,3 +61,6 @@ net_test:
fmt_test:
$(ODIN) run fmt -out:test_core_fmt
+
+thread_test:
+ $(ODIN) run thread -out:test_core_thread
diff --git a/tests/core/build.bat b/tests/core/build.bat
index 1d146c8a4..311c9c78e 100644
--- a/tests/core/build.bat
+++ b/tests/core/build.bat
@@ -85,3 +85,8 @@ echo ---
echo Running core:container tests
echo ---
%PATH_TO_ODIN% run container %COMMON% %COLLECTION% -out:test_core_container.exe || exit /b
+
+echo ---
+echo Running core:thread tests
+echo ---
+%PATH_TO_ODIN% run thread %COMMON% %COLLECTION% -out:test_core_thread.exe || exit /b
diff --git a/tests/core/thread/test_core_thread.odin b/tests/core/thread/test_core_thread.odin
new file mode 100644
index 000000000..e02fcc0f7
--- /dev/null
+++ b/tests/core/thread/test_core_thread.odin
@@ -0,0 +1,80 @@
+package test_core_thread
+
+import "core:testing"
+import "core:thread"
+import "core:fmt"
+import "core:os"
+
+TEST_count := 0
+TEST_fail := 0
+
+t := &testing.T{}
+
+when ODIN_TEST {
+ expect :: testing.expect
+ log :: testing.log
+} else {
+ expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
+ TEST_count += 1
+ if !condition {
+ TEST_fail += 1
+ fmt.printf("[%v] %v\n", loc, message)
+ return
+ }
+ }
+ log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
+ fmt.printf("[%v] ", loc)
+ fmt.printf("log: %v\n", v)
+ }
+}
+
+main :: proc() {
+ poly_data_test(t)
+
+ if TEST_fail > 0 {
+ os.exit(1)
+ }
+}
+
+@(test)
+poly_data_test :: proc(_t: ^testing.T) {
+ MAX :: size_of(rawptr) * thread.MAX_USER_ARGUMENTS
+
+ @static t: ^testing.T
+ t = _t
+
+ b: [MAX]byte = 8
+ t1 := thread.create_and_start_with_poly_data(b, proc(b: [MAX]byte) {
+ b_expect: [MAX]byte = 8
+ expect(t, b == b_expect, "thread poly data not correct")
+ }, self_cleanup = true)
+
+ b1: [3]uintptr = 1
+ b2: [MAX / 2]byte = 3
+ t2 := thread.create_and_start_with_poly_data2(b1, b2, proc(b: [3]uintptr, b2: [MAX / 2]byte) {
+ b_expect: [3]uintptr = 1
+ b2_expect: [MAX / 2]byte = 3
+ expect(t, b == b_expect, "thread poly data not correct")
+ expect(t, b2 == b2_expect, "thread poly data not correct")
+ }, self_cleanup = true)
+
+ t3 := thread.create_and_start_with_poly_data3(b1, b2, uintptr(333), proc(b: [3]uintptr, b2: [MAX / 2]byte, b3: uintptr) {
+ b_expect: [3]uintptr = 1
+ b2_expect: [MAX / 2]byte = 3
+
+ expect(t, b == b_expect, "thread poly data not correct")
+ expect(t, b2 == b2_expect, "thread poly data not correct")
+ expect(t, b3 == 333, "thread poly data not correct")
+ }, self_cleanup = true)
+
+ t4 := thread.create_and_start_with_poly_data4(uintptr(111), b1, uintptr(333), u8(5), proc(n: uintptr, b: [3]uintptr, n2: uintptr, n4: u8) {
+ b_expect: [3]uintptr = 1
+
+ expect(t, n == 111, "thread poly data not correct")
+ expect(t, b == b_expect, "thread poly data not correct")
+ expect(t, n2 == 333, "thread poly data not correct")
+ expect(t, n4 == 5, "thread poly data not correct")
+ }, self_cleanup = true)
+
+ thread.join_multiple(t1, t2, t3, t4)
+}