GCC Code Coverage Report


Directory: src/gate/
File: src/gate/threading.c
Date: 2026-09-21 06:26:40
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-2026, 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 12 static gate_thread_native_return_type GATE_THREAD_API gate_thread_start_entry_point(gate_thread_native_param_type param)
41 {
42 12 gate_runnable_t* executor = (gate_runnable_t*)(void*)param;
43 12 gate_result_t ret = GATE_RESULT_NULLPOINTER;
44
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (executor)
45 {
46 12 ret = gate_runnable_run(executor);
47 12 gate_object_release(executor);
48 }
49 else
50 {
51 ret = GATE_RESULT_NULLPOINTER;
52 }
53 12 return (gate_thread_native_return_type)(gate_intptr_t)ret;
54 }
55
56 12 gate_result_t gate_thread_start(gate_runnable_t* executor, gate_thread_t* thread_handle, gate_thread_id_t* thread_id)
57 {
58 12 gate_result_t ret = GATE_RESULT_FAILED;
59
60 do
61 {
62
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (executor == NULL)
63 {
64 ret = GATE_RESULT_NULLPOINTER;
65 break;
66 }
67
68 12 gate_object_retain(executor);
69 12 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 12 times.
✗ Branch 1 not taken.
12 if (GATE_SUCCEEDED(ret))
73 {
74 12 executor = NULL;
75 }
76 } while (0);
77
78
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (executor != NULL)
79 {
80 gate_object_release(executor);
81 }
82
83 12 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 12 static void gate_thread_dispatcher_release(void* disp)
98 {
99 12 gate_thread_dispatcher_t* ptr = (gate_thread_dispatcher_t*)disp;
100
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
12 if (gate_atomic_int_dec(&ptr->ref_counter) == 0)
101 {
102 6 gate_mem_dealloc(ptr);
103 }
104 12 }
105 6 static int gate_thread_dispatcher_retain(void* disp)
106 {
107 6 gate_thread_dispatcher_t* ptr = (gate_thread_dispatcher_t*)disp;
108 6 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 6 static gate_result_t gate_thread_dispatcher_run(void* disp)
117 {
118 6 gate_thread_dispatcher_t* ptr = (gate_thread_dispatcher_t*)disp;
119 6 return ptr->callback(ptr->data);
120 }
121
122 static GATE_INTERFACE_VTBL(gate_runnable) gate_thread_dispatcher_vtbl;
123 6 static void gate_init_thread_dispatcher_vtbl()
124 {
125
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 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 4 gate_thread_dispatcher_vtbl = local_vtbl;
135 }
136 6 }
137
138 6 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 6 gate_thread_dispatcher_t* disp = gate_mem_alloc(sizeof(gate_thread_dispatcher_t));
142
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (disp == NULL)
143 {
144 ret = GATE_RESULT_OUTOFMEMORY;
145 }
146 else
147 {
148 6 gate_init_thread_dispatcher_vtbl();
149 6 disp->vtbl = &gate_thread_dispatcher_vtbl;
150 6 gate_atomic_int_init(&disp->ref_counter, 1);
151 6 disp->callback = callback;
152 6 disp->data = data;
153 6 ret = gate_thread_start((gate_runnable_t*)disp, threadhandle, threadid);
154 6 gate_object_release(disp);
155 }
156 6 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 #elif defined(GATE_SYS_ARDUINO)
172 # define GATE_THREADING_ARDUINO_IMPL 1
173 #else
174 # define GATE_THREADING_NO_IMPL 1
175 #endif
176
177
178 #if defined(GATE_THREADING_STD_C)
179
180 #if defined _MSC_VER
181 # include <thr/xthreads.h>
182 # include <windows.h>
183
184
185 typedef _Thrd_t thrd_t;
186 typedef _Thrd_start_t thrd_start_t;
187
188 #define thrd_create(thr, fun, arg) _Thrd_create(thr, fun, arg)
189
190 #define thrd_detach(thr) _Thrd_detach(thr)
191 #define thrd_exit(code) _Thrd_exit(code)
192 #define thrd_join(thr, res) _Thrd_join(thr, res)
193 #define thrd_sleep(tm) _Thrd_sleep(tm)
194 #define thrd_yield _Thrd_yield
195 #define thrd_equal(thr0, thr1) _Thrd_equal(thr0, thr1)
196 #define thrd_current _Thrd_current
197
198 #define thrd_success _Thrd_success
199 #define thrd_nomem _Thrd_nomem
200 #define thrd_error _Thrd_error
201
202
203 typedef DWORD tss_t;
204 typedef void(*tss_dtor_t)(void*);
205
206 int tss_create(tss_t* tss_key, tss_dtor_t dtor)
207 {
208 if (!tss_key)
209 {
210 return thrd_error;
211 }
212 *tss_key = TlsAlloc();
213 if (*tss_key == TLS_OUT_OF_INDEXES)
214 {
215 return thrd_error;
216 }
217 return thrd_success;
218 }
219 void* tss_get(tss_t tss_key)
220 {
221 return TlsGetValue(tss_key);
222 }
223 int tss_set(tss_t tss_id, void* val)
224 {
225 if (TlsSetValue(tss_id, val))
226 {
227 return thrd_success;
228 }
229 else
230 {
231 return thrd_error;
232 }
233 }
234 void tss_delete(tss_t tss_id)
235 {
236 TlsFree(tss_id);
237 }
238
239
240 #else
241 # include <threads.h>
242 #endif
243 #include <time.h>
244
245 static int gate_thread_entry_function(void* ptr)
246 {
247 gate_runnable_t* executor = (gate_runnable_t*)ptr;
248 gate_result_t ret = gate_runnable_run(executor);
249 gate_object_release(executor);
250 return ret;
251 }
252
253 gate_enumint_t gate_thread_model()
254 {
255 return GATE_THREAD_MODEL_NATIVE;
256 }
257
258 gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function, gate_thread_native_param_type entry_param,
259 gate_thread_t* thread_handle, gate_thread_id_t* thread_id)
260 {
261 gate_result_t ret = GATE_RESULT_FAILED;
262 thrd_t* th = NULL;
263
264 do
265 {
266 if (entry_function == NULL)
267 {
268 ret = GATE_RESULT_NULLPOINTER;
269 break;
270 }
271
272 th = GATE_HANDLESTORE_CREATE(thread_handle, thrd_t);
273 if (th == NULL)
274 {
275 ret = GATE_RESULT_OUTOFMEMORY;
276 break;
277 }
278
279 int result = thrd_create(th, entry_function, entry_param);
280 switch (result)
281 {
282 case thrd_success:
283 {
284 if (thread_id != NULL)
285 {
286 *thread_id = (gate_uintptr_t)th;
287 }
288 break;
289 }
290 case thrd_nomem:
291 {
292 GATE_HANDLESTORE_DESTROY(thread_handle);
293 ret = GATE_RESULT_OUTOFRESOURCES;
294 break;
295 }
296 default:
297 {
298 GATE_HANDLESTORE_DESTROY(thread_handle);
299 ret = GATE_RESULT_FAILED;
300 break;
301 }
302 }
303
304 } while (0);
305 return ret;
306 }
307 gate_result_t gate_thread_detach(gate_thread_t* thread_handle)
308 {
309 thrd_t* th = GATE_HANDLESTORE_ACCESS(thread_handle, thrd_t);
310 if (th != NULL)
311 {
312 thrd_detach(*th);
313 GATE_HANDLESTORE_DESTROY(thread_handle);
314 }
315 return GATE_RESULT_OK;
316 }
317 gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* result)
318 {
319 gate_result_t ret = GATE_RESULT_INVALIDARG;
320 thrd_t* th = GATE_HANDLESTORE_ACCESS(thread_handle, thrd_t);
321 int thread_result;
322 int api_result;
323
324 if (th != NULL)
325 {
326 api_result = thrd_join(*th, &thread_result);
327 if (api_result == thrd_success)
328 {
329 ret = thread_result;
330 if (result)
331 {
332 *result = (gate_result_t)thread_result;
333 }
334 }
335 else
336 {
337 ret = GATE_RESULT_FAILED;
338 }
339 GATE_HANDLESTORE_DESTROY(thread_handle);
340 }
341 return ret;
342 }
343 gate_result_t gate_thread_current(gate_thread_t* thread_handle, gate_thread_id_t* thread_id)
344 {
345 gate_result_t ret = GATE_RESULT_FAILED;
346 thrd_t* th = GATE_HANDLESTORE_CREATE(thread_handle, thrd_t);
347 if (th != NULL)
348 {
349 *th = thrd_current();
350 if (thread_id != NULL)
351 {
352 *thread_id = (gate_uintptr_t)th;
353 }
354 ret = GATE_RESULT_OK;
355 }
356 return ret;
357 }
358 gate_result_t gate_thread_is_current(gate_thread_t* threadhandle, gate_bool_t* is_current)
359 {
360 thrd_t* thrd = GATE_HANDLESTORE_ACCESS(threadhandle, thrd_t);
361 thrd_t current_thread = thrd_current();
362
363 if (is_current)
364 {
365 *is_current = thrd_equal(current_thread, *thrd) != 0;
366 }
367 return GATE_RESULT_OK;
368 }
369 gate_bool_t gate_thread_equals(gate_thread_t* th1, gate_thread_t* th2)
370 {
371 thrd_t dummy;
372 thrd_t* thrd1 = GATE_HANDLESTORE_ACCESS(th1, thrd_t);
373 thrd_t* thrd2 = GATE_HANDLESTORE_ACCESS(th2, thrd_t);
374
375 if (thrd1 == NULL || thrd2 == NULL)
376 {
377 dummy = thrd_current();
378 if (thrd1 == NULL)
379 {
380 thrd1 = &dummy;
381 }
382 if (thrd2 == NULL)
383 {
384 thrd2 = &dummy;
385 }
386 }
387
388 return (0 == thrd_equal(*thrd1, *thrd2)) ? true : false;
389 }
390 void gate_thread_sleep(gate_uint32_t milliseconds)
391 {
392 clock_t start = clock();
393 clock_t now;
394 gate_uint32_t diff;
395 do
396 {
397 gate_thread_yield();
398 now = clock();
399 diff = (gate_uint32_t)((now - start) * 1000 / CLOCKS_PER_SEC);
400 } while (diff < milliseconds);
401 }
402 void gate_thread_yield(void)
403 {
404 thrd_yield();
405 }
406 gate_bool_t gate_thread_yield_if_preemptive(void)
407 {
408 thrd_yield();
409 return true;
410 }
411
412
413
414
415 gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id)
416 {
417 tss_t* ptr_tss = GATE_HANDLESTORE_CREATE(ptr_store_id, tss_t);
418 if (NULL == ptr_tss)
419 {
420 return GATE_RESULT_OUTOFMEMORY;
421 }
422 if (thrd_success != tss_create(ptr_tss, NULL))
423 {
424 GATE_HANDLESTORE_DESTROY(ptr_store_id);
425 return GATE_RESULT_FAILED;
426 }
427 return GATE_RESULT_OK;
428 }
429 gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data)
430 {
431 tss_t* ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, tss_t);
432 if (!ptr_tss)
433 {
434 return GATE_RESULT_INVALIDARG;
435 }
436 if (thrd_success != tss_set(*ptr_tss, data))
437 {
438 return GATE_RESULT_FAILED;
439 }
440
441 return GATE_RESULT_OK;
442 }
443 gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data)
444 {
445 tss_t* ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, tss_t);
446 if (!ptr_tss)
447 {
448 return GATE_RESULT_INVALIDARG;
449 }
450 if (ptr_data)
451 {
452 *ptr_data = tss_get(*ptr_tss);
453 }
454 return GATE_RESULT_OK;
455 }
456 gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id)
457 {
458 tss_t* ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, tss_t);
459 if (!ptr_tss)
460 {
461 return GATE_RESULT_INVALIDARG;
462 }
463 tss_delete(*ptr_tss);
464 GATE_HANDLESTORE_DESTROY(ptr_store_id);
465 return GATE_RESULT_OK;
466 }
467
468
469
470
471 #endif /* GATE_THREADING_STD_C */
472
473 #if defined(GATE_THREADING_WINAPI)
474
475 #include "gate/platforms.h"
476
477 gate_enumint_t gate_thread_model()
478 {
479 return GATE_THREAD_MODEL_NATIVE;
480 }
481
482 gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function, gate_thread_native_param_type entry_param,
483 gate_thread_t* thread_handle, gate_thread_id_t* thread_id)
484 {
485 gate_result_t ret;
486 if ((entry_function == NULL) || (thread_handle == NULL))
487 {
488 ret = GATE_RESULT_INVALIDARG;
489 }
490 else
491 {
492 DWORD id;
493 HANDLE* handle = GATE_HANDLESTORE_CREATE(thread_handle, HANDLE);
494 *handle = gate_win32_createthread(entry_function, entry_param, 0, &id);
495 if (*handle == NULL)
496 {
497 GATE_DEBUG_TRACE("gate_win32_createthread() failed");
498 GATE_DEBUG_TRACE_VALUE(gate_win32_getlasterror());
499
500 ret = GATE_RESULT_FAILED;
501 gate_win32_print_lasterror(&ret, NULL, 0);
502 GATE_HANDLESTORE_DESTROY(thread_handle);
503 }
504 else
505 {
506 ret = GATE_RESULT_OK;
507 if (thread_id != NULL)
508 {
509 *thread_id = (gate_thread_id_t)id;
510 }
511 }
512 }
513 return ret;
514
515 }
516
517 gate_result_t gate_thread_detach(gate_thread_t* threadhandle)
518 {
519 HANDLE* thread = GATE_HANDLESTORE_ACCESS(threadhandle, HANDLE);
520
521 GATE_DEBUG_ASSERT(thread != NULL);
522
523 if (CloseHandle(*thread))
524 {
525 GATE_HANDLESTORE_DESTROY(threadhandle);
526 return GATE_RESULT_OK;
527 }
528 else
529 {
530 GATE_DEBUG_TRACE("CloseHandle() failed");
531 GATE_DEBUG_TRACE_VALUE(gate_win32_getlasterror());
532 return GATE_RESULT_FAILED;
533 }
534 }
535 gate_result_t gate_thread_join(gate_thread_t* threadhandle, gate_result_t* ptr_result)
536 {
537 HANDLE* thread = GATE_HANDLESTORE_ACCESS(threadhandle, HANDLE);
538 DWORD dwResult = 0;
539 DWORD dwExitCode = 0;
540 gate_result_t ret;
541
542 GATE_DEBUG_ASSERT(thread != NULL);
543
544 dwResult = WaitForSingleObject(*thread, INFINITE);
545 if (dwResult != WAIT_OBJECT_0)
546 {
547 GATE_DEBUG_TRACE("WaitForSingleObject() failed");
548 GATE_DEBUG_TRACE_VALUE(dwResult);
549
550 ret = GATE_RESULT_CRITICALERROR;
551 }
552 else
553 {
554 if (GetExitCodeThread(*thread, &dwExitCode))
555 {
556 if (ptr_result != NULL)
557 {
558 *ptr_result = (gate_result_t)dwExitCode;
559 }
560 ret = GATE_RESULT_OK;
561 }
562 else
563 {
564 ret = GATE_RESULT_INVALIDOUTPUT;
565 }
566 if (CloseHandle(*thread))
567 {
568 GATE_HANDLESTORE_DESTROY(threadhandle);
569 }
570 else
571 {
572 GATE_DEBUG_TRACE("CloseHandle() failed");
573 GATE_DEBUG_TRACE_VALUE(gate_win32_getlasterror());
574 ret = GATE_RESULT_FAILED;
575 }
576 }
577
578 return ret;
579 }
580 gate_result_t gate_thread_current(gate_thread_t* threadhandle, gate_thread_id_t* threadid)
581 {
582
583 if (threadhandle)
584 {
585 HANDLE* 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 gate_platform_yield();
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 "gate/platforms.h"
751 #include <pthread.h>
752 #include <unistd.h>
753
754 2 gate_enumint_t gate_thread_model()
755 {
756 2 return GATE_THREAD_MODEL_NATIVE;
757 }
758
759 15 gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function,
760 gate_thread_native_param_type entry_param,
761 gate_thread_t* thread_handle,
762 gate_thread_id_t* thread_id)
763 {
764 int result;
765 pthread_t* handle;
766
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
15 if ((entry_function == NULL) || (thread_handle == NULL))
767 {
768 return GATE_RESULT_INVALIDARG;
769 }
770
771 15 handle = GATE_HANDLESTORE_CREATE(thread_handle, pthread_t);
772
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 if (handle == NULL)
773 {
774 return GATE_RESULT_OUTOFMEMORY;
775 }
776
777 15 result = pthread_create(handle, 0, entry_function, (void*)entry_param);
778
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (0 == result)
779 {
780
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 6 times.
15 if (thread_id != NULL)
781 {
782 9 *thread_id = (gate_thread_id_t)handle;
783 }
784 15 return GATE_RESULT_OK;
785 }
786 else
787 {
788 GATE_HANDLESTORE_DESTROY(thread_handle);
789 return GATE_RESULT_FAILED;
790 }
791 }
792
793 2 gate_result_t gate_thread_detach(gate_thread_t* thread_handle)
794 {
795 2 pthread_t* handle = GATE_HANDLESTORE_ACCESS(thread_handle, pthread_t);
796
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (handle)
797 {
798 2 pthread_detach(*handle);
799 2 GATE_HANDLESTORE_DESTROY(thread_handle);
800 }
801 2 return GATE_RESULT_OK;
802 }
803 13 gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* ptr_result)
804 {
805 13 gate_result_t ret = GATE_RESULT_FAILED;
806 void* threadresult;
807 13 pthread_t* handle = GATE_HANDLESTORE_ACCESS(thread_handle, pthread_t);
808
809
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 if (handle)
810 {
811
1/2
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
13 if (0 == pthread_join(*handle, &threadresult))
812 {
813
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1 times.
13 if (ptr_result != NULL)
814 {
815 12 *ptr_result = (gate_result_t)(gate_intptr_t)threadresult;
816 }
817 13 ret = GATE_RESULT_OK;
818 }
819 else
820 {
821 ret = GATE_RESULT_FAILED;
822 }
823 13 GATE_HANDLESTORE_DESTROY(thread_handle);
824 }
825 13 return ret;
826 }
827 static pthread_t get_real_pthread(gate_thread_t* thread_handle)
828 {
829 pthread_t* handle = GATE_HANDLESTORE_ACCESS(thread_handle, pthread_t);
830 if (*handle == ((pthread_t)-1))
831 {
832 return pthread_self();
833 }
834 return *handle;
835 }
836
837 19 gate_result_t gate_thread_current(gate_thread_t* thread_handle, gate_thread_id_t* threadid)
838 {
839 19 gate_result_t ret = GATE_RESULT_OK;
840
841
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 18 times.
19 if (thread_handle)
842 {
843 1 pthread_t* handle = GATE_HANDLESTORE_CREATE(thread_handle, pthread_t);
844
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (handle != NULL)
845 {
846 1 *handle = (pthread_t)-1;
847 }
848 else
849 {
850 ret = GATE_RESULT_OUTOFMEMORY;
851 }
852 }
853
854
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 if (threadid != NULL)
855 {
856 19 pthread_t th = pthread_self();
857 19 *threadid = (gate_thread_id_t)th;
858 }
859 19 return ret;
860 }
861
862 5 gate_result_t gate_thread_is_current(gate_thread_t* thread_handle, gate_bool_t* is_current)
863 {
864 5 gate_result_t ret = GATE_RESULT_OK;
865 5 pthread_t* handle = GATE_HANDLESTORE_ACCESS(thread_handle, pthread_t);
866 5 pthread_t th = pthread_self();
867 5 *is_current = (pthread_equal(*handle, th) != 0);
868 5 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 229 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 229 times.
229 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 229 seconds = milliseconds / 1000;
900 229 millis = (milliseconds % 1000) * 1000;
901
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 229 times.
229 if (seconds > 0)
902 {
903 sleep(seconds);
904 }
905
2/2
✓ Branch 0 taken 228 times.
✓ Branch 1 taken 1 times.
229 if (millis > 0)
906 {
907 228 usleep(millis);
908 }
909 }
910 229 }
911 20 void gate_thread_yield(void)
912 {
913 20 gate_platform_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 7 gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id)
922 {
923 7 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 7 times.
7 if (NULL == ptr_handle)
927 {
928 return GATE_RESULT_OUTOFMEMORY;
929 }
930
931 7 error = pthread_key_create(ptr_handle, NULL);
932
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (error)
933 {
934 GATE_HANDLESTORE_DESTROY(ptr_store_id);
935 return GATE_RESULT_OUTOFRESOURCES;
936 }
937 7 return GATE_RESULT_OK;
938 }
939
940 33 gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data)
941 {
942 33 pthread_key_t* ptr_handle = GATE_HANDLESTORE_ACCESS(ptr_store_id, pthread_key_t);
943 33 int error = pthread_setspecific(*ptr_handle, data);
944
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (error)
945 {
946 return GATE_RESULT_FAILED;
947 }
948 33 return GATE_RESULT_OK;
949 }
950
951 691937 gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data)
952 {
953 691937 pthread_key_t* ptr_handle = GATE_HANDLESTORE_ACCESS(ptr_store_id, pthread_key_t);
954 691937 void* data = pthread_getspecific(*ptr_handle);
955
1/2
✓ Branch 0 taken 691937 times.
✗ Branch 1 not taken.
691937 if (ptr_data)
956 {
957 691937 *ptr_data = data;
958 }
959 691937 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 #include "gate/platforms.h"
983
984 gate_enumint_t gate_thread_model()
985 {
986 return GATE_THREAD_MODEL_NATIVE;
987 }
988
989 gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function,
990 gate_thread_native_param_type entry_param,
991 gate_thread_t* ptr_thread_handle,
992 gate_thread_id_t* ptr_thread_id)
993 {
994 status_t tstat;
995 thread_id tid;
996
997 tid = spawn_thread((thread_func)entry_function, "thread", B_NORMAL_PRIORITY, entry_param);
998
999 if (tid == B_NO_MEMORY)
1000 {
1001 return GATE_RESULT_OUTOFMEMORY;
1002 }
1003 else if (tid == B_NO_MORE_THREADS)
1004 {
1005 return GATE_RESULT_OUTOFRESOURCES;
1006 }
1007
1008 tstat = resume_thread(tid);
1009 if (B_OK != tstat)
1010 {
1011 kill_thread(tid);
1012 return GATE_RESULT_FAILED;
1013 }
1014
1015
1016 if (ptr_thread_handle)
1017 {
1018 thread_id* ptr_tid = GATE_HANDLESTORE_CREATE(ptr_thread_handle, thread_id);
1019 if (NULL == ptr_tid)
1020 {
1021 kill_thread(tid);
1022 return GATE_RESULT_OUTOFMEMORY;
1023 }
1024 *ptr_tid = tid;
1025 }
1026 if (ptr_thread_id)
1027 {
1028 *ptr_thread_id = (gate_thread_id_t)tid;
1029 }
1030
1031 return GATE_RESULT_OK;
1032 }
1033
1034
1035 gate_result_t gate_thread_detach(gate_thread_t* thread_handle)
1036 {
1037 thread_id* handle = GATE_HANDLESTORE_ACCESS(thread_handle, thread_id);
1038 if (handle)
1039 {
1040 GATE_HANDLESTORE_DESTROY(thread_handle);
1041 }
1042 return GATE_RESULT_OK;
1043 }
1044
1045 gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* result)
1046 {
1047 gate_result_t ret = GATE_RESULT_FAILED;
1048 status_t status;
1049 status_t thread_status;
1050 thread_id* handle = GATE_HANDLESTORE_ACCESS(thread_handle, thread_id);
1051 if (handle)
1052 {
1053 status = wait_for_thread(*handle, &thread_status);
1054 if (B_OK == status)
1055 {
1056 if (result)
1057 {
1058 *result = (gate_result_t)thread_status;
1059 }
1060 GATE_HANDLESTORE_DESTROY(thread_handle);
1061 ret = GATE_RESULT_OK;
1062 }
1063 else if (B_OK == B_INTERRUPTED)
1064 {
1065 if (result)
1066 {
1067 *result = GATE_RESULT_CANCELED;
1068 }
1069 GATE_HANDLESTORE_DESTROY(thread_handle);
1070 ret = GATE_RESULT_OK;
1071 }
1072 else
1073 {
1074 ret = GATE_RESULT_FAILED;
1075 }
1076 }
1077 return ret;
1078 }
1079
1080 gate_result_t gate_thread_current(gate_thread_t* ptr_thread_handle, gate_thread_id_t* ptr_thread_id)
1081 {
1082 thread_id tid = find_thread(NULL);
1083
1084 if (ptr_thread_handle)
1085 {
1086 thread_id* ptr_tid = GATE_HANDLESTORE_CREATE(ptr_thread_handle, thread_id);
1087 if (NULL == ptr_tid)
1088 {
1089 kill_thread(tid);
1090 return GATE_RESULT_OUTOFMEMORY;
1091 }
1092 *ptr_tid = tid;
1093 }
1094 if (ptr_thread_id)
1095 {
1096 *ptr_thread_id = (gate_thread_id_t)tid;
1097 }
1098 return GATE_RESULT_OK;
1099 }
1100
1101 gate_result_t gate_thread_is_current(gate_thread_t* ptr_thread_handle, gate_bool_t* is_current)
1102 {
1103 thread_id cur_tid = find_thread(NULL);
1104 thread_id* ptr_tid = GATE_HANDLESTORE_ACCESS(ptr_thread_handle, thread_id);
1105 if (!ptr_tid)
1106 {
1107 return GATE_RESULT_INVALIDARG;
1108 }
1109 if (is_current)
1110 {
1111 *is_current = *ptr_tid == cur_tid;
1112 }
1113 return GATE_RESULT_OK;
1114 }
1115
1116 gate_bool_t gate_thread_equals(gate_thread_t* thread_handle_1, gate_thread_t* thread_handle_2)
1117 {
1118 thread_id* ptr_tid1 = GATE_HANDLESTORE_ACCESS(thread_handle_1, thread_id);
1119 thread_id* ptr_tid2 = GATE_HANDLESTORE_ACCESS(thread_handle_2, thread_id);
1120 if (ptr_tid1 == ptr_tid2)
1121 {
1122 return true;
1123 }
1124 else if ((ptr_tid1 == NULL) || (ptr_tid2 == NULL))
1125 {
1126 return false;
1127 }
1128 else
1129 {
1130 return *ptr_tid1 == *ptr_tid2;
1131 }
1132 }
1133
1134 void gate_thread_sleep(gate_uint32_t milliseconds)
1135 {
1136 bigtime_t usec = (bigtime_t)milliseconds * 1000;
1137 snooze(usec);
1138 }
1139
1140 void gate_thread_yield(void)
1141 {
1142 gate_platform_yield();
1143 }
1144
1145 gate_bool_t gate_thread_yield_if_preemptive(void)
1146 {
1147 return false;
1148 }
1149
1150 gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id)
1151 {
1152 int32* ptr_ts = GATE_HANDLESTORE_CREATE(ptr_store_id, int32);
1153 if (NULL == ptr_ts)
1154 {
1155 return GATE_RESULT_OUTOFMEMORY;
1156 }
1157 *ptr_ts = tls_allocate();
1158 return GATE_RESULT_OK;
1159 }
1160 gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data)
1161 {
1162 int32* ptr_ts = GATE_HANDLESTORE_ACCESS(ptr_store_id, int32);
1163 if (!ptr_ts)
1164 {
1165 return GATE_RESULT_NOTAVAILABLE;
1166 }
1167 tls_set(*ptr_ts, data);
1168 return GATE_RESULT_OK;
1169 }
1170
1171 gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data)
1172 {
1173 int32* ptr_ts = GATE_HANDLESTORE_ACCESS(ptr_store_id, int32);
1174 void* ptr_ts_data = NULL;
1175 if (!ptr_ts)
1176 {
1177 return GATE_RESULT_NOTAVAILABLE;
1178 }
1179 ptr_ts_data = tls_get(*ptr_ts);
1180 if (ptr_data)
1181 {
1182 *ptr_data = ptr_ts_data;
1183 }
1184 return GATE_RESULT_OK;
1185 }
1186
1187 gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id)
1188 {
1189 int32* ptr_ts = GATE_HANDLESTORE_ACCESS(ptr_store_id, int32);
1190 if (!ptr_ts)
1191 {
1192 return GATE_RESULT_NOTAVAILABLE;
1193 }
1194 GATE_HANDLESTORE_DESTROY(ptr_store_id);
1195 return GATE_RESULT_OK;
1196 }
1197
1198 #endif /* GATE_THREADING_BEOS */
1199
1200
1201
1202 #ifdef GATE_THREADING_COROUTINES
1203
1204 #include "gate/platform/efi/efi_gate.h"
1205 #include "gate/coroutines.h"
1206
1207 gate_enumint_t gate_thread_model()
1208 {
1209 return GATE_THREAD_MODEL_MANUAL;
1210 }
1211
1212
1213 gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function,
1214 gate_thread_native_param_type entry_param,
1215 gate_thread_t* thread_handle, gate_thread_id_t* thread_id)
1216 {
1217 gate_result_t ret;
1218 gate_coroutine_id_t* ptr_co_id;
1219
1220 if ((NULL == entry_function) || (NULL == thread_handle))
1221 {
1222 return GATE_RESULT_INVALIDARG;
1223 }
1224
1225 ptr_co_id = GATE_HANDLESTORE_CREATE(thread_handle, gate_coroutine_id_t);
1226 if (NULL == ptr_co_id)
1227 {
1228 return GATE_RESULT_OUTOFMEMORY;
1229 }
1230
1231 ret = gate_coroutine_create(entry_function, entry_param, ptr_co_id);
1232 if (GATE_FAILED(ret))
1233 {
1234 GATE_HANDLESTORE_DESTROY(thread_handle);
1235 return ret;
1236 }
1237
1238 if (thread_id)
1239 {
1240 *thread_id = (gate_thread_id_t)*ptr_co_id;
1241 }
1242 return ret;
1243 }
1244
1245 gate_result_t gate_thread_detach(gate_thread_t* thread_handle)
1246 {
1247 GATE_HANDLESTORE_DESTROY(thread_handle);
1248 return GATE_RESULT_OK;
1249 }
1250
1251 gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* result)
1252 {
1253 gate_result_t ret = GATE_RESULT_FAILED;
1254 gate_coroutine_id_t* ptr_co_id = GATE_HANDLESTORE_ACCESS(thread_handle, gate_coroutine_id_t);
1255
1256 if (ptr_co_id)
1257 {
1258 ret = gate_coroutine_await(*ptr_co_id, result);
1259 }
1260 else
1261 {
1262 ret = GATE_RESULT_NOTAVAILABLE;
1263 }
1264 return ret;
1265 }
1266
1267 gate_result_t gate_thread_current(gate_thread_t* thread_handle, gate_thread_id_t* thread_id)
1268 {
1269 gate_result_t ret = GATE_RESULT_FAILED;
1270 gate_coroutine_id_t co_id;
1271
1272 ret = gate_coroutine_get_current(&co_id);
1273 if (GATE_SUCCEEDED(ret))
1274 {
1275 if (thread_handle)
1276 {
1277 gate_coroutine_id_t* ptr_co_id = GATE_HANDLESTORE_CREATE(thread_handle, gate_coroutine_id_t);
1278 *ptr_co_id = co_id;
1279 }
1280 if (thread_id)
1281 {
1282 *thread_id = (gate_thread_id_t)co_id;
1283 }
1284 }
1285 return ret;
1286 }
1287
1288 gate_result_t gate_thread_is_current(gate_thread_t* thread_handle, gate_bool_t* is_current)
1289 {
1290 gate_result_t ret = GATE_RESULT_FAILED;
1291 gate_coroutine_id_t co_id;
1292
1293 ret = gate_coroutine_get_current(&co_id);
1294 if (GATE_SUCCEEDED(ret))
1295 {
1296 gate_coroutine_id_t* 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 "gate/platforms.h"
1371 #include <stdlib.h>
1372
1373 gate_enumint_t gate_thread_model()
1374 {
1375 return GATE_THREAD_MODEL_NATIVE;
1376 }
1377
1378
1379 typedef struct
1380 {
1381 gate_thread_native_entry entry_function;
1382 gate_thread_native_param_type entry_param;
1383 } worker_param_t;
1384
1385 static gate_result_t wasm_thread_dispatcher(gate_dataptr_t arg)
1386 {
1387 worker_param_t* ptr_param = (worker_param_t*)arg;
1388 gate_thread_native_entry func = ptr_param->entry_function;
1389 gate_thread_native_param_type func_param = ptr_param->entry_param;
1390 gate_thread_native_return_type func_ret_value = (gate_thread_native_return_type)0;
1391 gate_wasm_worker_id_t worker_id = gate_wasm_worker_id();
1392
1393 if (func)
1394 {
1395 func_ret_value = func(func_param);
1396 }
1397
1398 gate_wasm_worker_completed(worker_id, (gate_result_t)func_ret_value);
1399 return GATE_RESULT_OK;
1400 }
1401
1402 gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function,
1403 gate_thread_native_param_type entry_param,
1404 gate_thread_t* thread_handle,
1405 gate_thread_id_t* thread_id)
1406 {
1407 gate_result_t ret = GATE_RESULT_FAILED;
1408 gate_wasm_worker_id_t worker_id = NULL;
1409 worker_param_t* ptr_worker_param = NULL;
1410
1411 do
1412 {
1413 ptr_worker_param = (worker_param_t*)malloc(sizeof(worker_param_t));
1414 if (ptr_worker_param == NULL)
1415 {
1416 ret = GATE_RESULT_OUTOFMEMORY;
1417 break;
1418 }
1419
1420 ptr_worker_param->entry_function = entry_function;
1421 ptr_worker_param->entry_param = entry_param;
1422
1423 ret = gate_wasm_worker_create(&worker_id);
1424 GATE_BREAK_IF_FAILED(ret);
1425
1426 ret = gate_wasm_worker_post_task(worker_id, &wasm_thread_dispatcher, ptr_worker_param);
1427 GATE_BREAK_IF_FAILED(ret);
1428
1429 /* success case */
1430 ret = GATE_RESULT_OK;
1431
1432 if (thread_handle)
1433 {
1434 gate_wasm_worker_id_t* ptr_handle = GATE_HANDLESTORE_CREATE(thread_handle, gate_wasm_worker_id_t);
1435 *ptr_handle = worker_id;
1436 }
1437
1438 if (thread_id)
1439 {
1440 *thread_id = (gate_thread_id_t)worker_id;
1441 }
1442
1443 worker_id = NULL;
1444 ptr_worker_param = NULL;
1445
1446 } while (0);
1447
1448 if (worker_id)
1449 {
1450 gate_wasm_worker_destroy(worker_id);
1451 }
1452
1453 if (ptr_worker_param)
1454 {
1455 free(ptr_worker_param);
1456 }
1457
1458 return ret;
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 gate_platform_yield();
1529 }
1530
1531 gate_bool_t gate_thread_yield_if_preemptive(void)
1532 {
1533 return false;
1534 }
1535
1536 gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id)
1537 {
1538 void** ptr_tss = GATE_HANDLESTORE_CREATE(ptr_store_id, void*);
1539 if (NULL == ptr_tss)
1540 {
1541 return GATE_RESULT_OUTOFMEMORY;
1542 }
1543 *ptr_tss = NULL;
1544 return GATE_RESULT_OK;
1545 }
1546 gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data)
1547 {
1548 void** ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, void*);
1549 *ptr_tss = data;
1550 return GATE_RESULT_OK;
1551 }
1552
1553 gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data)
1554 {
1555 void** ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, void*);
1556 *ptr_data = *ptr_tss;
1557 return GATE_RESULT_OK;
1558 }
1559
1560 gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id)
1561 {
1562 GATE_HANDLESTORE_DESTROY(ptr_store_id);
1563 return GATE_RESULT_OK;
1564 }
1565
1566 #endif /* GATE_THREADING_WASM */
1567
1568
1569
1570 #if defined(GATE_THREADING_ARDUINO_IMPL)
1571
1572 #include "gate/platform/arduino/arduino_gate.h"
1573 #include "gate/platforms.h"
1574
1575 gate_enumint_t gate_thread_model()
1576 {
1577 return GATE_THREAD_MODEL_NONE;
1578 }
1579
1580 gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function,
1581 gate_thread_native_param_type entry_param,
1582 gate_thread_t* thread_handle,
1583 gate_thread_id_t* thread_id)
1584 {
1585 GATE_UNUSED_ARG(entry_function);
1586 GATE_UNUSED_ARG(entry_param);
1587 GATE_UNUSED_ARG(thread_handle);
1588 GATE_UNUSED_ARG(thread_id);
1589 return GATE_RESULT_NOTSUPPORTED;
1590 }
1591
1592
1593 gate_result_t gate_thread_detach(gate_thread_t* thread_handle)
1594 {
1595 GATE_UNUSED_ARG(thread_handle);
1596 return GATE_RESULT_NOTSUPPORTED;
1597 }
1598
1599 gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* result)
1600 {
1601 GATE_UNUSED_ARG(thread_handle);
1602 GATE_UNUSED_ARG(result);
1603 return GATE_RESULT_NOTSUPPORTED;
1604 }
1605
1606 gate_result_t gate_thread_current(gate_thread_t* thread_handle, gate_thread_id_t* thread_id)
1607 {
1608 GATE_UNUSED_ARG(thread_handle);
1609 GATE_UNUSED_ARG(thread_id);
1610 return GATE_RESULT_NOTSUPPORTED;
1611 }
1612
1613 gate_result_t gate_thread_is_current(gate_thread_t* thread_handle, gate_bool_t* is_current)
1614 {
1615 GATE_UNUSED_ARG(thread_handle);
1616 GATE_UNUSED_ARG(is_current);
1617 return GATE_RESULT_NOTSUPPORTED;
1618 }
1619
1620 gate_bool_t gate_thread_equals(gate_thread_t* thread_handle_1, gate_thread_t* thread_handle_2)
1621 {
1622 GATE_UNUSED_ARG(thread_handle_1);
1623 GATE_UNUSED_ARG(thread_handle_2);
1624 return false;
1625 }
1626
1627 void gate_thread_sleep(gate_uint32_t milliseconds)
1628 {
1629 gate_arduino_sleep(milliseconds);
1630 }
1631
1632 void gate_thread_yield(void)
1633 {
1634 gate_platform_yield();
1635 }
1636
1637 gate_bool_t gate_thread_yield_if_preemptive(void)
1638 {
1639 return false;
1640 }
1641
1642 gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id)
1643 {
1644 void** ptr_tss = GATE_HANDLESTORE_CREATE(ptr_store_id, void*);
1645 if (NULL == ptr_tss)
1646 {
1647 return GATE_RESULT_OUTOFMEMORY;
1648 }
1649 *ptr_tss = NULL;
1650 return GATE_RESULT_OK;
1651 }
1652 gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data)
1653 {
1654 void** ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, void*);
1655 *ptr_tss = data;
1656 return GATE_RESULT_OK;
1657 }
1658
1659 gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data)
1660 {
1661 void** ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, void*);
1662 *ptr_data = *ptr_tss;
1663 return GATE_RESULT_OK;
1664 }
1665
1666 gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id)
1667 {
1668 GATE_HANDLESTORE_DESTROY(ptr_store_id);
1669 return GATE_RESULT_OK;
1670 }
1671
1672 #endif /* GATE_THREADING_ARDUINO_IMPL */
1673
1674
1675
1676 #if defined(GATE_THREADING_NO_IMPL)
1677
1678 gate_enumint_t gate_thread_model()
1679 {
1680 return GATE_THREAD_MODEL_NONE;
1681 }
1682
1683 gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function,
1684 gate_thread_native_param_type entry_param,
1685 gate_thread_t* thread_handle,
1686 gate_thread_id_t* thread_id)
1687 {
1688 GATE_UNUSED_ARG(entry_function);
1689 GATE_UNUSED_ARG(entry_param);
1690 GATE_UNUSED_ARG(thread_handle);
1691 GATE_UNUSED_ARG(thread_id);
1692 return GATE_RESULT_NOTSUPPORTED;
1693 }
1694
1695
1696 gate_result_t gate_thread_detach(gate_thread_t* thread_handle)
1697 {
1698 GATE_UNUSED_ARG(thread_handle);
1699 return GATE_RESULT_NOTSUPPORTED;
1700 }
1701
1702 gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* result)
1703 {
1704 GATE_UNUSED_ARG(thread_handle);
1705 GATE_UNUSED_ARG(result);
1706 return GATE_RESULT_NOTSUPPORTED;
1707 }
1708
1709 gate_result_t gate_thread_current(gate_thread_t* thread_handle, gate_thread_id_t* thread_id)
1710 {
1711 GATE_UNUSED_ARG(thread_handle);
1712 GATE_UNUSED_ARG(thread_id);
1713 return GATE_RESULT_NOTSUPPORTED;
1714 }
1715
1716 gate_result_t gate_thread_is_current(gate_thread_t* thread_handle, gate_bool_t* is_current)
1717 {
1718 GATE_UNUSED_ARG(thread_handle);
1719 GATE_UNUSED_ARG(is_current);
1720 return GATE_RESULT_NOTSUPPORTED;
1721 }
1722
1723 gate_bool_t gate_thread_equals(gate_thread_t* thread_handle_1, gate_thread_t* thread_handle_2)
1724 {
1725 GATE_UNUSED_ARG(thread_handle_1);
1726 GATE_UNUSED_ARG(thread_handle_2);
1727 return false;
1728 }
1729
1730 void gate_thread_sleep(gate_uint32_t milliseconds)
1731 {
1732 GATE_UNUSED_ARG(milliseconds);
1733 }
1734
1735 void gate_thread_yield(void)
1736 {
1737 }
1738
1739 gate_bool_t gate_thread_yield_if_preemptive(void)
1740 {
1741 return false;
1742 }
1743
1744 gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id)
1745 {
1746 void** ptr_tss = GATE_HANDLESTORE_CREATE(ptr_store_id, void*);
1747 if (NULL == ptr_tss)
1748 {
1749 return GATE_RESULT_OUTOFMEMORY;
1750 }
1751 *ptr_tss = NULL;
1752 return GATE_RESULT_OK;
1753 }
1754 gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data)
1755 {
1756 void** ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, void*);
1757 *ptr_tss = data;
1758 return GATE_RESULT_OK;
1759 }
1760
1761 gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data)
1762 {
1763 void** ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, void*);
1764 *ptr_data = *ptr_tss;
1765 return GATE_RESULT_OK;
1766 }
1767
1768 gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id)
1769 {
1770 GATE_HANDLESTORE_DESTROY(ptr_store_id);
1771 return GATE_RESULT_OK;
1772 }
1773
1774
1775 #endif /* GATE_THREADING_NO_IMPL */
1776