GCC Code Coverage Report


Directory: src/gate/
File: src/gate/threading.c
Date: 2025-12-12 23:40:09
Exec Total Coverage
Lines: 122 156 78.2%
Functions: 20 23 87.0%
Branches: 33 58 56.9%

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 8 static gate_thread_native_return_type GATE_THREAD_API gate_thread_start_entry_point(gate_thread_native_param_type param)
41 {
42 8 gate_runnable_t* executor = (gate_runnable_t*)(void*)param;
43 8 gate_result_t ret = GATE_RESULT_NULLPOINTER;
44
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (executor)
45 {
46 8 ret = gate_runnable_run(executor);
47 8 gate_object_release(executor);
48 }
49 else
50 {
51 ret = GATE_RESULT_NULLPOINTER;
52 }
53 8 return (gate_thread_native_return_type)(gate_intptr_t)ret;
54 }
55
56 8 gate_result_t gate_thread_start(gate_runnable_t* executor, gate_thread_t* thread_handle, gate_thread_id_t* thread_id)
57 {
58 8 gate_result_t ret = GATE_RESULT_FAILED;
59
60 do
61 {
62
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (executor == NULL)
63 {
64 ret = GATE_RESULT_NULLPOINTER;
65 break;
66 }
67
68 8 gate_object_retain(executor);
69 8 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 8 times.
✗ Branch 1 not taken.
8 if (GATE_SUCCEEDED(ret))
73 {
74 8 executor = NULL;
75 }
76 } while (0);
77
78
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (executor != NULL)
79 {
80 gate_object_release(executor);
81 }
82
83 8 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 8 static void gate_thread_dispatcher_release(void* disp)
98 {
99 8 gate_thread_dispatcher_t* ptr = (gate_thread_dispatcher_t*)disp;
100
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
8 if (gate_atomic_int_dec(&ptr->ref_counter) == 0)
101 {
102 4 gate_mem_dealloc(ptr);
103 }
104 8 }
105 4 static int gate_thread_dispatcher_retain(void* disp)
106 {
107 4 gate_thread_dispatcher_t* ptr = (gate_thread_dispatcher_t*)disp;
108 4 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 4 static gate_result_t gate_thread_dispatcher_run(void* disp)
117 {
118 4 gate_thread_dispatcher_t* ptr = (gate_thread_dispatcher_t*)disp;
119 4 return ptr->callback(ptr->data);
120 }
121
122 static GATE_INTERFACE_VTBL(gate_runnable) gate_thread_dispatcher_vtbl;
123 4 static void gate_init_thread_dispatcher_vtbl()
124 {
125
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 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 3 gate_thread_dispatcher_vtbl = local_vtbl;
135 }
136 4 }
137
138 4 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 4 gate_thread_dispatcher_t* disp = gate_mem_alloc(sizeof(gate_thread_dispatcher_t));
142
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (disp == NULL)
143 {
144 ret = GATE_RESULT_OUTOFMEMORY;
145 }
146 else
147 {
148 4 gate_init_thread_dispatcher_vtbl();
149 4 disp->vtbl = &gate_thread_dispatcher_vtbl;
150 4 gate_atomic_int_init(&disp->ref_counter, 1);
151 4 disp->callback = callback;
152 4 disp->data = data;
153 4 ret = gate_thread_start((gate_runnable_t*)disp, threadhandle, threadid);
154 4 gate_object_release(disp);
155 }
156 4 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 if ((entry_function == NULL) || (thread_handle == NULL))
485 {
486 ret = GATE_RESULT_INVALIDARG;
487 }
488 else
489 {
490 DWORD id;
491 HANDLE* handle = GATE_HANDLESTORE_CREATE(thread_handle, HANDLE);
492 *handle = gate_win32_createthread(entry_function, entry_param, 0, &id);
493 if (*handle == NULL)
494 {
495 GATE_DEBUG_TRACE("gate_win32_createthread() failed");
496 GATE_DEBUG_TRACE_VALUE(gate_win32_getlasterror());
497
498 ret = GATE_RESULT_FAILED;
499 gate_win32_print_lasterror(&ret, NULL, 0);
500 GATE_HANDLESTORE_DESTROY(thread_handle);
501 }
502 else
503 {
504 ret = GATE_RESULT_OK;
505 if (thread_id != NULL)
506 {
507 *thread_id = (gate_thread_id_t)id;
508 }
509 }
510 }
511 return ret;
512
513 }
514
515 gate_result_t gate_thread_detach(gate_thread_t* threadhandle)
516 {
517 HANDLE* thread = GATE_HANDLESTORE_ACCESS(threadhandle, HANDLE);
518
519 GATE_DEBUG_ASSERT(thread != NULL);
520
521 if (CloseHandle(*thread))
522 {
523 GATE_HANDLESTORE_DESTROY(threadhandle);
524 return GATE_RESULT_OK;
525 }
526 else
527 {
528 GATE_DEBUG_TRACE("CloseHandle() failed");
529 GATE_DEBUG_TRACE_VALUE(gate_win32_getlasterror());
530 return GATE_RESULT_FAILED;
531 }
532 }
533 gate_result_t gate_thread_join(gate_thread_t* threadhandle, gate_result_t* ptr_result)
534 {
535 HANDLE* thread = GATE_HANDLESTORE_ACCESS(threadhandle, HANDLE);
536 DWORD dwResult = 0;
537 DWORD dwExitCode = 0;
538 gate_result_t ret;
539
540 GATE_DEBUG_ASSERT(thread != NULL);
541
542 dwResult = WaitForSingleObject(*thread, INFINITE);
543 if (dwResult != WAIT_OBJECT_0)
544 {
545 GATE_DEBUG_TRACE("WaitForSingleObject() failed");
546 GATE_DEBUG_TRACE_VALUE(dwResult);
547
548 ret = GATE_RESULT_CRITICALERROR;
549 }
550 else
551 {
552 if (GetExitCodeThread(*thread, &dwExitCode))
553 {
554 if (ptr_result != NULL)
555 {
556 *ptr_result = (gate_result_t)dwExitCode;
557 }
558 ret = GATE_RESULT_OK;
559 }
560 else
561 {
562 ret = GATE_RESULT_INVALIDOUTPUT;
563 }
564 if (CloseHandle(*thread))
565 {
566 GATE_HANDLESTORE_DESTROY(threadhandle);
567 }
568 else
569 {
570 GATE_DEBUG_TRACE("CloseHandle() failed");
571 GATE_DEBUG_TRACE_VALUE(gate_win32_getlasterror());
572 ret = GATE_RESULT_FAILED;
573 }
574 }
575
576 return ret;
577 }
578 gate_result_t gate_thread_current(gate_thread_t* threadhandle, gate_thread_id_t* threadid)
579 {
580
581 if (threadhandle)
582 {
583 HANDLE* thread = GATE_HANDLESTORE_CREATE(threadhandle, HANDLE);
584 if (thread == NULL)
585 {
586 return GATE_RESULT_OUTOFMEMORY;
587 }
588 *thread = GetCurrentThread();
589 }
590 if (threadid != NULL)
591 {
592 *threadid = (gate_thread_id_t)gate_win32_get_thread_id(); //TODO
593 }
594 return GATE_RESULT_OK;
595 }
596 gate_bool_t gate_thread_equals(gate_thread_t* th1, gate_thread_t* th2)
597 {
598 HANDLE* thread1 = GATE_HANDLESTORE_ACCESS(th1, HANDLE);
599 HANDLE* thread2 = GATE_HANDLESTORE_ACCESS(th2, HANDLE);
600 return gate_win32_get_thread_handle_id(*thread1) == gate_win32_get_thread_handle_id(*thread2);
601 }
602 gate_result_t gate_thread_is_current(gate_thread_t* threadhandle, gate_bool_t* is_current)
603 {
604 HANDLE* ptr_thread = GATE_HANDLESTORE_ACCESS(threadhandle, HANDLE);
605 *is_current = gate_win32_get_thread_handle_id(*ptr_thread) == gate_win32_get_thread_id();
606 return GATE_RESULT_OK;
607 }
608 void gate_thread_sleep(gate_uint32_t milliseconds)
609 {
610 gate_timecounter_t now = 0, start = 0;
611 gate_int64_t diff;
612 gate_int64_t timeout;
613 if (gate_coroutine_enabled())
614 {
615 gate_timecounter_now(&start);
616 timeout = (gate_int64_t)milliseconds * 1000;
617 do
618 {
619 gate_coroutine_yield();
620 gate_timecounter_now(&now);
621 diff = gate_timecounter_diff(now, start);
622 } while (diff < timeout);
623 }
624 else
625 {
626 Sleep((DWORD)milliseconds);
627 }
628 }
629 void gate_thread_yield(void)
630 {
631 if (gate_coroutine_enabled())
632 {
633 gate_coroutine_yield();
634 }
635 else
636 {
637 Sleep(0);
638 }
639 }
640
641 static gate_bool_t gate_win32_thread_yield(void)
642 {
643 Sleep(0);
644 return true;
645 }
646 static gate_bool_t gate_win32_thread_noyield(void)
647 {
648 return false;
649 }
650
651 static gate_bool_t(*gate_win32_thread_yield_function)(void) = NULL;
652
653 #if defined(GATE_SYS_WINSTORE)
654 #define GetSystemInfo(info) GetNativeSystemInfo(info)
655 #endif
656
657 gate_bool_t gate_thread_yield_if_preemptive(void)
658 {
659 SYSTEM_INFO info = GATE_INIT_EMPTY;
660 if (gate_coroutine_enabled())
661 {
662 gate_coroutine_yield();
663 return true;
664 }
665 else
666 {
667 if (gate_win32_thread_yield_function == NULL)
668 {
669 GetSystemInfo(&info);
670 gate_win32_thread_yield_function = (info.dwNumberOfProcessors > 1) ? &gate_win32_thread_noyield : &gate_win32_thread_yield;
671 }
672 return gate_win32_thread_yield_function();
673 }
674 }
675
676 #ifndef TLS_OUT_OF_INDEXES
677 #define TLS_OUT_OF_INDEXES 0xFFFFFFFF
678 #endif
679
680 gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id)
681 {
682 DWORD* ptr_handle = GATE_HANDLESTORE_CREATE(ptr_store_id, DWORD);
683
684 if (NULL == ptr_handle)
685 {
686 return GATE_RESULT_OUTOFMEMORY;
687 }
688
689 *ptr_handle = TlsAlloc();
690
691 if (TLS_OUT_OF_INDEXES == *ptr_handle)
692 {
693 GATE_HANDLESTORE_DESTROY(ptr_store_id);
694 return GATE_RESULT_OUTOFRESOURCES;
695 }
696 return GATE_RESULT_OK;
697 }
698
699 gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data)
700 {
701 DWORD* ptr_handle = GATE_HANDLESTORE_ACCESS(ptr_store_id, DWORD);
702 if (FALSE == TlsSetValue(*ptr_handle, (LPVOID)data))
703 {
704 return gate_platform_print_last_error(NULL, 0);
705 }
706 return GATE_RESULT_OK;
707 }
708
709 gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data)
710 {
711 DWORD* ptr_handle = GATE_HANDLESTORE_ACCESS(ptr_store_id, DWORD);
712 DWORD last_error;
713 void* data = TlsGetValue(*ptr_handle);
714
715 if (data == NULL)
716 {
717 last_error = gate_win32_getlasterror();
718 if (last_error != ERROR_SUCCESS)
719 {
720 return gate_platform_print_error((gate_int32_t)last_error, NULL, 0);
721 }
722 }
723 if (ptr_data)
724 {
725 *ptr_data = data;
726 }
727 return GATE_RESULT_OK;
728 }
729
730 gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id)
731 {
732 DWORD* ptr_handle = GATE_HANDLESTORE_ACCESS(ptr_store_id, DWORD);
733 if (FALSE == TlsFree(*ptr_handle))
734 {
735 return gate_platform_print_last_error(NULL, 0);
736 }
737 GATE_HANDLESTORE_DESTROY(ptr_store_id);
738 return GATE_RESULT_OK;
739 }
740
741 #endif /* #if defined(GATE_THREADING_WINAPI) */
742
743
744
745 #if defined(GATE_THREADING_PTHREAD)
746
747 #include "gate/handles.h"
748 #include <pthread.h>
749 #include <unistd.h>
750
751 2 gate_enumint_t gate_thread_model()
752 {
753 2 return GATE_THREAD_MODEL_NATIVE;
754 }
755
756 11 gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function,
757 gate_thread_native_param_type entry_param,
758 gate_thread_t* thread_handle,
759 gate_thread_id_t* thread_id)
760 {
761 int result;
762 pthread_t* handle;
763
2/4
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
11 if ((entry_function == NULL) || (thread_handle == NULL))
764 {
765 return GATE_RESULT_INVALIDARG;
766 }
767
768 11 handle = GATE_HANDLESTORE_CREATE(thread_handle, pthread_t);
769
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if (handle == NULL)
770 {
771 return GATE_RESULT_OUTOFMEMORY;
772 }
773
774 11 result = pthread_create(handle, 0, entry_function, (void*)entry_param);
775
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (0 == result)
776 {
777
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 5 times.
11 if (thread_id != NULL)
778 {
779 6 *thread_id = (gate_thread_id_t)handle;
780 }
781 11 return GATE_RESULT_OK;
782 }
783 else
784 {
785 GATE_HANDLESTORE_DESTROY(thread_handle);
786 return GATE_RESULT_FAILED;
787 }
788 }
789
790 2 gate_result_t gate_thread_detach(gate_thread_t* thread_handle)
791 {
792 2 pthread_t* handle = GATE_HANDLESTORE_ACCESS(thread_handle, pthread_t);
793
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (handle)
794 {
795 2 pthread_detach(*handle);
796 2 GATE_HANDLESTORE_DESTROY(thread_handle);
797 }
798 2 return GATE_RESULT_OK;
799 }
800 9 gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* ptr_result)
801 {
802 9 gate_result_t ret = GATE_RESULT_FAILED;
803 void* threadresult;
804 9 pthread_t* handle = GATE_HANDLESTORE_ACCESS(thread_handle, pthread_t);
805
806
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 if (handle)
807 {
808
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 if (0 == pthread_join(*handle, &threadresult))
809 {
810
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 if (ptr_result != NULL)
811 {
812 8 *ptr_result = (gate_result_t)(gate_intptr_t)threadresult;
813 }
814 9 ret = GATE_RESULT_OK;
815 }
816 else
817 {
818 ret = GATE_RESULT_FAILED;
819 }
820 9 GATE_HANDLESTORE_DESTROY(thread_handle);
821 }
822 9 return ret;
823 }
824 static pthread_t get_real_pthread(gate_thread_t* thread_handle)
825 {
826 pthread_t* handle = GATE_HANDLESTORE_ACCESS(thread_handle, pthread_t);
827 if (*handle == ((pthread_t)-1))
828 {
829 return pthread_self();
830 }
831 return *handle;
832 }
833
834 14 gate_result_t gate_thread_current(gate_thread_t* thread_handle, gate_thread_id_t* threadid)
835 {
836 14 gate_result_t ret = GATE_RESULT_OK;
837
838
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 13 times.
14 if (thread_handle)
839 {
840 1 pthread_t* handle = GATE_HANDLESTORE_CREATE(thread_handle, pthread_t);
841
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (handle != NULL)
842 {
843 1 *handle = (pthread_t)-1;
844 }
845 else
846 {
847 ret = GATE_RESULT_OUTOFMEMORY;
848 }
849 }
850
851
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 if (threadid != NULL)
852 {
853 14 pthread_t th = pthread_self();
854 14 *threadid = (gate_thread_id_t)th;
855 }
856 14 return ret;
857 }
858
859 4 gate_result_t gate_thread_is_current(gate_thread_t* thread_handle, gate_bool_t* is_current)
860 {
861 4 gate_result_t ret = GATE_RESULT_OK;
862 4 pthread_t* handle = GATE_HANDLESTORE_ACCESS(thread_handle, pthread_t);
863 4 pthread_t th = pthread_self();
864 4 *is_current = (pthread_equal(*handle, th) != 0);
865 4 return ret;
866 }
867
868
869 gate_bool_t gate_thread_equals(gate_thread_t* th1, gate_thread_t* th2)
870 {
871 pthread_t pth1 = get_real_pthread(th1);
872 pthread_t pth2 = get_real_pthread(th2);
873 return (pthread_equal(pth1, pth2) == 0) ? false : true;
874 }
875 5 void gate_thread_sleep(gate_uint32_t milliseconds)
876 {
877 gate_uint32_t seconds;
878 gate_uint32_t millis;
879 gate_timecounter_t now, start;
880 gate_int64_t diff;
881 gate_int64_t timeout;
882
883
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if (gate_coroutine_enabled())
884 {
885 gate_timecounter_now(&start);
886 timeout = (gate_int64_t)milliseconds * 1000;
887 do
888 {
889 gate_coroutine_yield();
890 gate_timecounter_now(&now);
891 diff = gate_timecounter_diff(now, start);
892 } while (diff < timeout);
893 }
894 else
895 {
896 5 seconds = milliseconds / 1000;
897 5 millis = (milliseconds % 1000) * 1000;
898
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (seconds > 0)
899 {
900 sleep(seconds);
901 }
902
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (millis > 0)
903 {
904 4 usleep(millis);
905 }
906 }
907 5 }
908 20 void gate_thread_yield(void)
909 {
910 20 sched_yield();
911 20 }
912 1 gate_bool_t gate_thread_yield_if_preemptive(void)
913 {
914 1 sched_yield();
915 1 return true;
916 }
917
918 4 gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id)
919 {
920 4 pthread_key_t* ptr_handle = GATE_HANDLESTORE_CREATE(ptr_store_id, pthread_key_t);
921 int error;
922
923
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (NULL == ptr_handle)
924 {
925 return GATE_RESULT_OUTOFMEMORY;
926 }
927
928 4 error = pthread_key_create(ptr_handle, NULL);
929
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (error)
930 {
931 GATE_HANDLESTORE_DESTROY(ptr_store_id);
932 return GATE_RESULT_OUTOFRESOURCES;
933 }
934 4 return GATE_RESULT_OK;
935 }
936
937 27 gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data)
938 {
939 27 pthread_key_t* ptr_handle = GATE_HANDLESTORE_ACCESS(ptr_store_id, pthread_key_t);
940 27 int error = pthread_setspecific(*ptr_handle, data);
941
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
27 if (error)
942 {
943 return GATE_RESULT_FAILED;
944 }
945 27 return GATE_RESULT_OK;
946 }
947
948 837332 gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data)
949 {
950 837332 pthread_key_t* ptr_handle = GATE_HANDLESTORE_ACCESS(ptr_store_id, pthread_key_t);
951 837332 void* data = pthread_getspecific(*ptr_handle);
952
1/2
✓ Branch 0 taken 837332 times.
✗ Branch 1 not taken.
837332 if (ptr_data)
953 {
954 837332 *ptr_data = data;
955 }
956 837332 return GATE_RESULT_OK;
957 }
958
959 1 gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id)
960 {
961 1 pthread_key_t* ptr_handle = GATE_HANDLESTORE_ACCESS(ptr_store_id, pthread_key_t);
962 1 int error = pthread_key_delete(*ptr_handle);
963
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (error)
964 {
965 return GATE_RESULT_FAILED;
966 }
967 1 GATE_HANDLESTORE_DESTROY(ptr_store_id);
968 1 return GATE_RESULT_OK;
969 }
970
971 #endif /* GATE_THREADING_PTHREAD */
972
973
974
975 #if defined(GATE_THREADING_BEOS)
976
977 #include <kernel/OS.h>
978 #include <support/TLS.h>
979
980 gate_enumint_t gate_thread_model()
981 {
982 return GATE_THREAD_MODEL_NATIVE;
983 }
984
985 gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function,
986 gate_thread_native_param_type entry_param,
987 gate_thread_t* ptr_thread_handle,
988 gate_thread_id_t* ptr_thread_id)
989 {
990 status_t tstat;
991 thread_id tid;
992
993 tid = spawn_thread((thread_func)entry_function, "thread", B_NORMAL_PRIORITY, entry_param);
994
995 if (tid == B_NO_MEMORY)
996 {
997 return GATE_RESULT_OUTOFMEMORY;
998 }
999 else if (tid == B_NO_MORE_THREADS)
1000 {
1001 return GATE_RESULT_OUTOFRESOURCES;
1002 }
1003
1004 tstat = resume_thread(tid);
1005 if (B_OK != tstat)
1006 {
1007 kill_thread(tid);
1008 return GATE_RESULT_FAILED;
1009 }
1010
1011
1012 if (ptr_thread_handle)
1013 {
1014 thread_id* ptr_tid = GATE_HANDLESTORE_CREATE(ptr_thread_handle, thread_id);
1015 if (NULL == ptr_tid)
1016 {
1017 kill_thread(tid);
1018 return GATE_RESULT_OUTOFMEMORY;
1019 }
1020 *ptr_tid = tid;
1021 }
1022 if (ptr_thread_id)
1023 {
1024 *ptr_thread_id = (gate_thread_id_t)tid;
1025 }
1026
1027 return GATE_RESULT_OK;
1028 }
1029
1030
1031 gate_result_t gate_thread_detach(gate_thread_t* thread_handle)
1032 {
1033 thread_id* handle = GATE_HANDLESTORE_ACCESS(thread_handle, thread_id);
1034 if (handle)
1035 {
1036 GATE_HANDLESTORE_DESTROY(thread_handle);
1037 }
1038 return GATE_RESULT_OK;
1039 }
1040
1041 gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* result)
1042 {
1043 gate_result_t ret = GATE_RESULT_FAILED;
1044 status_t status;
1045 status_t thread_status;
1046 thread_id* handle = GATE_HANDLESTORE_ACCESS(thread_handle, thread_id);
1047 if (handle)
1048 {
1049 status = wait_for_thread(*handle, &thread_status);
1050 if (B_OK == status)
1051 {
1052 if (result)
1053 {
1054 *result = (gate_result_t)thread_status;
1055 }
1056 GATE_HANDLESTORE_DESTROY(thread_handle);
1057 ret = GATE_RESULT_OK;
1058 }
1059 else if (B_OK == B_INTERRUPTED)
1060 {
1061 if (result)
1062 {
1063 *result = GATE_RESULT_CANCELED;
1064 }
1065 GATE_HANDLESTORE_DESTROY(thread_handle);
1066 ret = GATE_RESULT_OK;
1067 }
1068 else
1069 {
1070 ret = GATE_RESULT_FAILED;
1071 }
1072 }
1073 return ret;
1074 }
1075
1076 gate_result_t gate_thread_current(gate_thread_t* ptr_thread_handle, gate_thread_id_t* ptr_thread_id)
1077 {
1078 thread_id tid = find_thread(NULL);
1079
1080 if (ptr_thread_handle)
1081 {
1082 thread_id* ptr_tid = GATE_HANDLESTORE_CREATE(ptr_thread_handle, thread_id);
1083 if (NULL == ptr_tid)
1084 {
1085 kill_thread(tid);
1086 return GATE_RESULT_OUTOFMEMORY;
1087 }
1088 *ptr_tid = tid;
1089 }
1090 if (ptr_thread_id)
1091 {
1092 *ptr_thread_id = (gate_thread_id_t)tid;
1093 }
1094 return GATE_RESULT_OK;
1095 }
1096
1097 gate_result_t gate_thread_is_current(gate_thread_t* ptr_thread_handle, gate_bool_t* is_current)
1098 {
1099 thread_id cur_tid = find_thread(NULL);
1100 thread_id* ptr_tid = GATE_HANDLESTORE_ACCESS(ptr_thread_handle, thread_id);
1101 if (!ptr_tid)
1102 {
1103 return GATE_RESULT_INVALIDARG;
1104 }
1105 if (is_current)
1106 {
1107 *is_current = *ptr_tid == cur_tid;
1108 }
1109 return GATE_RESULT_OK;
1110 }
1111
1112 gate_bool_t gate_thread_equals(gate_thread_t* thread_handle_1, gate_thread_t* thread_handle_2)
1113 {
1114 thread_id* ptr_tid1 = GATE_HANDLESTORE_ACCESS(thread_handle_1, thread_id);
1115 thread_id* ptr_tid2 = GATE_HANDLESTORE_ACCESS(thread_handle_2, thread_id);
1116 if (ptr_tid1 == ptr_tid2)
1117 {
1118 return true;
1119 }
1120 else if ((ptr_tid1 == NULL) || (ptr_tid2 == NULL))
1121 {
1122 return false;
1123 }
1124 else
1125 {
1126 return *ptr_tid1 == *ptr_tid2;
1127 }
1128 }
1129
1130 void gate_thread_sleep(gate_uint32_t milliseconds)
1131 {
1132 bigtime_t usec = (bigtime_t)milliseconds * 1000;
1133 snooze(usec);
1134 }
1135
1136 void gate_thread_yield(void)
1137 {
1138 }
1139
1140 gate_bool_t gate_thread_yield_if_preemptive(void)
1141 {
1142 return false;
1143 }
1144
1145 gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id)
1146 {
1147 int32* ptr_ts = GATE_HANDLESTORE_CREATE(ptr_store_id, int32);
1148 if (NULL == ptr_ts)
1149 {
1150 return GATE_RESULT_OUTOFMEMORY;
1151 }
1152 *ptr_ts = tls_allocate();
1153 return GATE_RESULT_OK;
1154 }
1155 gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data)
1156 {
1157 int32* ptr_ts = GATE_HANDLESTORE_ACCESS(ptr_store_id, int32);
1158 if (!ptr_ts)
1159 {
1160 return GATE_RESULT_NOTAVAILABLE;
1161 }
1162 tls_set(*ptr_ts, data);
1163 return GATE_RESULT_OK;
1164 }
1165
1166 gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data)
1167 {
1168 int32* ptr_ts = GATE_HANDLESTORE_ACCESS(ptr_store_id, int32);
1169 void* ptr_ts_data = NULL;
1170 if (!ptr_ts)
1171 {
1172 return GATE_RESULT_NOTAVAILABLE;
1173 }
1174 ptr_ts_data = tls_get(*ptr_ts);
1175 if (ptr_data)
1176 {
1177 *ptr_data = ptr_ts_data;
1178 }
1179 return GATE_RESULT_OK;
1180 }
1181
1182 gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id)
1183 {
1184 int32* ptr_ts = GATE_HANDLESTORE_ACCESS(ptr_store_id, int32);
1185 if (!ptr_ts)
1186 {
1187 return GATE_RESULT_NOTAVAILABLE;
1188 }
1189 GATE_HANDLESTORE_DESTROY(ptr_store_id);
1190 return GATE_RESULT_OK;
1191 }
1192
1193 #endif /* GATE_THREADING_BEOS */
1194
1195
1196
1197 #ifdef GATE_THREADING_COROUTINES
1198
1199 #include "gate/platform/efi/efi_gate.h"
1200 #include "gate/coroutines.h"
1201
1202 gate_enumint_t gate_thread_model()
1203 {
1204 return GATE_THREAD_MODEL_MANUAL;
1205 }
1206
1207
1208 gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function,
1209 gate_thread_native_param_type entry_param,
1210 gate_thread_t* thread_handle, gate_thread_id_t* thread_id)
1211 {
1212 gate_result_t ret;
1213 gate_coroutine_id_t* ptr_co_id;
1214
1215 if ((NULL == entry_function) || (NULL == thread_handle))
1216 {
1217 return GATE_RESULT_INVALIDARG;
1218 }
1219
1220 ptr_co_id = GATE_HANDLESTORE_CREATE(thread_handle, gate_coroutine_id_t);
1221 if (NULL == ptr_co_id)
1222 {
1223 return GATE_RESULT_OUTOFMEMORY;
1224 }
1225
1226 ret = gate_coroutine_create(entry_function, entry_param, ptr_co_id);
1227 if (GATE_FAILED(ret))
1228 {
1229 GATE_HANDLESTORE_DESTROY(thread_handle);
1230 return ret;
1231 }
1232
1233 if (thread_id)
1234 {
1235 *thread_id = (gate_thread_id_t)*ptr_co_id;
1236 }
1237 return ret;
1238 }
1239
1240 gate_result_t gate_thread_detach(gate_thread_t* thread_handle)
1241 {
1242 GATE_HANDLESTORE_DESTROY(thread_handle);
1243 return GATE_RESULT_OK;
1244 }
1245
1246 gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* result)
1247 {
1248 gate_result_t ret = GATE_RESULT_FAILED;
1249 gate_coroutine_id_t* ptr_co_id = GATE_HANDLESTORE_ACCESS(thread_handle, gate_coroutine_id_t);
1250
1251 if (ptr_co_id)
1252 {
1253 ret = gate_coroutine_await(*ptr_co_id, result);
1254 }
1255 else
1256 {
1257 ret = GATE_RESULT_NOTAVAILABLE;
1258 }
1259 return ret;
1260 }
1261
1262 gate_result_t gate_thread_current(gate_thread_t* thread_handle, gate_thread_id_t* thread_id)
1263 {
1264 gate_result_t ret = GATE_RESULT_FAILED;
1265 gate_coroutine_id_t co_id;
1266
1267 ret = gate_coroutine_get_current(&co_id);
1268 if (GATE_SUCCEEDED(ret))
1269 {
1270 if (thread_handle)
1271 {
1272 gate_coroutine_id_t* ptr_co_id = GATE_HANDLESTORE_CREATE(thread_handle, gate_coroutine_id_t);
1273 *ptr_co_id = co_id;
1274 }
1275 if (thread_id)
1276 {
1277 *thread_id = (gate_thread_id_t)co_id;
1278 }
1279 }
1280 return ret;
1281 }
1282
1283 gate_result_t gate_thread_is_current(gate_thread_t* thread_handle, gate_bool_t* is_current)
1284 {
1285 gate_result_t ret = GATE_RESULT_FAILED;
1286 gate_coroutine_id_t co_id;
1287
1288 ret = gate_coroutine_get_current(&co_id);
1289 if (GATE_SUCCEEDED(ret))
1290 {
1291 gate_coroutine_id_t* ptr_co_id = GATE_HANDLESTORE_ACCESS(thread_handle, gate_coroutine_id_t);
1292 if (ptr_co_id)
1293 {
1294 if (is_current)
1295 {
1296 *is_current = *ptr_co_id == co_id;
1297 }
1298 }
1299 }
1300 return ret;
1301 }
1302
1303 gate_bool_t gate_thread_equals(gate_thread_t* thread_handle_1, gate_thread_t* thread_handle_2)
1304 {
1305 gate_coroutine_id_t* ptr_co_id1 = GATE_HANDLESTORE_ACCESS(thread_handle_1, gate_coroutine_id_t);
1306 gate_coroutine_id_t* ptr_co_id2 = GATE_HANDLESTORE_ACCESS(thread_handle_2, gate_coroutine_id_t);
1307
1308 if (ptr_co_id1 && ptr_co_id2)
1309 {
1310 return *ptr_co_id1 == *ptr_co_id2;
1311 }
1312 return false;
1313 }
1314
1315 void gate_thread_sleep(gate_uint32_t milliseconds)
1316 {
1317 gate_coroutine_sleep(milliseconds);
1318 //gate_platform_efi_wait(milliseconds);
1319 }
1320
1321 void gate_thread_yield(void)
1322 {
1323 gate_coroutine_yield();
1324 }
1325
1326 gate_bool_t gate_thread_yield_if_preemptive(void)
1327 {
1328 gate_coroutine_yield();
1329 return true;
1330 }
1331
1332 gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id)
1333 {
1334 GATE_UNUSED_ARG(ptr_store_id);
1335 return GATE_RESULT_NOTSUPPORTED;
1336 }
1337
1338 gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data)
1339 {
1340 GATE_UNUSED_ARG(ptr_store_id);
1341 GATE_UNUSED_ARG(data);
1342 return GATE_RESULT_NOTSUPPORTED;
1343 }
1344
1345 gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data)
1346 {
1347 GATE_UNUSED_ARG(ptr_store_id);
1348 GATE_UNUSED_ARG(ptr_data);
1349 return GATE_RESULT_NOTSUPPORTED;
1350 }
1351
1352 gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id)
1353 {
1354 GATE_UNUSED_ARG(ptr_store_id);
1355 return GATE_RESULT_NOTSUPPORTED;
1356 }
1357
1358 #endif /* GATE_THREADING_COROUTINES */
1359
1360
1361
1362 #if defined(GATE_THREADING_WASM)
1363
1364 #include "gate/platform/wasm/wasm_gate.h"
1365 #include <stdlib.h>
1366
1367 gate_enumint_t gate_thread_model()
1368 {
1369 return GATE_THREAD_MODEL_NATIVE;
1370 }
1371
1372
1373 typedef struct
1374 {
1375 gate_thread_native_entry entry_function;
1376 gate_thread_native_param_type entry_param;
1377 } worker_param_t;
1378
1379 static gate_result_t wasm_thread_dispatcher(gate_dataptr_t arg)
1380 {
1381 worker_param_t* ptr_param = (worker_param_t*)arg;
1382 gate_thread_native_entry func = ptr_param->entry_function;
1383 gate_thread_native_param_type func_param = ptr_param->entry_param;
1384 gate_thread_native_return_type func_ret_value = (gate_thread_native_return_type)0;
1385 gate_wasm_worker_id_t worker_id = gate_wasm_worker_id();
1386
1387 if (func)
1388 {
1389 func_ret_value = func(func_param);
1390 }
1391
1392 gate_wasm_worker_completed(worker_id, (gate_result_t)func_ret_value);
1393 return GATE_RESULT_OK;
1394 }
1395
1396 gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function,
1397 gate_thread_native_param_type entry_param,
1398 gate_thread_t* thread_handle,
1399 gate_thread_id_t* thread_id)
1400 {
1401 gate_result_t ret = GATE_RESULT_FAILED;
1402 gate_wasm_worker_id_t worker_id = NULL;
1403 worker_param_t* ptr_worker_param = NULL;
1404
1405 do
1406 {
1407 ptr_worker_param = (worker_param_t*)malloc(sizeof(worker_param_t));
1408 if (ptr_worker_param == NULL)
1409 {
1410 ret = GATE_RESULT_OUTOFMEMORY;
1411 break;
1412 }
1413
1414 ptr_worker_param->entry_function = entry_function;
1415 ptr_worker_param->entry_param = entry_param;
1416
1417 ret = gate_wasm_worker_create(&worker_id);
1418 GATE_BREAK_IF_FAILED(ret);
1419
1420 ret = gate_wasm_worker_post_task(worker_id, &wasm_thread_dispatcher, ptr_worker_param);
1421 GATE_BREAK_IF_FAILED(ret);
1422
1423 /* success case */
1424 ret = GATE_RESULT_OK;
1425
1426 if (thread_handle)
1427 {
1428 gate_wasm_worker_id_t* ptr_handle = GATE_HANDLESTORE_CREATE(thread_handle, gate_wasm_worker_id_t);
1429 *ptr_handle = worker_id;
1430 }
1431
1432 if (thread_id)
1433 {
1434 *thread_id = (gate_thread_id_t)worker_id;
1435 }
1436
1437 worker_id = NULL;
1438 ptr_worker_param = NULL;
1439
1440 } while (0);
1441
1442 if (worker_id)
1443 {
1444 gate_wasm_worker_destroy(worker_id);
1445 }
1446
1447 if (ptr_worker_param)
1448 {
1449 free(ptr_worker_param);
1450 }
1451
1452 return ret;
1453 }
1454
1455
1456 gate_result_t gate_thread_detach(gate_thread_t* thread_handle)
1457 {
1458 GATE_HANDLESTORE_DESTROY(thread_handle);
1459 return GATE_RESULT_OK;
1460 }
1461
1462 gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* result)
1463 {
1464 gate_result_t ret = GATE_RESULT_INVALIDARG;
1465 gate_wasm_worker_id_t* ptr_handle = GATE_HANDLESTORE_ACCESS(thread_handle, gate_wasm_worker_id_t);
1466
1467 if (ptr_handle && *ptr_handle)
1468 {
1469 ret = gate_wasm_worker_join(*ptr_handle, result);
1470 }
1471 return ret;
1472 }
1473
1474 gate_result_t gate_thread_current(gate_thread_t* thread_handle, gate_thread_id_t* thread_id)
1475 {
1476 gate_wasm_worker_id_t worker_id = gate_wasm_worker_id();
1477 if (thread_handle)
1478 {
1479 gate_wasm_worker_id_t* ptr_handle = GATE_HANDLESTORE_CREATE(thread_handle, gate_wasm_worker_id_t);
1480 *ptr_handle = worker_id;
1481 }
1482
1483 if (thread_id)
1484 {
1485 *thread_id = (gate_thread_id_t)worker_id;
1486 }
1487 return GATE_RESULT_OK;
1488 }
1489
1490 gate_result_t gate_thread_is_current(gate_thread_t* thread_handle, gate_bool_t* is_current)
1491 {
1492 gate_wasm_worker_id_t worker_id = gate_wasm_worker_id();
1493 gate_wasm_worker_id_t* ptr_handle = GATE_HANDLESTORE_ACCESS(thread_handle, gate_wasm_worker_id_t);
1494 if (ptr_handle)
1495 {
1496 if (is_current)
1497 {
1498 *is_current = *ptr_handle == worker_id;
1499 }
1500 return GATE_RESULT_OK;
1501 }
1502 return GATE_RESULT_INVALIDARG;
1503 }
1504
1505 gate_bool_t gate_thread_equals(gate_thread_t* thread_handle_1, gate_thread_t* thread_handle_2)
1506 {
1507 gate_wasm_worker_id_t* ptr_handle_1 = GATE_HANDLESTORE_ACCESS(thread_handle_1, gate_wasm_worker_id_t);
1508 gate_wasm_worker_id_t* ptr_handle_2 = GATE_HANDLESTORE_ACCESS(thread_handle_2, gate_wasm_worker_id_t);
1509 if (!ptr_handle_1 || !ptr_handle_2)
1510 {
1511 return false;
1512 }
1513 return *ptr_handle_1 == ptr_handle_2;
1514 }
1515
1516 void gate_thread_sleep(gate_uint32_t milliseconds)
1517 {
1518 gate_wasm_thread_sleep(milliseconds);
1519 }
1520
1521 void gate_thread_yield(void)
1522 {
1523 }
1524
1525 gate_bool_t gate_thread_yield_if_preemptive(void)
1526 {
1527 return false;
1528 }
1529
1530 gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id)
1531 {
1532 void** ptr_tss = GATE_HANDLESTORE_CREATE(ptr_store_id, void*);
1533 if (NULL == ptr_tss)
1534 {
1535 return GATE_RESULT_OUTOFMEMORY;
1536 }
1537 *ptr_tss = NULL;
1538 return GATE_RESULT_OK;
1539 }
1540 gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data)
1541 {
1542 void** ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, void*);
1543 *ptr_tss = data;
1544 return GATE_RESULT_OK;
1545 }
1546
1547 gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data)
1548 {
1549 void** ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, void*);
1550 *ptr_data = *ptr_tss;
1551 return GATE_RESULT_OK;
1552 }
1553
1554 gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id)
1555 {
1556 GATE_HANDLESTORE_DESTROY(ptr_store_id);
1557 return GATE_RESULT_OK;
1558 }
1559
1560
1561
1562 #endif /* GATE_THREADING_WASM */
1563
1564
1565
1566 #if defined(GATE_THREADING_NO_IMPL)
1567
1568 gate_enumint_t gate_thread_model()
1569 {
1570 return GATE_THREAD_MODEL_NONE;
1571 }
1572
1573 gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function,
1574 gate_thread_native_param_type entry_param,
1575 gate_thread_t* thread_handle,
1576 gate_thread_id_t* thread_id)
1577 {
1578 GATE_UNUSED_ARG(entry_function);
1579 GATE_UNUSED_ARG(entry_param);
1580 GATE_UNUSED_ARG(thread_handle);
1581 GATE_UNUSED_ARG(thread_id);
1582 return GATE_RESULT_NOTSUPPORTED;
1583 }
1584
1585
1586 gate_result_t gate_thread_detach(gate_thread_t* thread_handle)
1587 {
1588 GATE_UNUSED_ARG(thread_handle);
1589 return GATE_RESULT_NOTSUPPORTED;
1590 }
1591
1592 gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* result)
1593 {
1594 GATE_UNUSED_ARG(thread_handle);
1595 GATE_UNUSED_ARG(result);
1596 return GATE_RESULT_NOTSUPPORTED;
1597 }
1598
1599 gate_result_t gate_thread_current(gate_thread_t* thread_handle, gate_thread_id_t* thread_id)
1600 {
1601 GATE_UNUSED_ARG(thread_handle);
1602 GATE_UNUSED_ARG(thread_id);
1603 return GATE_RESULT_NOTSUPPORTED;
1604 }
1605
1606 gate_result_t gate_thread_is_current(gate_thread_t* thread_handle, gate_bool_t* is_current)
1607 {
1608 GATE_UNUSED_ARG(thread_handle);
1609 GATE_UNUSED_ARG(is_current);
1610 return GATE_RESULT_NOTSUPPORTED;
1611 }
1612
1613 gate_bool_t gate_thread_equals(gate_thread_t* thread_handle_1, gate_thread_t* thread_handle_2)
1614 {
1615 GATE_UNUSED_ARG(thread_handle_1);
1616 GATE_UNUSED_ARG(thread_handle_2);
1617 return false;
1618 }
1619
1620 void gate_thread_sleep(gate_uint32_t milliseconds)
1621 {
1622 GATE_UNUSED_ARG(milliseconds);
1623 }
1624
1625 void gate_thread_yield(void)
1626 {
1627 }
1628
1629 gate_bool_t gate_thread_yield_if_preemptive(void)
1630 {
1631 return false;
1632 }
1633
1634 gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id)
1635 {
1636 void** ptr_tss = GATE_HANDLESTORE_CREATE(ptr_store_id, void*);
1637 if (NULL == ptr_tss)
1638 {
1639 return GATE_RESULT_OUTOFMEMORY;
1640 }
1641 *ptr_tss = NULL;
1642 return GATE_RESULT_OK;
1643 }
1644 gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data)
1645 {
1646 void** ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, void*);
1647 *ptr_tss = data;
1648 return GATE_RESULT_OK;
1649 }
1650
1651 gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data)
1652 {
1653 void** ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, void*);
1654 *ptr_data = *ptr_tss;
1655 return GATE_RESULT_OK;
1656 }
1657
1658 gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id)
1659 {
1660 GATE_HANDLESTORE_DESTROY(ptr_store_id);
1661 return GATE_RESULT_OK;
1662 }
1663
1664
1665 #endif /* GATE_THREADING_NO_IMPL */
1666