vxx2 / vlib / v3 / tests / spawn_args_test.v
107 lines · 94 sloc · 3.06 KB · 0e30f8d2f2cf6ed81ee9cebe949190dc76b548c9
Raw
1import os
2
3const vexe = @VEXE
4const tests_dir = os.dir(@FILE)
5const v3_dir = os.dir(tests_dir)
6const v3_src = os.join_path(v3_dir, 'v3.v')
7
8fn build_v3() string {
9 v3_bin := os.join_path(os.temp_dir(), 'v3_spawn_args_test')
10 build := os.execute('${vexe} -o ${v3_bin} ${v3_src}')
11 assert build.exit_code == 0, build.output
12 return v3_bin
13}
14
15fn gen_c(v3_bin string, name string, src string) string {
16 src_file := os.join_path(os.temp_dir(), '${name}.v')
17 os.write_file(src_file, src) or { panic(err) }
18 c_out := os.join_path(os.temp_dir(), '${name}.c')
19 os.rm(c_out) or {}
20 compile := os.execute('${v3_bin} ${src_file} -o ${c_out}')
21 assert compile.exit_code == 0, compile.output
22 return os.read_file(c_out) or { '' }
23}
24
25fn assert_spawn_pthread_decls(c_code string) {
26 assert c_code.contains('i32 pthread_attr_init(void* attr);'), c_code
27 assert c_code.contains('i32 pthread_attr_setstacksize(void* attr, size_t stacksize);'), c_code
28 assert c_code.contains('i32 pthread_create(void* thread, void* attr, void* start_routine, void* arg);'), c_code
29 assert c_code.contains('i32 pthread_attr_destroy(void* attr);'), c_code
30 assert c_code.contains('i32 pthread_join(void* thread, void* retval);'), c_code
31}
32
33// A `spawn` of a free function with arguments must pack the arguments into a heap
34// struct and run the real function through a wrapper, instead of emitting a
35// `(void*)0` no-op that silently drops the call and its arguments.
36fn test_spawn_free_function_with_arguments_packs_args() {
37 v3_bin := build_v3()
38 c_code := gen_c(v3_bin, 'v3_spawn_args_free', '
39struct Counter {
40mut:
41 total int
42}
43
44fn add(mut c Counter, a int, b int) {
45 c.total = a + b
46}
47
48fn main() {
49 mut c := Counter{}
50 _ := spawn add(mut c, 3, 4)
51 println("ok")
52}
53')
54 assert c_code.contains('add_thread_args'), c_code
55 assert c_code.contains('pthread_create'), c_code
56 assert_spawn_pthread_decls(c_code)
57 assert c_code.contains('add(p->a0, p->a1, p->a2)'), c_code
58}
59
60// A `spawn` of a method with arguments must pack the receiver and arguments and
61// dispatch the real method instead of dropping the call.
62fn test_spawn_method_with_arguments_packs_receiver_and_args() {
63 v3_bin := build_v3()
64 c_code := gen_c(v3_bin, 'v3_spawn_args_method', '
65struct Counter {
66mut:
67 total int
68}
69
70fn (mut c Counter) bump(x int) {
71 c.total += x
72}
73
74fn main() {
75 mut c := Counter{}
76 _ := spawn c.bump(10)
77 println("ok")
78}
79')
80 assert c_code.contains('pthread_create'), c_code
81 assert c_code.contains('Counter__bump(p->a0, p->a1)'), c_code
82}
83
84// A no-arg `spawn` of a by-value receiver method must copy the receiver into the
85// heap arg struct; casting the void* thread argument straight to the struct type
86// (`(Greeter)arg`) is invalid C.
87fn test_spawn_value_receiver_copies_receiver() {
88 v3_bin := build_v3()
89 c_code := gen_c(v3_bin, 'v3_spawn_value_receiver', '
90struct Greeter {
91 name string
92}
93
94fn (g Greeter) greet() {
95 println(g.name)
96}
97
98fn main() {
99 g := Greeter{name: "world"}
100 _ := spawn g.greet()
101 println("ok")
102}
103')
104 assert c_code.contains('pthread_create'), c_code
105 assert c_code.contains('Greeter__greet(p->a0)'), c_code
106 assert !c_code.contains('(Greeter)arg'), c_code
107}
108