v / vlib / sync / tls_test.v
284 lines · 246 sloc · 7.13 KB · fcbe2e6ce77207e4d35b31cade9d6f1ecef55b5f
Raw
1import sync
2import time
3
4// Testing basic data types
5fn test_basic_tls() {
6 println('--- Testing basic datatypes TLS ---')
7
8 // invalid type
9 sync.new_tls[string]('hello world') or { assert err.msg().contains('invalid type') }
10
11 mut tls_i8 := sync.new_tls[i8](-3)!
12 assert tls_i8.get()! == -3
13 tls_i8.set(-4)!
14 assert tls_i8.get()! == -4
15 tls_i8.destroy()!
16 if v := tls_i8.get() {
17 assert false
18 } else {
19 assert err.msg().contains('already destroyed')
20 }
21 tls_i8.set(-5) or { assert err.msg().contains('already destroyed') }
22
23 mut tls_i16 := sync.new_tls[i16](-57)!
24 assert tls_i16.get()! == -57
25 tls_i16.set(-58)!
26 assert tls_i16.get()! == -58
27 tls_i16.destroy()!
28 if v := tls_i16.get() {
29 assert false
30 } else {
31 assert err.msg().contains('already destroyed')
32 }
33 tls_i16.set(-59) or { assert err.msg().contains('already destroyed') }
34
35 mut tls_i32 := sync.new_tls[i32](-570)!
36 assert tls_i32.get()! == -570
37 tls_i32.set(-580)!
38 assert tls_i32.get()! == -580
39 tls_i32.destroy()!
40 if v := tls_i32.get() {
41 assert false
42 } else {
43 assert err.msg().contains('already destroyed')
44 }
45 tls_i32.set(-59) or { assert err.msg().contains('already destroyed') }
46
47 mut tls_i64 := sync.new_tls[i64](-5700)!
48 assert tls_i64.get()! == -5700
49 tls_i64.set(-5800)!
50 assert tls_i64.get()! == -5800
51 tls_i64.destroy()!
52 if v := tls_i64.get() {
53 assert false
54 } else {
55 assert err.msg().contains('already destroyed')
56 }
57 tls_i64.set(-5900) or { assert err.msg().contains('already destroyed') }
58
59 mut tls_u8 := sync.new_tls[u8](3)!
60 assert tls_u8.get()! == 3
61 tls_u8.set(4)!
62 assert tls_u8.get()! == 4
63 tls_u8.destroy()!
64 if v := tls_u8.get() {
65 assert false
66 } else {
67 assert err.msg().contains('already destroyed')
68 }
69 tls_u8.set(5) or { assert err.msg().contains('already destroyed') }
70
71 mut tls_u16 := sync.new_tls[i16](57)!
72 assert tls_u16.get()! == 57
73 tls_u16.set(58)!
74 assert tls_u16.get()! == 58
75 tls_u16.destroy()!
76 if v := tls_u16.get() {
77 assert false
78 } else {
79 assert err.msg().contains('already destroyed')
80 }
81 tls_u16.set(59) or { assert err.msg().contains('already destroyed') }
82
83 mut tls_u32 := sync.new_tls[u32](570)!
84 assert tls_u32.get()! == 570
85 tls_u32.set(580)!
86 assert tls_u32.get()! == 580
87 tls_u32.destroy()!
88 if v := tls_u32.get() {
89 assert false
90 } else {
91 assert err.msg().contains('already destroyed')
92 }
93 tls_u32.set(590) or { assert err.msg().contains('already destroyed') }
94
95 mut tls_u64 := sync.new_tls[u64](5700)!
96 assert tls_u64.get()! == 5700
97 tls_u64.set(5800)!
98 assert tls_u64.get()! == 5800
99 tls_u64.destroy()!
100 if v := tls_u64.get() {
101 assert false
102 } else {
103 assert err.msg().contains('already destroyed')
104 }
105 tls_u64.set(5900) or { assert err.msg().contains('already destroyed') }
106
107 mut tls_isize := sync.new_tls[isize](-57000)!
108 assert tls_isize.get()! == -57000
109 tls_isize.set(-58000)!
110 assert tls_isize.get()! == -58000
111 tls_isize.destroy()!
112 if v := tls_isize.get() {
113 assert false
114 } else {
115 assert err.msg().contains('already destroyed')
116 }
117 tls_isize.set(-59000) or { assert err.msg().contains('already destroyed') }
118
119 mut tls_usize := sync.new_tls[usize](57000)!
120 assert tls_usize.get()! == 57000
121 tls_usize.set(58000)!
122 assert tls_usize.get()! == 58000
123 tls_usize.destroy()!
124 if v := tls_usize.get() {
125 assert false
126 } else {
127 assert err.msg().contains('already destroyed')
128 }
129 tls_usize.set(59000) or { assert err.msg().contains('already destroyed') }
130
131 mut tls_int := sync.new_tls[int](-32767)!
132 assert tls_int.get()! == -32767
133 tls_int.set(-32768)!
134 assert tls_int.get()! == -32768
135 tls_int.destroy()!
136 if v := tls_int.get() {
137 assert false
138 } else {
139 assert err.msg().contains('already destroyed')
140 }
141 tls_int.set(-32769) or { assert err.msg().contains('already destroyed') }
142
143 mut tls_f32 := sync.new_tls[f32](1.5)!
144 assert tls_f32.get()! == 1.5
145 tls_f32.set(2.5)!
146 assert tls_f32.get()! == 2.5
147 tls_f32.destroy()!
148 if v := tls_f32.get() {
149 assert false
150 } else {
151 assert err.msg().contains('already destroyed')
152 }
153 tls_f32.set(3.5) or { assert err.msg().contains('already destroyed') }
154
155 mut tls_f64 := sync.new_tls[f64](-1.5)!
156 assert tls_f64.get()! == -1.5
157 tls_f64.set(-2.5)!
158 assert tls_f64.get()! == -2.5
159 tls_f64.destroy()!
160 if v := tls_f64.get() {
161 assert false
162 } else {
163 assert err.msg().contains('already destroyed')
164 }
165 tls_f64.set(-3.5) or { assert err.msg().contains('already destroyed') }
166}
167
168// Testing pointer type
169struct PtrData {
170 id int
171 val string
172}
173
174fn test_pointer_tls() {
175 println('--- Testing pointer TLS ---')
176
177 data := &PtrData{
178 id: 100
179 val: 'initial'
180 }
181 mut tls := sync.new_tls[&PtrData](data) or { panic('Failed to create TLS: ${err}') }
182
183 // Verify initial value
184 assert tls.get()!.id == 100
185 assert tls.get()!.val == 'initial'
186
187 // Update and verify new value
188 new_data := &PtrData{
189 id: 200
190 val: 'updated'
191 }
192 tls.set(new_data)!
193 assert tls.get()!.id == 200
194 assert tls.get()!.val == 'updated'
195
196 tls.destroy()!
197 // Attempt to set value after destruction
198 tls.set(data) or { assert err.msg().contains('already destroyed') }
199
200 // Attempt to get value after destruction
201 if res_get := tls.get() {
202 assert false
203 } else {
204 assert err.msg().contains('already destroyed')
205 }
206}
207
208// Thread worker function
209fn thread_worker(tls &sync.ThreadLocalStorage[u64], thread_id u64) {
210 mut mut_tls := unsafe { tls }
211 // Each thread sets a unique value
212 mut_tls.set(thread_id * 100) or { panic(err) }
213
214 // Simulate work with a delay
215 time.sleep(10 * time.millisecond)
216
217 // Retrieve and verify thread-private value
218 val := mut_tls.get() or { panic(err) }
219 assert val == thread_id * 100
220 println('Thread ${thread_id}: TLS value = ${val}')
221}
222
223// Testing multi-thread isolation
224fn test_thread_isolation() {
225 println('--- Testing multi-thread isolation ---')
226
227 // Create shared TLS instance
228 mut tls := sync.new_tls[u64](3366) or { panic(err) }
229 defer { tls.destroy() or { panic(err) } }
230
231 // Create multiple threads
232 mut threads := []thread{}
233 for i in 1 .. 5 {
234 threads << spawn thread_worker(&tls, u64(i))
235 }
236
237 // Wait for all threads to complete
238 threads.wait()
239
240 // Verify main thread value remains unchanged
241 println('Main thread value after operations: ${tls.get()!}')
242 assert tls.get()! == 3366
243}
244
245// Thread worker function
246fn worker(int_tls &sync.ThreadLocalStorage[int],
247 f64_tls &sync.ThreadLocalStorage[f64]) {
248 mut mut_int_tls := unsafe { int_tls }
249 mut mut_f64_tls := unsafe { f64_tls }
250 // Update integer value
251 mut_int_tls.set(100) or { panic(err) }
252 v := mut_int_tls.get() or { panic(err) }
253 assert v == 100
254
255 // Update floating-point value
256 mut_f64_tls.set(2.5) or { panic(err) }
257 s := mut_f64_tls.get() or { panic(err) }
258 assert s == 2.5
259}
260
261// Testing cross-thread type safety
262fn test_cross_thread_type() {
263 println('--- Testing cross-thread type safety ---')
264
265 mut int_tls := sync.new_tls[int](42) or { panic(err) }
266 defer { int_tls.destroy() or { panic(err) } }
267
268 mut f64_tls := sync.new_tls[f64](1.5) or { panic(err) }
269 defer { f64_tls.destroy() or { panic(err) } }
270
271 shared_int_tls := &int_tls
272 shared_f64_tls := &f64_tls
273
274 // Create and wait for threads
275 threads := [
276 spawn worker(shared_int_tls, shared_f64_tls),
277 spawn worker(shared_int_tls, shared_f64_tls),
278 ]
279 threads.wait()
280
281 // Verify original values in main thread
282 assert int_tls.get()! == 42
283 assert f64_tls.get()! == 1.5
284}
285