GCC Code Coverage Report


Directory: src/gate/
File: src/gate/threading.c
Date: 2025-09-14 13:10:38
Exec Total Coverage
Lines: 122 156 78.2%
Functions: 20 23 87.0%
Branches: 31 58 53.4%

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