Line | Branch | Exec | Source |
---|---|---|---|
1 | /* GATE PROJECT LICENSE: | ||
2 | +----------------------------------------------------------------------------+ | ||
3 | | Copyright(c) 2018-2025, Stefan Meislinger <sm@opengate.at> | | ||
4 | | All rights reserved. | | ||
5 | | | | ||
6 | | Redistribution and use in source and binary forms, with or without | | ||
7 | | modification, are permitted provided that the following conditions are met:| | ||
8 | | | | ||
9 | | 1. Redistributions of source code must retain the above copyright notice, | | ||
10 | | this list of conditions and the following disclaimer. | | ||
11 | | 2. Redistributions in binary form must reproduce the above copyright | | ||
12 | | notice, this list of conditions and the following disclaimer in the | | ||
13 | | documentation and/or other materials provided with the distribution. | | ||
14 | | | | ||
15 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"| | ||
16 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | ||
17 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ||
18 | | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | | ||
19 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | ||
20 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | ||
21 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | ||
22 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | ||
23 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | ||
24 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | | ||
25 | | THE POSSIBILITY OF SUCH DAMAGE. | | ||
26 | +----------------------------------------------------------------------------+ | ||
27 | */ | ||
28 | |||
29 | #include "gate/threading.h" | ||
30 | #include "gate/memalloc.h" | ||
31 | #include "gate/debugging.h" | ||
32 | #include "gate/coroutines.h" | ||
33 | #include "gate/times.h" | ||
34 | #include "gate/results.h" | ||
35 | #include "gate/atomics.h" | ||
36 | |||
37 | |||
38 | /* platform independent code: */ | ||
39 | |||
40 | 6 | static gate_thread_native_return_type GATE_THREAD_API gate_thread_start_entry_point(gate_thread_native_param_type param) | |
41 | { | ||
42 | 6 | gate_runnable_t* executor = (gate_runnable_t*)(void*)param; | |
43 | 6 | gate_result_t ret = GATE_RESULT_NULLPOINTER; | |
44 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if (executor) |
45 | { | ||
46 | 6 | ret = gate_runnable_run(executor); | |
47 | 6 | gate_object_release(executor); | |
48 | } | ||
49 | else | ||
50 | { | ||
51 | ✗ | ret = GATE_RESULT_NULLPOINTER; | |
52 | } | ||
53 | 6 | return (gate_thread_native_return_type)(gate_intptr_t)ret; | |
54 | } | ||
55 | |||
56 | 6 | gate_result_t gate_thread_start(gate_runnable_t* executor, gate_thread_t* thread_handle, gate_thread_id_t* thread_id) | |
57 | { | ||
58 | 6 | gate_result_t ret = GATE_RESULT_FAILED; | |
59 | |||
60 | do | ||
61 | { | ||
62 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (executor == NULL) |
63 | { | ||
64 | ✗ | ret = GATE_RESULT_NULLPOINTER; | |
65 | ✗ | break; | |
66 | } | ||
67 | |||
68 | 6 | gate_object_retain(executor); | |
69 | 6 | ret = gate_thread_start_native(&gate_thread_start_entry_point, | |
70 | (gate_thread_native_param_type)(void*)executor, | ||
71 | thread_handle, thread_id); | ||
72 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | if (GATE_SUCCEEDED(ret)) |
73 | { | ||
74 | 6 | executor = NULL; | |
75 | } | ||
76 | } while (0); | ||
77 | |||
78 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (executor != NULL) |
79 | { | ||
80 | ✗ | gate_object_release(executor); | |
81 | } | ||
82 | |||
83 | 6 | return ret; | |
84 | } | ||
85 | |||
86 | |||
87 | |||
88 | |||
89 | typedef struct gate_thread_dispatcher | ||
90 | { | ||
91 | GATE_INTERFACE_VTBL(gate_runnable) const* vtbl; | ||
92 | gate_atomic_int_t ref_counter; | ||
93 | gate_result_t(*callback)(void*); | ||
94 | void* data; | ||
95 | } gate_thread_dispatcher_t; | ||
96 | |||
97 | 4 | static void gate_thread_dispatcher_release(void* disp) | |
98 | { | ||
99 | 4 | gate_thread_dispatcher_t* ptr = (gate_thread_dispatcher_t*)disp; | |
100 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
|
4 | if (gate_atomic_int_dec(&ptr->ref_counter) == 0) |
101 | { | ||
102 | 2 | gate_mem_dealloc(ptr); | |
103 | } | ||
104 | 4 | } | |
105 | 2 | static int gate_thread_dispatcher_retain(void* disp) | |
106 | { | ||
107 | 2 | gate_thread_dispatcher_t* ptr = (gate_thread_dispatcher_t*)disp; | |
108 | 2 | return (int)gate_atomic_int_inc(&ptr->ref_counter); | |
109 | } | ||
110 | ✗ | static char const* gate_thread_dispatcher_get_interface_name(void* disp) | |
111 | { | ||
112 | (void)disp; | ||
113 | ✗ | return GATE_INTERFACE_NAME_RUNNABLE; | |
114 | } | ||
115 | |||
116 | 2 | static gate_result_t gate_thread_dispatcher_run(void* disp) | |
117 | { | ||
118 | 2 | gate_thread_dispatcher_t* ptr = (gate_thread_dispatcher_t*)disp; | |
119 | 2 | return ptr->callback(ptr->data); | |
120 | } | ||
121 | |||
122 | static GATE_INTERFACE_VTBL(gate_runnable) gate_thread_dispatcher_vtbl; | ||
123 | 2 | static void gate_init_thread_dispatcher_vtbl() | |
124 | { | ||
125 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (!gate_thread_dispatcher_vtbl.get_interface_name) |
126 | { | ||
127 | GATE_INTERFACE_VTBL(gate_runnable) const local_vtbl = | ||
128 | { | ||
129 | &gate_thread_dispatcher_get_interface_name, | ||
130 | &gate_thread_dispatcher_release, | ||
131 | &gate_thread_dispatcher_retain, | ||
132 | &gate_thread_dispatcher_run | ||
133 | }; | ||
134 | 2 | gate_thread_dispatcher_vtbl = local_vtbl; | |
135 | } | ||
136 | 2 | } | |
137 | |||
138 | 2 | gate_result_t gate_thread_start_code(gate_result_t(*callback)(void*), void* data, gate_thread_t* threadhandle, gate_thread_id_t* threadid) | |
139 | { | ||
140 | gate_result_t ret; | ||
141 | 2 | gate_thread_dispatcher_t* disp = gate_mem_alloc(sizeof(gate_thread_dispatcher_t)); | |
142 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (disp == NULL) |
143 | { | ||
144 | ✗ | ret = GATE_RESULT_OUTOFMEMORY; | |
145 | } | ||
146 | else | ||
147 | { | ||
148 | 2 | gate_init_thread_dispatcher_vtbl(); | |
149 | 2 | disp->vtbl = &gate_thread_dispatcher_vtbl; | |
150 | 2 | gate_atomic_int_init(&disp->ref_counter, 1); | |
151 | 2 | disp->callback = callback; | |
152 | 2 | disp->data = data; | |
153 | 2 | ret = gate_thread_start((gate_runnable_t*)disp, threadhandle, threadid); | |
154 | 2 | gate_object_release(disp); | |
155 | } | ||
156 | 2 | return ret; | |
157 | } | ||
158 | |||
159 | #if defined(GATE_USE_COROUTINE_THREADS) | ||
160 | # define GATE_THREADING_COROUTINES 1 | ||
161 | #elif defined(GATE_USE_STD_THREADS) && !defined(__STDC_NO_THREADS__) | ||
162 | # define GATE_THREADING_STD_C 1 | ||
163 | #elif defined(GATE_SYS_WASM) | ||
164 | # define GATE_THREADING_WASM 1 | ||
165 | #elif defined(GATE_SYS_WIN) | ||
166 | # define GATE_THREADING_WINAPI 1 | ||
167 | #elif defined(GATE_SYS_BEOS) | ||
168 | # define GATE_THREADING_BEOS 1 | ||
169 | #elif defined(GATE_SYS_POSIX) | ||
170 | # define GATE_THREADING_PTHREAD 1 | ||
171 | #else | ||
172 | # define GATE_THREADING_NO_IMPL 1 | ||
173 | #endif | ||
174 | |||
175 | |||
176 | #if defined(GATE_THREADING_STD_C) | ||
177 | |||
178 | #if defined _MSC_VER | ||
179 | # include <thr/xthreads.h> | ||
180 | # include <windows.h> | ||
181 | |||
182 | |||
183 | typedef _Thrd_t thrd_t; | ||
184 | typedef _Thrd_start_t thrd_start_t; | ||
185 | |||
186 | #define thrd_create(thr, fun, arg) _Thrd_create(thr, fun, arg) | ||
187 | |||
188 | #define thrd_detach(thr) _Thrd_detach(thr) | ||
189 | #define thrd_exit(code) _Thrd_exit(code) | ||
190 | #define thrd_join(thr, res) _Thrd_join(thr, res) | ||
191 | #define thrd_sleep(tm) _Thrd_sleep(tm) | ||
192 | #define thrd_yield _Thrd_yield | ||
193 | #define thrd_equal(thr0, thr1) _Thrd_equal(thr0, thr1) | ||
194 | #define thrd_current _Thrd_current | ||
195 | |||
196 | #define thrd_success _Thrd_success | ||
197 | #define thrd_nomem _Thrd_nomem | ||
198 | #define thrd_error _Thrd_error | ||
199 | |||
200 | |||
201 | typedef DWORD tss_t; | ||
202 | typedef void(*tss_dtor_t)(void*); | ||
203 | |||
204 | int tss_create(tss_t* tss_key, tss_dtor_t dtor) | ||
205 | { | ||
206 | if (!tss_key) | ||
207 | { | ||
208 | return thrd_error; | ||
209 | } | ||
210 | *tss_key = TlsAlloc(); | ||
211 | if (*tss_key == TLS_OUT_OF_INDEXES) | ||
212 | { | ||
213 | return thrd_error; | ||
214 | } | ||
215 | return thrd_success; | ||
216 | } | ||
217 | void* tss_get(tss_t tss_key) | ||
218 | { | ||
219 | return TlsGetValue(tss_key); | ||
220 | } | ||
221 | int tss_set(tss_t tss_id, void* val) | ||
222 | { | ||
223 | if (TlsSetValue(tss_id, val)) | ||
224 | { | ||
225 | return thrd_success; | ||
226 | } | ||
227 | else | ||
228 | { | ||
229 | return thrd_error; | ||
230 | } | ||
231 | } | ||
232 | void tss_delete(tss_t tss_id) | ||
233 | { | ||
234 | TlsFree(tss_id); | ||
235 | } | ||
236 | |||
237 | |||
238 | #else | ||
239 | # include <threads.h> | ||
240 | #endif | ||
241 | #include <time.h> | ||
242 | |||
243 | static int gate_thread_entry_function(void* ptr) | ||
244 | { | ||
245 | gate_runnable_t* executor = (gate_runnable_t*)ptr; | ||
246 | gate_result_t ret = gate_runnable_run(executor); | ||
247 | gate_object_release(executor); | ||
248 | return ret; | ||
249 | } | ||
250 | |||
251 | gate_enumint_t gate_thread_model() | ||
252 | { | ||
253 | return GATE_THREAD_MODEL_NATIVE; | ||
254 | } | ||
255 | |||
256 | gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function, gate_thread_native_param_type entry_param, | ||
257 | gate_thread_t* thread_handle, gate_thread_id_t* thread_id) | ||
258 | { | ||
259 | gate_result_t ret = GATE_RESULT_FAILED; | ||
260 | thrd_t* th = NULL; | ||
261 | |||
262 | do | ||
263 | { | ||
264 | if (entry_function == NULL) | ||
265 | { | ||
266 | ret = GATE_RESULT_NULLPOINTER; | ||
267 | break; | ||
268 | } | ||
269 | |||
270 | th = GATE_HANDLESTORE_CREATE(thread_handle, thrd_t); | ||
271 | if (th == NULL) | ||
272 | { | ||
273 | ret = GATE_RESULT_OUTOFMEMORY; | ||
274 | break; | ||
275 | } | ||
276 | |||
277 | int result = thrd_create(th, entry_function, entry_param); | ||
278 | switch (result) | ||
279 | { | ||
280 | case thrd_success: | ||
281 | { | ||
282 | if (thread_id != NULL) | ||
283 | { | ||
284 | *thread_id = (gate_uintptr_t)th; | ||
285 | } | ||
286 | break; | ||
287 | } | ||
288 | case thrd_nomem: | ||
289 | { | ||
290 | GATE_HANDLESTORE_DESTROY(thread_handle); | ||
291 | ret = GATE_RESULT_OUTOFRESOURCES; | ||
292 | break; | ||
293 | } | ||
294 | default: | ||
295 | { | ||
296 | GATE_HANDLESTORE_DESTROY(thread_handle); | ||
297 | ret = GATE_RESULT_FAILED; | ||
298 | break; | ||
299 | } | ||
300 | } | ||
301 | |||
302 | } while (0); | ||
303 | return ret; | ||
304 | } | ||
305 | gate_result_t gate_thread_detach(gate_thread_t* thread_handle) | ||
306 | { | ||
307 | thrd_t* th = GATE_HANDLESTORE_ACCESS(thread_handle, thrd_t); | ||
308 | if (th != NULL) | ||
309 | { | ||
310 | thrd_detach(*th); | ||
311 | GATE_HANDLESTORE_DESTROY(thread_handle); | ||
312 | } | ||
313 | return GATE_RESULT_OK; | ||
314 | } | ||
315 | gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* result) | ||
316 | { | ||
317 | gate_result_t ret = GATE_RESULT_INVALIDARG; | ||
318 | thrd_t* th = GATE_HANDLESTORE_ACCESS(thread_handle, thrd_t); | ||
319 | int thread_result; | ||
320 | int api_result; | ||
321 | |||
322 | if (th != NULL) | ||
323 | { | ||
324 | api_result = thrd_join(*th, &thread_result); | ||
325 | if (api_result == thrd_success) | ||
326 | { | ||
327 | ret = thread_result; | ||
328 | if (result) | ||
329 | { | ||
330 | *result = (gate_result_t)thread_result; | ||
331 | } | ||
332 | } | ||
333 | else | ||
334 | { | ||
335 | ret = GATE_RESULT_FAILED; | ||
336 | } | ||
337 | GATE_HANDLESTORE_DESTROY(thread_handle); | ||
338 | } | ||
339 | return ret; | ||
340 | } | ||
341 | gate_result_t gate_thread_current(gate_thread_t* thread_handle, gate_thread_id_t* thread_id) | ||
342 | { | ||
343 | gate_result_t ret = GATE_RESULT_FAILED; | ||
344 | thrd_t* th = GATE_HANDLESTORE_CREATE(thread_handle, thrd_t); | ||
345 | if (th != NULL) | ||
346 | { | ||
347 | *th = thrd_current(); | ||
348 | if (thread_id != NULL) | ||
349 | { | ||
350 | *thread_id = (gate_uintptr_t)th; | ||
351 | } | ||
352 | ret = GATE_RESULT_OK; | ||
353 | } | ||
354 | return ret; | ||
355 | } | ||
356 | gate_result_t gate_thread_is_current(gate_thread_t* threadhandle, gate_bool_t* is_current) | ||
357 | { | ||
358 | thrd_t* thrd = GATE_HANDLESTORE_ACCESS(threadhandle, thrd_t); | ||
359 | thrd_t current_thread = thrd_current(); | ||
360 | |||
361 | if (is_current) | ||
362 | { | ||
363 | *is_current = thrd_equal(current_thread, *thrd) != 0; | ||
364 | } | ||
365 | return GATE_RESULT_OK; | ||
366 | } | ||
367 | gate_bool_t gate_thread_equals(gate_thread_t* th1, gate_thread_t* th2) | ||
368 | { | ||
369 | thrd_t dummy; | ||
370 | thrd_t* thrd1 = GATE_HANDLESTORE_ACCESS(th1, thrd_t); | ||
371 | thrd_t* thrd2 = GATE_HANDLESTORE_ACCESS(th2, thrd_t); | ||
372 | |||
373 | if (thrd1 == NULL || thrd2 == NULL) | ||
374 | { | ||
375 | dummy = thrd_current(); | ||
376 | if (thrd1 == NULL) | ||
377 | { | ||
378 | thrd1 = &dummy; | ||
379 | } | ||
380 | if (thrd2 == NULL) | ||
381 | { | ||
382 | thrd2 = &dummy; | ||
383 | } | ||
384 | } | ||
385 | |||
386 | return (0 == thrd_equal(*thrd1, *thrd2)) ? true : false; | ||
387 | } | ||
388 | void gate_thread_sleep(gate_uint32_t milliseconds) | ||
389 | { | ||
390 | clock_t start = clock(); | ||
391 | clock_t now; | ||
392 | gate_uint32_t diff; | ||
393 | do | ||
394 | { | ||
395 | gate_thread_yield(); | ||
396 | now = clock(); | ||
397 | diff = (gate_uint32_t)((now - start) * 1000 / CLOCKS_PER_SEC); | ||
398 | } while (diff < milliseconds); | ||
399 | } | ||
400 | void gate_thread_yield(void) | ||
401 | { | ||
402 | thrd_yield(); | ||
403 | } | ||
404 | gate_bool_t gate_thread_yield_if_preemptive(void) | ||
405 | { | ||
406 | thrd_yield(); | ||
407 | return true; | ||
408 | } | ||
409 | |||
410 | |||
411 | |||
412 | |||
413 | gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id) | ||
414 | { | ||
415 | tss_t* ptr_tss = GATE_HANDLESTORE_CREATE(ptr_store_id, tss_t); | ||
416 | if (NULL == ptr_tss) | ||
417 | { | ||
418 | return GATE_RESULT_OUTOFMEMORY; | ||
419 | } | ||
420 | if (thrd_success != tss_create(ptr_tss, NULL)) | ||
421 | { | ||
422 | GATE_HANDLESTORE_DESTROY(ptr_store_id); | ||
423 | return GATE_RESULT_FAILED; | ||
424 | } | ||
425 | return GATE_RESULT_OK; | ||
426 | } | ||
427 | gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data) | ||
428 | { | ||
429 | tss_t* ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, tss_t); | ||
430 | if (!ptr_tss) | ||
431 | { | ||
432 | return GATE_RESULT_INVALIDARG; | ||
433 | } | ||
434 | if (thrd_success != tss_set(*ptr_tss, data)) | ||
435 | { | ||
436 | return GATE_RESULT_FAILED; | ||
437 | } | ||
438 | |||
439 | return GATE_RESULT_OK; | ||
440 | } | ||
441 | gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data) | ||
442 | { | ||
443 | tss_t* ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, tss_t); | ||
444 | if (!ptr_tss) | ||
445 | { | ||
446 | return GATE_RESULT_INVALIDARG; | ||
447 | } | ||
448 | if (ptr_data) | ||
449 | { | ||
450 | *ptr_data = tss_get(*ptr_tss); | ||
451 | } | ||
452 | return GATE_RESULT_OK; | ||
453 | } | ||
454 | gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id) | ||
455 | { | ||
456 | tss_t* ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, tss_t); | ||
457 | if (!ptr_tss) | ||
458 | { | ||
459 | return GATE_RESULT_INVALIDARG; | ||
460 | } | ||
461 | tss_delete(*ptr_tss); | ||
462 | GATE_HANDLESTORE_DESTROY(ptr_store_id); | ||
463 | return GATE_RESULT_OK; | ||
464 | } | ||
465 | |||
466 | |||
467 | |||
468 | |||
469 | #endif /* GATE_THREADING_STD_C */ | ||
470 | |||
471 | #if defined(GATE_THREADING_WINAPI) | ||
472 | |||
473 | #include "gate/platforms.h" | ||
474 | |||
475 | gate_enumint_t gate_thread_model() | ||
476 | { | ||
477 | return GATE_THREAD_MODEL_NATIVE; | ||
478 | } | ||
479 | |||
480 | gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function, gate_thread_native_param_type entry_param, | ||
481 | gate_thread_t* thread_handle, gate_thread_id_t* thread_id) | ||
482 | { | ||
483 | gate_result_t ret; | ||
484 | DWORD id; | ||
485 | HANDLE* handle; | ||
486 | if ((entry_function == NULL) || (thread_handle == NULL)) | ||
487 | { | ||
488 | ret = GATE_RESULT_INVALIDARG; | ||
489 | } | ||
490 | else | ||
491 | { | ||
492 | handle = GATE_HANDLESTORE_CREATE(thread_handle, HANDLE); | ||
493 | *handle = gate_win32_createthread(entry_function, entry_param, 0, &id); | ||
494 | if (*handle == NULL) | ||
495 | { | ||
496 | GATE_DEBUG_TRACE("gate_win32_createthread() failed"); | ||
497 | GATE_DEBUG_TRACE_VALUE(gate_win32_getlasterror()); | ||
498 | |||
499 | ret = GATE_RESULT_FAILED; | ||
500 | gate_win32_print_lasterror(&ret, NULL, 0); | ||
501 | GATE_HANDLESTORE_DESTROY(thread_handle); | ||
502 | } | ||
503 | else | ||
504 | { | ||
505 | ret = GATE_RESULT_OK; | ||
506 | if (thread_id != NULL) | ||
507 | { | ||
508 | *thread_id = (gate_thread_id_t)id; | ||
509 | } | ||
510 | } | ||
511 | } | ||
512 | return ret; | ||
513 | |||
514 | } | ||
515 | |||
516 | gate_result_t gate_thread_detach(gate_thread_t* threadhandle) | ||
517 | { | ||
518 | HANDLE* thread = GATE_HANDLESTORE_ACCESS(threadhandle, HANDLE); | ||
519 | |||
520 | GATE_DEBUG_ASSERT(thread != NULL); | ||
521 | |||
522 | if (CloseHandle(*thread)) | ||
523 | { | ||
524 | GATE_HANDLESTORE_DESTROY(threadhandle); | ||
525 | return GATE_RESULT_OK; | ||
526 | } | ||
527 | else | ||
528 | { | ||
529 | GATE_DEBUG_TRACE("CloseHandle() failed"); | ||
530 | GATE_DEBUG_TRACE_VALUE(gate_win32_getlasterror()); | ||
531 | return GATE_RESULT_FAILED; | ||
532 | } | ||
533 | } | ||
534 | gate_result_t gate_thread_join(gate_thread_t* threadhandle, gate_result_t* ptr_result) | ||
535 | { | ||
536 | HANDLE* thread = GATE_HANDLESTORE_ACCESS(threadhandle, HANDLE); | ||
537 | DWORD dwResult = 0; | ||
538 | DWORD dwExitCode = 0; | ||
539 | gate_result_t ret; | ||
540 | |||
541 | GATE_DEBUG_ASSERT(thread != NULL); | ||
542 | |||
543 | dwResult = WaitForSingleObject(*thread, INFINITE); | ||
544 | if (dwResult != WAIT_OBJECT_0) | ||
545 | { | ||
546 | GATE_DEBUG_TRACE("WaitForSingleObject() failed"); | ||
547 | GATE_DEBUG_TRACE_VALUE(dwResult); | ||
548 | |||
549 | ret = GATE_RESULT_CRITICALERROR; | ||
550 | } | ||
551 | else | ||
552 | { | ||
553 | if (GetExitCodeThread(*thread, &dwExitCode)) | ||
554 | { | ||
555 | if (ptr_result != NULL) | ||
556 | { | ||
557 | *ptr_result = (gate_result_t)dwExitCode; | ||
558 | } | ||
559 | ret = GATE_RESULT_OK; | ||
560 | } | ||
561 | else | ||
562 | { | ||
563 | ret = GATE_RESULT_INVALIDOUTPUT; | ||
564 | } | ||
565 | if (CloseHandle(*thread)) | ||
566 | { | ||
567 | GATE_HANDLESTORE_DESTROY(threadhandle); | ||
568 | } | ||
569 | else | ||
570 | { | ||
571 | GATE_DEBUG_TRACE("CloseHandle() failed"); | ||
572 | GATE_DEBUG_TRACE_VALUE(gate_win32_getlasterror()); | ||
573 | ret = GATE_RESULT_FAILED; | ||
574 | } | ||
575 | } | ||
576 | |||
577 | return ret; | ||
578 | } | ||
579 | gate_result_t gate_thread_current(gate_thread_t* threadhandle, gate_thread_id_t* threadid) | ||
580 | { | ||
581 | HANDLE* thread; | ||
582 | |||
583 | if (threadhandle) | ||
584 | { | ||
585 | thread = GATE_HANDLESTORE_CREATE(threadhandle, HANDLE); | ||
586 | if (thread == NULL) | ||
587 | { | ||
588 | return GATE_RESULT_OUTOFMEMORY; | ||
589 | } | ||
590 | *thread = GetCurrentThread(); | ||
591 | } | ||
592 | if (threadid != NULL) | ||
593 | { | ||
594 | *threadid = (gate_thread_id_t)gate_win32_get_thread_id(); //TODO | ||
595 | } | ||
596 | return GATE_RESULT_OK; | ||
597 | } | ||
598 | gate_bool_t gate_thread_equals(gate_thread_t* th1, gate_thread_t* th2) | ||
599 | { | ||
600 | HANDLE* thread1 = GATE_HANDLESTORE_ACCESS(th1, HANDLE); | ||
601 | HANDLE* thread2 = GATE_HANDLESTORE_ACCESS(th2, HANDLE); | ||
602 | return gate_win32_get_thread_handle_id(*thread1) == gate_win32_get_thread_handle_id(*thread2); | ||
603 | } | ||
604 | gate_result_t gate_thread_is_current(gate_thread_t* threadhandle, gate_bool_t* is_current) | ||
605 | { | ||
606 | HANDLE* ptr_thread = GATE_HANDLESTORE_ACCESS(threadhandle, HANDLE); | ||
607 | *is_current = gate_win32_get_thread_handle_id(*ptr_thread) == gate_win32_get_thread_id(); | ||
608 | return GATE_RESULT_OK; | ||
609 | } | ||
610 | void gate_thread_sleep(gate_uint32_t milliseconds) | ||
611 | { | ||
612 | gate_timecounter_t now = 0, start = 0; | ||
613 | gate_int64_t diff; | ||
614 | gate_int64_t timeout; | ||
615 | if (gate_coroutine_enabled()) | ||
616 | { | ||
617 | gate_timecounter_now(&start); | ||
618 | timeout = (gate_int64_t)milliseconds * 1000; | ||
619 | do | ||
620 | { | ||
621 | gate_coroutine_yield(); | ||
622 | gate_timecounter_now(&now); | ||
623 | diff = gate_timecounter_diff(now, start); | ||
624 | } while (diff < timeout); | ||
625 | } | ||
626 | else | ||
627 | { | ||
628 | Sleep((DWORD)milliseconds); | ||
629 | } | ||
630 | } | ||
631 | void gate_thread_yield(void) | ||
632 | { | ||
633 | if (gate_coroutine_enabled()) | ||
634 | { | ||
635 | gate_coroutine_yield(); | ||
636 | } | ||
637 | else | ||
638 | { | ||
639 | Sleep(0); | ||
640 | } | ||
641 | } | ||
642 | |||
643 | static gate_bool_t gate_win32_thread_yield(void) | ||
644 | { | ||
645 | Sleep(0); | ||
646 | return true; | ||
647 | } | ||
648 | static gate_bool_t gate_win32_thread_noyield(void) | ||
649 | { | ||
650 | return false; | ||
651 | } | ||
652 | |||
653 | static gate_bool_t(*gate_win32_thread_yield_function)(void) = NULL; | ||
654 | |||
655 | #if defined(GATE_SYS_WINSTORE) | ||
656 | #define GetSystemInfo(info) GetNativeSystemInfo(info) | ||
657 | #endif | ||
658 | |||
659 | gate_bool_t gate_thread_yield_if_preemptive(void) | ||
660 | { | ||
661 | SYSTEM_INFO info = GATE_INIT_EMPTY; | ||
662 | if (gate_coroutine_enabled()) | ||
663 | { | ||
664 | gate_coroutine_yield(); | ||
665 | return true; | ||
666 | } | ||
667 | else | ||
668 | { | ||
669 | if (gate_win32_thread_yield_function == NULL) | ||
670 | { | ||
671 | GetSystemInfo(&info); | ||
672 | gate_win32_thread_yield_function = (info.dwNumberOfProcessors > 1) ? &gate_win32_thread_noyield : &gate_win32_thread_yield; | ||
673 | } | ||
674 | return gate_win32_thread_yield_function(); | ||
675 | } | ||
676 | } | ||
677 | |||
678 | #ifndef TLS_OUT_OF_INDEXES | ||
679 | #define TLS_OUT_OF_INDEXES 0xFFFFFFFF | ||
680 | #endif | ||
681 | |||
682 | gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id) | ||
683 | { | ||
684 | DWORD* ptr_handle = GATE_HANDLESTORE_CREATE(ptr_store_id, DWORD); | ||
685 | |||
686 | if (NULL == ptr_handle) | ||
687 | { | ||
688 | return GATE_RESULT_OUTOFMEMORY; | ||
689 | } | ||
690 | |||
691 | *ptr_handle = TlsAlloc(); | ||
692 | |||
693 | if (TLS_OUT_OF_INDEXES == *ptr_handle) | ||
694 | { | ||
695 | GATE_HANDLESTORE_DESTROY(ptr_store_id); | ||
696 | return GATE_RESULT_OUTOFRESOURCES; | ||
697 | } | ||
698 | return GATE_RESULT_OK; | ||
699 | } | ||
700 | |||
701 | gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data) | ||
702 | { | ||
703 | DWORD* ptr_handle = GATE_HANDLESTORE_ACCESS(ptr_store_id, DWORD); | ||
704 | if (FALSE == TlsSetValue(*ptr_handle, (LPVOID)data)) | ||
705 | { | ||
706 | return gate_platform_print_last_error(NULL, 0); | ||
707 | } | ||
708 | return GATE_RESULT_OK; | ||
709 | } | ||
710 | |||
711 | gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data) | ||
712 | { | ||
713 | DWORD* ptr_handle = GATE_HANDLESTORE_ACCESS(ptr_store_id, DWORD); | ||
714 | DWORD last_error; | ||
715 | void* data = TlsGetValue(*ptr_handle); | ||
716 | |||
717 | if (data == NULL) | ||
718 | { | ||
719 | last_error = gate_win32_getlasterror(); | ||
720 | if (last_error != ERROR_SUCCESS) | ||
721 | { | ||
722 | return gate_platform_print_error((gate_int32_t)last_error, NULL, 0); | ||
723 | } | ||
724 | } | ||
725 | if (ptr_data) | ||
726 | { | ||
727 | *ptr_data = data; | ||
728 | } | ||
729 | return GATE_RESULT_OK; | ||
730 | } | ||
731 | |||
732 | gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id) | ||
733 | { | ||
734 | DWORD* ptr_handle = GATE_HANDLESTORE_ACCESS(ptr_store_id, DWORD); | ||
735 | if (FALSE == TlsFree(*ptr_handle)) | ||
736 | { | ||
737 | return gate_platform_print_last_error(NULL, 0); | ||
738 | } | ||
739 | GATE_HANDLESTORE_DESTROY(ptr_store_id); | ||
740 | return GATE_RESULT_OK; | ||
741 | } | ||
742 | |||
743 | #endif /* #if defined(GATE_THREADING_WINAPI) */ | ||
744 | |||
745 | |||
746 | |||
747 | #if defined(GATE_THREADING_PTHREAD) | ||
748 | |||
749 | #include "gate/handles.h" | ||
750 | #include <pthread.h> | ||
751 | #include <unistd.h> | ||
752 | |||
753 | 2 | gate_enumint_t gate_thread_model() | |
754 | { | ||
755 | 2 | return GATE_THREAD_MODEL_NATIVE; | |
756 | } | ||
757 | |||
758 | 9 | gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function, | |
759 | gate_thread_native_param_type entry_param, | ||
760 | gate_thread_t* thread_handle, | ||
761 | gate_thread_id_t* thread_id) | ||
762 | { | ||
763 | int result; | ||
764 | pthread_t* handle; | ||
765 |
2/4✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
|
9 | if ((entry_function == NULL) || (thread_handle == NULL)) |
766 | { | ||
767 | ✗ | return GATE_RESULT_INVALIDARG; | |
768 | } | ||
769 | |||
770 | 9 | handle = GATE_HANDLESTORE_CREATE(thread_handle, pthread_t); | |
771 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | if (handle == NULL) |
772 | { | ||
773 | ✗ | return GATE_RESULT_OUTOFMEMORY; | |
774 | } | ||
775 | |||
776 | 9 | result = pthread_create(handle, 0, entry_function, (void*)entry_param); | |
777 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | if (0 == result) |
778 | { | ||
779 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
|
9 | if (thread_id != NULL) |
780 | { | ||
781 | 6 | *thread_id = (gate_thread_id_t)handle; | |
782 | } | ||
783 | 9 | return GATE_RESULT_OK; | |
784 | } | ||
785 | else | ||
786 | { | ||
787 | ✗ | GATE_HANDLESTORE_DESTROY(thread_handle); | |
788 | ✗ | return GATE_RESULT_FAILED; | |
789 | } | ||
790 | } | ||
791 | |||
792 | 2 | gate_result_t gate_thread_detach(gate_thread_t* thread_handle) | |
793 | { | ||
794 | 2 | pthread_t* handle = GATE_HANDLESTORE_ACCESS(thread_handle, pthread_t); | |
795 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (handle) |
796 | { | ||
797 | 2 | pthread_detach(*handle); | |
798 | 2 | GATE_HANDLESTORE_DESTROY(thread_handle); | |
799 | } | ||
800 | 2 | return GATE_RESULT_OK; | |
801 | } | ||
802 | 7 | gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* ptr_result) | |
803 | { | ||
804 | 7 | gate_result_t ret = GATE_RESULT_FAILED; | |
805 | void* threadresult; | ||
806 | 7 | pthread_t* handle = GATE_HANDLESTORE_ACCESS(thread_handle, pthread_t); | |
807 | |||
808 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | if (handle) |
809 | { | ||
810 |
1/2✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
7 | if (0 == pthread_join(*handle, &threadresult)) |
811 | { | ||
812 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
|
7 | if (ptr_result != NULL) |
813 | { | ||
814 | 6 | *ptr_result = (gate_result_t)(gate_intptr_t)threadresult; | |
815 | } | ||
816 | 7 | ret = GATE_RESULT_OK; | |
817 | } | ||
818 | else | ||
819 | { | ||
820 | ✗ | ret = GATE_RESULT_FAILED; | |
821 | } | ||
822 | 7 | GATE_HANDLESTORE_DESTROY(thread_handle); | |
823 | } | ||
824 | 7 | return ret; | |
825 | } | ||
826 | ✗ | static pthread_t get_real_pthread(gate_thread_t* thread_handle) | |
827 | { | ||
828 | ✗ | pthread_t* handle = GATE_HANDLESTORE_ACCESS(thread_handle, pthread_t); | |
829 | ✗ | if (*handle == ((pthread_t)-1)) | |
830 | { | ||
831 | ✗ | return pthread_self(); | |
832 | } | ||
833 | ✗ | return *handle; | |
834 | } | ||
835 | |||
836 | 7 | gate_result_t gate_thread_current(gate_thread_t* thread_handle, gate_thread_id_t* threadid) | |
837 | { | ||
838 | 7 | gate_result_t ret = GATE_RESULT_OK; | |
839 | 7 | pthread_t th = pthread_self(); | |
840 | pthread_t* handle; | ||
841 | |||
842 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
|
7 | if (thread_handle) |
843 | { | ||
844 | 1 | handle = GATE_HANDLESTORE_CREATE(thread_handle, pthread_t); | |
845 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (handle != NULL) |
846 | { | ||
847 | 1 | *handle = (pthread_t)-1; | |
848 | } | ||
849 | else | ||
850 | { | ||
851 | ✗ | ret = GATE_RESULT_OUTOFMEMORY; | |
852 | } | ||
853 | } | ||
854 | |||
855 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | if (threadid != NULL) |
856 | { | ||
857 | 7 | *threadid = (gate_thread_id_t)th; | |
858 | } | ||
859 | 7 | return ret; | |
860 | } | ||
861 | |||
862 | 2 | gate_result_t gate_thread_is_current(gate_thread_t* thread_handle, gate_bool_t* is_current) | |
863 | { | ||
864 | 2 | gate_result_t ret = GATE_RESULT_OK; | |
865 | 2 | pthread_t* handle = GATE_HANDLESTORE_ACCESS(thread_handle, pthread_t); | |
866 | 2 | pthread_t th = pthread_self(); | |
867 | 2 | *is_current = (pthread_equal(*handle, th) != 0); | |
868 | 2 | return ret; | |
869 | } | ||
870 | |||
871 | |||
872 | ✗ | gate_bool_t gate_thread_equals(gate_thread_t* th1, gate_thread_t* th2) | |
873 | { | ||
874 | ✗ | pthread_t pth1 = get_real_pthread(th1); | |
875 | ✗ | pthread_t pth2 = get_real_pthread(th2); | |
876 | ✗ | return (pthread_equal(pth1, pth2) == 0) ? false : true; | |
877 | } | ||
878 | 4 | void gate_thread_sleep(gate_uint32_t milliseconds) | |
879 | { | ||
880 | gate_uint32_t seconds; | ||
881 | gate_uint32_t millis; | ||
882 | gate_timecounter_t now, start; | ||
883 | gate_int64_t diff; | ||
884 | gate_int64_t timeout; | ||
885 | |||
886 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 | if (gate_coroutine_enabled()) |
887 | { | ||
888 | ✗ | gate_timecounter_now(&start); | |
889 | ✗ | timeout = (gate_int64_t)milliseconds * 1000; | |
890 | do | ||
891 | { | ||
892 | ✗ | gate_coroutine_yield(); | |
893 | ✗ | gate_timecounter_now(&now); | |
894 | ✗ | diff = gate_timecounter_diff(now, start); | |
895 | ✗ | } while (diff < timeout); | |
896 | } | ||
897 | else | ||
898 | { | ||
899 | 4 | seconds = milliseconds / 1000; | |
900 | 4 | millis = (milliseconds % 1000) * 1000; | |
901 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (seconds > 0) |
902 | { | ||
903 | ✗ | sleep(seconds); | |
904 | } | ||
905 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (millis > 0) |
906 | { | ||
907 | 4 | usleep(millis); | |
908 | } | ||
909 | } | ||
910 | 4 | } | |
911 | 20 | void gate_thread_yield(void) | |
912 | { | ||
913 | 20 | sched_yield(); | |
914 | 20 | } | |
915 | 1 | gate_bool_t gate_thread_yield_if_preemptive(void) | |
916 | { | ||
917 | 1 | sched_yield(); | |
918 | 1 | return true; | |
919 | } | ||
920 | |||
921 | 4 | gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id) | |
922 | { | ||
923 | 4 | pthread_key_t* ptr_handle = GATE_HANDLESTORE_CREATE(ptr_store_id, pthread_key_t); | |
924 | int error; | ||
925 | |||
926 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (NULL == ptr_handle) |
927 | { | ||
928 | ✗ | return GATE_RESULT_OUTOFMEMORY; | |
929 | } | ||
930 | |||
931 | 4 | error = pthread_key_create(ptr_handle, NULL); | |
932 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (error) |
933 | { | ||
934 | ✗ | GATE_HANDLESTORE_DESTROY(ptr_store_id); | |
935 | ✗ | return GATE_RESULT_OUTOFRESOURCES; | |
936 | } | ||
937 | 4 | return GATE_RESULT_OK; | |
938 | } | ||
939 | |||
940 | 23 | gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data) | |
941 | { | ||
942 | 23 | pthread_key_t* ptr_handle = GATE_HANDLESTORE_ACCESS(ptr_store_id, pthread_key_t); | |
943 | 23 | int error = pthread_setspecific(*ptr_handle, data); | |
944 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (error) |
945 | { | ||
946 | ✗ | return GATE_RESULT_FAILED; | |
947 | } | ||
948 | 23 | return GATE_RESULT_OK; | |
949 | } | ||
950 | |||
951 | 66 | gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data) | |
952 | { | ||
953 | 66 | pthread_key_t* ptr_handle = GATE_HANDLESTORE_ACCESS(ptr_store_id, pthread_key_t); | |
954 | 66 | void* data = pthread_getspecific(*ptr_handle); | |
955 |
1/2✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
|
66 | if (ptr_data) |
956 | { | ||
957 | 66 | *ptr_data = data; | |
958 | } | ||
959 | 66 | return GATE_RESULT_OK; | |
960 | } | ||
961 | |||
962 | 1 | gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id) | |
963 | { | ||
964 | 1 | pthread_key_t* ptr_handle = GATE_HANDLESTORE_ACCESS(ptr_store_id, pthread_key_t); | |
965 | 1 | int error = pthread_key_delete(*ptr_handle); | |
966 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (error) |
967 | { | ||
968 | ✗ | return GATE_RESULT_FAILED; | |
969 | } | ||
970 | 1 | GATE_HANDLESTORE_DESTROY(ptr_store_id); | |
971 | 1 | return GATE_RESULT_OK; | |
972 | } | ||
973 | |||
974 | #endif /* GATE_THREADING_PTHREAD */ | ||
975 | |||
976 | |||
977 | |||
978 | #if defined(GATE_THREADING_BEOS) | ||
979 | |||
980 | #include <kernel/OS.h> | ||
981 | #include <support/TLS.h> | ||
982 | |||
983 | gate_enumint_t gate_thread_model() | ||
984 | { | ||
985 | return GATE_THREAD_MODEL_NATIVE; | ||
986 | } | ||
987 | |||
988 | gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function, | ||
989 | gate_thread_native_param_type entry_param, | ||
990 | gate_thread_t* ptr_thread_handle, | ||
991 | gate_thread_id_t* ptr_thread_id) | ||
992 | { | ||
993 | status_t tstat; | ||
994 | thread_id tid; | ||
995 | |||
996 | tid = spawn_thread((thread_func)entry_function, "thread", B_NORMAL_PRIORITY, entry_param); | ||
997 | |||
998 | if (tid == B_NO_MEMORY) | ||
999 | { | ||
1000 | return GATE_RESULT_OUTOFMEMORY; | ||
1001 | } | ||
1002 | else if (tid == B_NO_MORE_THREADS) | ||
1003 | { | ||
1004 | return GATE_RESULT_OUTOFRESOURCES; | ||
1005 | } | ||
1006 | |||
1007 | tstat = resume_thread(tid); | ||
1008 | if (B_OK != tstat) | ||
1009 | { | ||
1010 | kill_thread(tid); | ||
1011 | return GATE_RESULT_FAILED; | ||
1012 | } | ||
1013 | |||
1014 | |||
1015 | if (ptr_thread_handle) | ||
1016 | { | ||
1017 | thread_id* ptr_tid = GATE_HANDLESTORE_CREATE(ptr_thread_handle, thread_id); | ||
1018 | if (NULL == ptr_tid) | ||
1019 | { | ||
1020 | kill_thread(tid); | ||
1021 | return GATE_RESULT_OUTOFMEMORY; | ||
1022 | } | ||
1023 | *ptr_tid = tid; | ||
1024 | } | ||
1025 | if (ptr_thread_id) | ||
1026 | { | ||
1027 | *ptr_thread_id = (gate_thread_id_t)tid; | ||
1028 | } | ||
1029 | |||
1030 | return GATE_RESULT_OK; | ||
1031 | } | ||
1032 | |||
1033 | |||
1034 | gate_result_t gate_thread_detach(gate_thread_t* thread_handle) | ||
1035 | { | ||
1036 | thread_id* handle = GATE_HANDLESTORE_ACCESS(thread_handle, thread_id); | ||
1037 | if (handle) | ||
1038 | { | ||
1039 | GATE_HANDLESTORE_DESTROY(thread_handle); | ||
1040 | } | ||
1041 | return GATE_RESULT_OK; | ||
1042 | } | ||
1043 | |||
1044 | gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* result) | ||
1045 | { | ||
1046 | gate_result_t ret = GATE_RESULT_FAILED; | ||
1047 | status_t status; | ||
1048 | status_t thread_status; | ||
1049 | thread_id* handle = GATE_HANDLESTORE_ACCESS(thread_handle, thread_id); | ||
1050 | if (handle) | ||
1051 | { | ||
1052 | status = wait_for_thread(*handle, &thread_status); | ||
1053 | if (B_OK == status) | ||
1054 | { | ||
1055 | if (result) | ||
1056 | { | ||
1057 | *result = (gate_result_t)thread_status; | ||
1058 | } | ||
1059 | GATE_HANDLESTORE_DESTROY(thread_handle); | ||
1060 | ret = GATE_RESULT_OK; | ||
1061 | } | ||
1062 | else if (B_OK == B_INTERRUPTED) | ||
1063 | { | ||
1064 | if (result) | ||
1065 | { | ||
1066 | *result = GATE_RESULT_CANCELED; | ||
1067 | } | ||
1068 | GATE_HANDLESTORE_DESTROY(thread_handle); | ||
1069 | ret = GATE_RESULT_OK; | ||
1070 | } | ||
1071 | else | ||
1072 | { | ||
1073 | ret = GATE_RESULT_FAILED; | ||
1074 | } | ||
1075 | } | ||
1076 | return ret; | ||
1077 | } | ||
1078 | |||
1079 | gate_result_t gate_thread_current(gate_thread_t* ptr_thread_handle, gate_thread_id_t* ptr_thread_id) | ||
1080 | { | ||
1081 | thread_id tid = find_thread(NULL); | ||
1082 | |||
1083 | if (ptr_thread_handle) | ||
1084 | { | ||
1085 | thread_id* ptr_tid = GATE_HANDLESTORE_CREATE(ptr_thread_handle, thread_id); | ||
1086 | if (NULL == ptr_tid) | ||
1087 | { | ||
1088 | kill_thread(tid); | ||
1089 | return GATE_RESULT_OUTOFMEMORY; | ||
1090 | } | ||
1091 | *ptr_tid = tid; | ||
1092 | } | ||
1093 | if (ptr_thread_id) | ||
1094 | { | ||
1095 | *ptr_thread_id = (gate_thread_id_t)tid; | ||
1096 | } | ||
1097 | return GATE_RESULT_OK; | ||
1098 | } | ||
1099 | |||
1100 | gate_result_t gate_thread_is_current(gate_thread_t* ptr_thread_handle, gate_bool_t* is_current) | ||
1101 | { | ||
1102 | thread_id cur_tid = find_thread(NULL); | ||
1103 | thread_id* ptr_tid = GATE_HANDLESTORE_ACCESS(ptr_thread_handle, thread_id); | ||
1104 | if (!ptr_tid) | ||
1105 | { | ||
1106 | return GATE_RESULT_INVALIDARG; | ||
1107 | } | ||
1108 | if (is_current) | ||
1109 | { | ||
1110 | *is_current = *ptr_tid == cur_tid; | ||
1111 | } | ||
1112 | return GATE_RESULT_OK; | ||
1113 | } | ||
1114 | |||
1115 | gate_bool_t gate_thread_equals(gate_thread_t* thread_handle_1, gate_thread_t* thread_handle_2) | ||
1116 | { | ||
1117 | thread_id* ptr_tid1 = GATE_HANDLESTORE_ACCESS(thread_handle_1, thread_id); | ||
1118 | thread_id* ptr_tid2 = GATE_HANDLESTORE_ACCESS(thread_handle_2, thread_id); | ||
1119 | if (ptr_tid1 == ptr_tid2) | ||
1120 | { | ||
1121 | return true; | ||
1122 | } | ||
1123 | else if ((ptr_tid1 == NULL) || (ptr_tid2 == NULL)) | ||
1124 | { | ||
1125 | return false; | ||
1126 | } | ||
1127 | else | ||
1128 | { | ||
1129 | return *ptr_tid1 == *ptr_tid2; | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1133 | void gate_thread_sleep(gate_uint32_t milliseconds) | ||
1134 | { | ||
1135 | bigtime_t usec = (bigtime_t)milliseconds * 1000; | ||
1136 | snooze(usec); | ||
1137 | } | ||
1138 | |||
1139 | void gate_thread_yield(void) | ||
1140 | { | ||
1141 | } | ||
1142 | |||
1143 | gate_bool_t gate_thread_yield_if_preemptive(void) | ||
1144 | { | ||
1145 | return false; | ||
1146 | } | ||
1147 | |||
1148 | gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id) | ||
1149 | { | ||
1150 | int32* ptr_ts = GATE_HANDLESTORE_CREATE(ptr_store_id, int32); | ||
1151 | if (NULL == ptr_ts) | ||
1152 | { | ||
1153 | return GATE_RESULT_OUTOFMEMORY; | ||
1154 | } | ||
1155 | *ptr_ts = tls_allocate(); | ||
1156 | return GATE_RESULT_OK; | ||
1157 | } | ||
1158 | gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data) | ||
1159 | { | ||
1160 | int32* ptr_ts = GATE_HANDLESTORE_ACCESS(ptr_store_id, int32); | ||
1161 | if (!ptr_ts) | ||
1162 | { | ||
1163 | return GATE_RESULT_NOTAVAILABLE; | ||
1164 | } | ||
1165 | tls_set(*ptr_ts, data); | ||
1166 | return GATE_RESULT_OK; | ||
1167 | } | ||
1168 | |||
1169 | gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data) | ||
1170 | { | ||
1171 | int32* ptr_ts = GATE_HANDLESTORE_ACCESS(ptr_store_id, int32); | ||
1172 | void* ptr_ts_data = NULL; | ||
1173 | if (!ptr_ts) | ||
1174 | { | ||
1175 | return GATE_RESULT_NOTAVAILABLE; | ||
1176 | } | ||
1177 | ptr_ts_data = tls_get(*ptr_ts); | ||
1178 | if (ptr_data) | ||
1179 | { | ||
1180 | *ptr_data = ptr_ts_data; | ||
1181 | } | ||
1182 | return GATE_RESULT_OK; | ||
1183 | } | ||
1184 | |||
1185 | gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id) | ||
1186 | { | ||
1187 | int32* ptr_ts = GATE_HANDLESTORE_ACCESS(ptr_store_id, int32); | ||
1188 | if (!ptr_ts) | ||
1189 | { | ||
1190 | return GATE_RESULT_NOTAVAILABLE; | ||
1191 | } | ||
1192 | GATE_HANDLESTORE_DESTROY(ptr_store_id); | ||
1193 | return GATE_RESULT_OK; | ||
1194 | } | ||
1195 | |||
1196 | #endif /* GATE_THREADING_BEOS */ | ||
1197 | |||
1198 | |||
1199 | |||
1200 | #ifdef GATE_THREADING_COROUTINES | ||
1201 | |||
1202 | #include "gate/platform/efi/efi_gate.h" | ||
1203 | #include "gate/coroutines.h" | ||
1204 | |||
1205 | gate_enumint_t gate_thread_model() | ||
1206 | { | ||
1207 | return GATE_THREAD_MODEL_MANUAL; | ||
1208 | } | ||
1209 | |||
1210 | |||
1211 | gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function, | ||
1212 | gate_thread_native_param_type entry_param, | ||
1213 | gate_thread_t* thread_handle, gate_thread_id_t* thread_id) | ||
1214 | { | ||
1215 | gate_result_t ret; | ||
1216 | gate_coroutine_id_t* ptr_co_id; | ||
1217 | |||
1218 | if ((NULL == entry_function) || (NULL == thread_handle)) | ||
1219 | { | ||
1220 | return GATE_RESULT_INVALIDARG; | ||
1221 | } | ||
1222 | |||
1223 | ptr_co_id = GATE_HANDLESTORE_CREATE(thread_handle, gate_coroutine_id_t); | ||
1224 | if (NULL == ptr_co_id) | ||
1225 | { | ||
1226 | return GATE_RESULT_OUTOFMEMORY; | ||
1227 | } | ||
1228 | |||
1229 | ret = gate_coroutine_create(entry_function, entry_param, ptr_co_id); | ||
1230 | if (GATE_FAILED(ret)) | ||
1231 | { | ||
1232 | GATE_HANDLESTORE_DESTROY(thread_handle); | ||
1233 | return ret; | ||
1234 | } | ||
1235 | |||
1236 | if (thread_id) | ||
1237 | { | ||
1238 | *thread_id = (gate_thread_id_t)*ptr_co_id; | ||
1239 | } | ||
1240 | return ret; | ||
1241 | } | ||
1242 | |||
1243 | gate_result_t gate_thread_detach(gate_thread_t* thread_handle) | ||
1244 | { | ||
1245 | GATE_HANDLESTORE_DESTROY(thread_handle); | ||
1246 | return GATE_RESULT_OK; | ||
1247 | } | ||
1248 | |||
1249 | gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* result) | ||
1250 | { | ||
1251 | gate_result_t ret = GATE_RESULT_FAILED; | ||
1252 | gate_coroutine_id_t* ptr_co_id = GATE_HANDLESTORE_ACCESS(thread_handle, gate_coroutine_id_t); | ||
1253 | |||
1254 | if (ptr_co_id) | ||
1255 | { | ||
1256 | ret = gate_coroutine_await(*ptr_co_id, result); | ||
1257 | } | ||
1258 | else | ||
1259 | { | ||
1260 | ret = GATE_RESULT_NOTAVAILABLE; | ||
1261 | } | ||
1262 | return ret; | ||
1263 | } | ||
1264 | |||
1265 | gate_result_t gate_thread_current(gate_thread_t* thread_handle, gate_thread_id_t* thread_id) | ||
1266 | { | ||
1267 | gate_result_t ret = GATE_RESULT_FAILED; | ||
1268 | gate_coroutine_id_t co_id; | ||
1269 | gate_coroutine_id_t* ptr_co_id; | ||
1270 | |||
1271 | ret = gate_coroutine_get_current(&co_id); | ||
1272 | if (GATE_SUCCEEDED(ret)) | ||
1273 | { | ||
1274 | if (thread_handle) | ||
1275 | { | ||
1276 | ptr_co_id = GATE_HANDLESTORE_CREATE(thread_handle, gate_coroutine_id_t); | ||
1277 | *ptr_co_id = co_id; | ||
1278 | } | ||
1279 | if (thread_id) | ||
1280 | { | ||
1281 | *thread_id = (gate_thread_id_t)co_id; | ||
1282 | } | ||
1283 | } | ||
1284 | return ret; | ||
1285 | } | ||
1286 | |||
1287 | gate_result_t gate_thread_is_current(gate_thread_t* thread_handle, gate_bool_t* is_current) | ||
1288 | { | ||
1289 | gate_result_t ret = GATE_RESULT_FAILED; | ||
1290 | gate_coroutine_id_t co_id; | ||
1291 | gate_coroutine_id_t* ptr_co_id; | ||
1292 | |||
1293 | ret = gate_coroutine_get_current(&co_id); | ||
1294 | if (GATE_SUCCEEDED(ret)) | ||
1295 | { | ||
1296 | ptr_co_id = GATE_HANDLESTORE_ACCESS(thread_handle, gate_coroutine_id_t); | ||
1297 | if (ptr_co_id) | ||
1298 | { | ||
1299 | if (is_current) | ||
1300 | { | ||
1301 | *is_current = *ptr_co_id == co_id; | ||
1302 | } | ||
1303 | } | ||
1304 | } | ||
1305 | return ret; | ||
1306 | } | ||
1307 | |||
1308 | gate_bool_t gate_thread_equals(gate_thread_t* thread_handle_1, gate_thread_t* thread_handle_2) | ||
1309 | { | ||
1310 | gate_coroutine_id_t* ptr_co_id1 = GATE_HANDLESTORE_ACCESS(thread_handle_1, gate_coroutine_id_t); | ||
1311 | gate_coroutine_id_t* ptr_co_id2 = GATE_HANDLESTORE_ACCESS(thread_handle_2, gate_coroutine_id_t); | ||
1312 | |||
1313 | if (ptr_co_id1 && ptr_co_id2) | ||
1314 | { | ||
1315 | return *ptr_co_id1 == *ptr_co_id2; | ||
1316 | } | ||
1317 | return false; | ||
1318 | } | ||
1319 | |||
1320 | void gate_thread_sleep(gate_uint32_t milliseconds) | ||
1321 | { | ||
1322 | gate_coroutine_sleep(milliseconds); | ||
1323 | //gate_platform_efi_wait(milliseconds); | ||
1324 | } | ||
1325 | |||
1326 | void gate_thread_yield(void) | ||
1327 | { | ||
1328 | gate_coroutine_yield(); | ||
1329 | } | ||
1330 | |||
1331 | gate_bool_t gate_thread_yield_if_preemptive(void) | ||
1332 | { | ||
1333 | gate_coroutine_yield(); | ||
1334 | return true; | ||
1335 | } | ||
1336 | |||
1337 | gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id) | ||
1338 | { | ||
1339 | GATE_UNUSED_ARG(ptr_store_id); | ||
1340 | return GATE_RESULT_NOTSUPPORTED; | ||
1341 | } | ||
1342 | |||
1343 | gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data) | ||
1344 | { | ||
1345 | GATE_UNUSED_ARG(ptr_store_id); | ||
1346 | GATE_UNUSED_ARG(data); | ||
1347 | return GATE_RESULT_NOTSUPPORTED; | ||
1348 | } | ||
1349 | |||
1350 | gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data) | ||
1351 | { | ||
1352 | GATE_UNUSED_ARG(ptr_store_id); | ||
1353 | GATE_UNUSED_ARG(ptr_data); | ||
1354 | return GATE_RESULT_NOTSUPPORTED; | ||
1355 | } | ||
1356 | |||
1357 | gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id) | ||
1358 | { | ||
1359 | GATE_UNUSED_ARG(ptr_store_id); | ||
1360 | return GATE_RESULT_NOTSUPPORTED; | ||
1361 | } | ||
1362 | |||
1363 | #endif /* GATE_THREADING_COROUTINES */ | ||
1364 | |||
1365 | |||
1366 | |||
1367 | #if defined(GATE_THREADING_WASM) | ||
1368 | |||
1369 | #include "gate/platform/wasm/wasm_gate.h" | ||
1370 | #include <stdlib.h> | ||
1371 | |||
1372 | gate_enumint_t gate_thread_model() | ||
1373 | { | ||
1374 | return GATE_THREAD_MODEL_NATIVE; | ||
1375 | } | ||
1376 | |||
1377 | |||
1378 | typedef struct | ||
1379 | { | ||
1380 | gate_thread_native_entry entry_function; | ||
1381 | gate_thread_native_param_type entry_param; | ||
1382 | } worker_param_t; | ||
1383 | |||
1384 | static gate_result_t wasm_thread_dispatcher(gate_dataptr_t arg) | ||
1385 | { | ||
1386 | worker_param_t* ptr_param = (worker_param_t*)arg; | ||
1387 | gate_thread_native_entry func = ptr_param->entry_function; | ||
1388 | gate_thread_native_param_type func_param = ptr_param->entry_param; | ||
1389 | gate_thread_native_return_type func_ret_value = (gate_thread_native_return_type)0; | ||
1390 | gate_wasm_worker_id_t worker_id = gate_wasm_worker_id(); | ||
1391 | |||
1392 | if (func) | ||
1393 | { | ||
1394 | func_ret_value = func(func_param); | ||
1395 | } | ||
1396 | |||
1397 | gate_wasm_worker_completed(worker_id, (gate_result_t)func_ret_value); | ||
1398 | return GATE_RESULT_OK; | ||
1399 | } | ||
1400 | |||
1401 | gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function, | ||
1402 | gate_thread_native_param_type entry_param, | ||
1403 | gate_thread_t* thread_handle, | ||
1404 | gate_thread_id_t* thread_id) | ||
1405 | { | ||
1406 | gate_result_t ret = GATE_RESULT_FAILED; | ||
1407 | gate_wasm_worker_id_t worker_id = NULL; | ||
1408 | worker_param_t* ptr_worker_param = NULL; | ||
1409 | |||
1410 | do | ||
1411 | { | ||
1412 | ptr_worker_param = (worker_param_t*)malloc(sizeof(worker_param_t)); | ||
1413 | if (ptr_worker_param == NULL) | ||
1414 | { | ||
1415 | ret = GATE_RESULT_OUTOFMEMORY; | ||
1416 | break; | ||
1417 | } | ||
1418 | |||
1419 | ptr_worker_param->entry_function = entry_function; | ||
1420 | ptr_worker_param->entry_param = entry_param; | ||
1421 | |||
1422 | ret = gate_wasm_worker_create(&worker_id); | ||
1423 | GATE_BREAK_IF_FAILED(ret); | ||
1424 | |||
1425 | ret = gate_wasm_worker_post_task(worker_id, &wasm_thread_dispatcher, ptr_worker_param); | ||
1426 | GATE_BREAK_IF_FAILED(ret); | ||
1427 | |||
1428 | /* success case */ | ||
1429 | ret = GATE_RESULT_OK; | ||
1430 | |||
1431 | if (thread_handle) | ||
1432 | { | ||
1433 | gate_wasm_worker_id_t* ptr_handle = GATE_HANDLESTORE_CREATE(thread_handle, gate_wasm_worker_id_t); | ||
1434 | *ptr_handle = worker_id; | ||
1435 | } | ||
1436 | |||
1437 | if (thread_id) | ||
1438 | { | ||
1439 | *thread_id = (gate_thread_id_t)worker_id; | ||
1440 | } | ||
1441 | |||
1442 | worker_id = NULL; | ||
1443 | ptr_worker_param = NULL; | ||
1444 | |||
1445 | } while (0); | ||
1446 | |||
1447 | if (worker_id) | ||
1448 | { | ||
1449 | gate_wasm_worker_destroy(worker_id); | ||
1450 | } | ||
1451 | |||
1452 | if (ptr_worker_param) | ||
1453 | { | ||
1454 | free(ptr_worker_param); | ||
1455 | } | ||
1456 | |||
1457 | return ret; | ||
1458 | } | ||
1459 | |||
1460 | |||
1461 | gate_result_t gate_thread_detach(gate_thread_t* thread_handle) | ||
1462 | { | ||
1463 | GATE_HANDLESTORE_DESTROY(thread_handle); | ||
1464 | return GATE_RESULT_OK; | ||
1465 | } | ||
1466 | |||
1467 | gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* result) | ||
1468 | { | ||
1469 | gate_result_t ret = GATE_RESULT_INVALIDARG; | ||
1470 | gate_wasm_worker_id_t* ptr_handle = GATE_HANDLESTORE_ACCESS(thread_handle, gate_wasm_worker_id_t); | ||
1471 | |||
1472 | if (ptr_handle && *ptr_handle) | ||
1473 | { | ||
1474 | ret = gate_wasm_worker_join(*ptr_handle, result); | ||
1475 | } | ||
1476 | return ret; | ||
1477 | } | ||
1478 | |||
1479 | gate_result_t gate_thread_current(gate_thread_t* thread_handle, gate_thread_id_t* thread_id) | ||
1480 | { | ||
1481 | gate_wasm_worker_id_t worker_id = gate_wasm_worker_id(); | ||
1482 | if (thread_handle) | ||
1483 | { | ||
1484 | gate_wasm_worker_id_t* ptr_handle = GATE_HANDLESTORE_CREATE(thread_handle, gate_wasm_worker_id_t); | ||
1485 | *ptr_handle = worker_id; | ||
1486 | } | ||
1487 | |||
1488 | if (thread_id) | ||
1489 | { | ||
1490 | *thread_id = (gate_thread_id_t)worker_id; | ||
1491 | } | ||
1492 | return GATE_RESULT_OK; | ||
1493 | } | ||
1494 | |||
1495 | gate_result_t gate_thread_is_current(gate_thread_t* thread_handle, gate_bool_t* is_current) | ||
1496 | { | ||
1497 | gate_wasm_worker_id_t worker_id = gate_wasm_worker_id(); | ||
1498 | gate_wasm_worker_id_t* ptr_handle = GATE_HANDLESTORE_ACCESS(thread_handle, gate_wasm_worker_id_t); | ||
1499 | if (ptr_handle) | ||
1500 | { | ||
1501 | if (is_current) | ||
1502 | { | ||
1503 | *is_current = *ptr_handle == worker_id; | ||
1504 | } | ||
1505 | return GATE_RESULT_OK; | ||
1506 | } | ||
1507 | return GATE_RESULT_INVALIDARG; | ||
1508 | } | ||
1509 | |||
1510 | gate_bool_t gate_thread_equals(gate_thread_t* thread_handle_1, gate_thread_t* thread_handle_2) | ||
1511 | { | ||
1512 | gate_wasm_worker_id_t* ptr_handle_1 = GATE_HANDLESTORE_ACCESS(thread_handle_1, gate_wasm_worker_id_t); | ||
1513 | gate_wasm_worker_id_t* ptr_handle_2 = GATE_HANDLESTORE_ACCESS(thread_handle_2, gate_wasm_worker_id_t); | ||
1514 | if (!ptr_handle_1 || !ptr_handle_2) | ||
1515 | { | ||
1516 | return false; | ||
1517 | } | ||
1518 | return *ptr_handle_1 == ptr_handle_2; | ||
1519 | } | ||
1520 | |||
1521 | void gate_thread_sleep(gate_uint32_t milliseconds) | ||
1522 | { | ||
1523 | gate_wasm_thread_sleep(milliseconds); | ||
1524 | } | ||
1525 | |||
1526 | void gate_thread_yield(void) | ||
1527 | { | ||
1528 | } | ||
1529 | |||
1530 | gate_bool_t gate_thread_yield_if_preemptive(void) | ||
1531 | { | ||
1532 | return false; | ||
1533 | } | ||
1534 | |||
1535 | gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id) | ||
1536 | { | ||
1537 | void** ptr_tss = GATE_HANDLESTORE_CREATE(ptr_store_id, void*); | ||
1538 | if (NULL == ptr_tss) | ||
1539 | { | ||
1540 | return GATE_RESULT_OUTOFMEMORY; | ||
1541 | } | ||
1542 | *ptr_tss = NULL; | ||
1543 | return GATE_RESULT_OK; | ||
1544 | } | ||
1545 | gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data) | ||
1546 | { | ||
1547 | void** ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, void*); | ||
1548 | *ptr_tss = data; | ||
1549 | return GATE_RESULT_OK; | ||
1550 | } | ||
1551 | |||
1552 | gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data) | ||
1553 | { | ||
1554 | void** ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, void*); | ||
1555 | *ptr_data = *ptr_tss; | ||
1556 | return GATE_RESULT_OK; | ||
1557 | } | ||
1558 | |||
1559 | gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id) | ||
1560 | { | ||
1561 | GATE_HANDLESTORE_DESTROY(ptr_store_id); | ||
1562 | return GATE_RESULT_OK; | ||
1563 | } | ||
1564 | |||
1565 | |||
1566 | |||
1567 | #endif /* GATE_THREADING_WASM */ | ||
1568 | |||
1569 | |||
1570 | |||
1571 | #if defined(GATE_THREADING_NO_IMPL) | ||
1572 | |||
1573 | gate_enumint_t gate_thread_model() | ||
1574 | { | ||
1575 | return GATE_THREAD_MODEL_NONE; | ||
1576 | } | ||
1577 | |||
1578 | gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function, | ||
1579 | gate_thread_native_param_type entry_param, | ||
1580 | gate_thread_t* thread_handle, | ||
1581 | gate_thread_id_t* thread_id) | ||
1582 | { | ||
1583 | GATE_UNUSED_ARG(entry_function); | ||
1584 | GATE_UNUSED_ARG(entry_param); | ||
1585 | GATE_UNUSED_ARG(thread_handle); | ||
1586 | GATE_UNUSED_ARG(thread_id); | ||
1587 | return GATE_RESULT_NOTSUPPORTED; | ||
1588 | } | ||
1589 | |||
1590 | |||
1591 | gate_result_t gate_thread_detach(gate_thread_t* thread_handle) | ||
1592 | { | ||
1593 | GATE_UNUSED_ARG(thread_handle); | ||
1594 | return GATE_RESULT_NOTSUPPORTED; | ||
1595 | } | ||
1596 | |||
1597 | gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* result) | ||
1598 | { | ||
1599 | GATE_UNUSED_ARG(thread_handle); | ||
1600 | GATE_UNUSED_ARG(result); | ||
1601 | return GATE_RESULT_NOTSUPPORTED; | ||
1602 | } | ||
1603 | |||
1604 | gate_result_t gate_thread_current(gate_thread_t* thread_handle, gate_thread_id_t* thread_id) | ||
1605 | { | ||
1606 | GATE_UNUSED_ARG(thread_handle); | ||
1607 | GATE_UNUSED_ARG(thread_id); | ||
1608 | return GATE_RESULT_NOTSUPPORTED; | ||
1609 | } | ||
1610 | |||
1611 | gate_result_t gate_thread_is_current(gate_thread_t* thread_handle, gate_bool_t* is_current) | ||
1612 | { | ||
1613 | GATE_UNUSED_ARG(thread_handle); | ||
1614 | GATE_UNUSED_ARG(is_current); | ||
1615 | return GATE_RESULT_NOTSUPPORTED; | ||
1616 | } | ||
1617 | |||
1618 | gate_bool_t gate_thread_equals(gate_thread_t* thread_handle_1, gate_thread_t* thread_handle_2) | ||
1619 | { | ||
1620 | GATE_UNUSED_ARG(thread_handle_1); | ||
1621 | GATE_UNUSED_ARG(thread_handle_2); | ||
1622 | return false; | ||
1623 | } | ||
1624 | |||
1625 | void gate_thread_sleep(gate_uint32_t milliseconds) | ||
1626 | { | ||
1627 | } | ||
1628 | |||
1629 | void gate_thread_yield(void) | ||
1630 | { | ||
1631 | } | ||
1632 | |||
1633 | gate_bool_t gate_thread_yield_if_preemptive(void) | ||
1634 | { | ||
1635 | return false; | ||
1636 | } | ||
1637 | |||
1638 | gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id) | ||
1639 | { | ||
1640 | void** ptr_tss = GATE_HANDLESTORE_CREATE(ptr_store_id, void*); | ||
1641 | if (NULL == ptr_tss) | ||
1642 | { | ||
1643 | return GATE_RESULT_OUTOFMEMORY; | ||
1644 | } | ||
1645 | *ptr_tss = NULL; | ||
1646 | return GATE_RESULT_OK; | ||
1647 | } | ||
1648 | gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data) | ||
1649 | { | ||
1650 | void** ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, void*); | ||
1651 | *ptr_tss = data; | ||
1652 | return GATE_RESULT_OK; | ||
1653 | } | ||
1654 | |||
1655 | gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data) | ||
1656 | { | ||
1657 | void** ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, void*); | ||
1658 | *ptr_data = *ptr_tss; | ||
1659 | return GATE_RESULT_OK; | ||
1660 | } | ||
1661 | |||
1662 | gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id) | ||
1663 | { | ||
1664 | GATE_HANDLESTORE_DESTROY(ptr_store_id); | ||
1665 | return GATE_RESULT_OK; | ||
1666 | } | ||
1667 | |||
1668 | |||
1669 | #endif /* GATE_THREADING_NO_IMPL */ | ||
1670 |