GCC Code Coverage Report


Directory: src/gate/
File: src/gate/threading.c
Date: 2026-03-20 22:56:14
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 10 static gate_thread_native_return_type GATE_THREAD_API gate_thread_start_entry_point(gate_thread_native_param_type param)
41 {
42 10 gate_runnable_t* executor = (gate_runnable_t*)(void*)param;
43 10 gate_result_t ret = GATE_RESULT_NULLPOINTER;
44
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 if (executor)
45 {
46 10 ret = gate_runnable_run(executor);
47 10 gate_object_release(executor);
48 }
49 else
50 {
51 ret = GATE_RESULT_NULLPOINTER;
52 }
53 10 return (gate_thread_native_return_type)(gate_intptr_t)ret;
54 }
55
56 10 gate_result_t gate_thread_start(gate_runnable_t* executor, gate_thread_t* thread_handle, gate_thread_id_t* thread_id)
57 {
58 10 gate_result_t ret = GATE_RESULT_FAILED;
59
60 do
61 {
62
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (executor == NULL)
63 {
64 ret = GATE_RESULT_NULLPOINTER;
65 break;
66 }
67
68 10 gate_object_retain(executor);
69 10 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 10 times.
✗ Branch 1 not taken.
10 if (GATE_SUCCEEDED(ret))
73 {
74 10 executor = NULL;
75 }
76 } while (0);
77
78
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (executor != NULL)
79 {
80 gate_object_release(executor);
81 }
82
83 10 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 3 times.
✓ Branch 1 taken 3 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 3 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 Sleep(0);
640 }
641 }
642
643 static gate_bool_t gate_win32_thread_yield(void)
644 {
645 Sleep(0);
646 return true;
647 }
648 static gate_bool_t gate_win32_thread_noyield(void)
649 {
650 return false;
651 }
652
653 static gate_bool_t(*gate_win32_thread_yield_function)(void) = NULL;
654
655 #if defined(GATE_SYS_WINSTORE)
656 #define GetSystemInfo(info) GetNativeSystemInfo(info)
657 #endif
658
659 gate_bool_t gate_thread_yield_if_preemptive(void)
660 {
661 SYSTEM_INFO info = GATE_INIT_EMPTY;
662 if (gate_coroutine_enabled())
663 {
664 gate_coroutine_yield();
665 return true;
666 }
667 else
668 {
669 if (gate_win32_thread_yield_function == NULL)
670 {
671 GetSystemInfo(&info);
672 gate_win32_thread_yield_function = (info.dwNumberOfProcessors > 1) ? &gate_win32_thread_noyield : &gate_win32_thread_yield;
673 }
674 return gate_win32_thread_yield_function();
675 }
676 }
677
678 #ifndef TLS_OUT_OF_INDEXES
679 #define TLS_OUT_OF_INDEXES 0xFFFFFFFF
680 #endif
681
682 gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id)
683 {
684 DWORD* ptr_handle = GATE_HANDLESTORE_CREATE(ptr_store_id, DWORD);
685
686 if (NULL == ptr_handle)
687 {
688 return GATE_RESULT_OUTOFMEMORY;
689 }
690
691 *ptr_handle = TlsAlloc();
692
693 if (TLS_OUT_OF_INDEXES == *ptr_handle)
694 {
695 GATE_HANDLESTORE_DESTROY(ptr_store_id);
696 return GATE_RESULT_OUTOFRESOURCES;
697 }
698 return GATE_RESULT_OK;
699 }
700
701 gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data)
702 {
703 DWORD* ptr_handle = GATE_HANDLESTORE_ACCESS(ptr_store_id, DWORD);
704 if (FALSE == TlsSetValue(*ptr_handle, (LPVOID)data))
705 {
706 return gate_platform_print_last_error(NULL, 0);
707 }
708 return GATE_RESULT_OK;
709 }
710
711 gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data)
712 {
713 DWORD* ptr_handle = GATE_HANDLESTORE_ACCESS(ptr_store_id, DWORD);
714 DWORD last_error;
715 void* data = TlsGetValue(*ptr_handle);
716
717 if (data == NULL)
718 {
719 last_error = gate_win32_getlasterror();
720 if (last_error != ERROR_SUCCESS)
721 {
722 return gate_platform_print_error((gate_int32_t)last_error, NULL, 0);
723 }
724 }
725 if (ptr_data)
726 {
727 *ptr_data = data;
728 }
729 return GATE_RESULT_OK;
730 }
731
732 gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id)
733 {
734 DWORD* ptr_handle = GATE_HANDLESTORE_ACCESS(ptr_store_id, DWORD);
735 if (FALSE == TlsFree(*ptr_handle))
736 {
737 return gate_platform_print_last_error(NULL, 0);
738 }
739 GATE_HANDLESTORE_DESTROY(ptr_store_id);
740 return GATE_RESULT_OK;
741 }
742
743 #endif /* #if defined(GATE_THREADING_WINAPI) */
744
745
746
747 #if defined(GATE_THREADING_PTHREAD)
748
749 #include "gate/handles.h"
750 #include <pthread.h>
751 #include <unistd.h>
752
753 2 gate_enumint_t gate_thread_model()
754 {
755 2 return GATE_THREAD_MODEL_NATIVE;
756 }
757
758 13 gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function,
759 gate_thread_native_param_type entry_param,
760 gate_thread_t* thread_handle,
761 gate_thread_id_t* thread_id)
762 {
763 int result;
764 pthread_t* handle;
765
2/4
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
13 if ((entry_function == NULL) || (thread_handle == NULL))
766 {
767 return GATE_RESULT_INVALIDARG;
768 }
769
770 13 handle = GATE_HANDLESTORE_CREATE(thread_handle, pthread_t);
771
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (handle == NULL)
772 {
773 return GATE_RESULT_OUTOFMEMORY;
774 }
775
776 13 result = pthread_create(handle, 0, entry_function, (void*)entry_param);
777
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 if (0 == result)
778 {
779
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
13 if (thread_id != NULL)
780 {
781 7 *thread_id = (gate_thread_id_t)handle;
782 }
783 13 return GATE_RESULT_OK;
784 }
785 else
786 {
787 GATE_HANDLESTORE_DESTROY(thread_handle);
788 return GATE_RESULT_FAILED;
789 }
790 }
791
792 2 gate_result_t gate_thread_detach(gate_thread_t* thread_handle)
793 {
794 2 pthread_t* handle = GATE_HANDLESTORE_ACCESS(thread_handle, pthread_t);
795
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (handle)
796 {
797 2 pthread_detach(*handle);
798 2 GATE_HANDLESTORE_DESTROY(thread_handle);
799 }
800 2 return GATE_RESULT_OK;
801 }
802 11 gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* ptr_result)
803 {
804 11 gate_result_t ret = GATE_RESULT_FAILED;
805 void* threadresult;
806 11 pthread_t* handle = GATE_HANDLESTORE_ACCESS(thread_handle, pthread_t);
807
808
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (handle)
809 {
810
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 if (0 == pthread_join(*handle, &threadresult))
811 {
812
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 times.
11 if (ptr_result != NULL)
813 {
814 10 *ptr_result = (gate_result_t)(gate_intptr_t)threadresult;
815 }
816 11 ret = GATE_RESULT_OK;
817 }
818 else
819 {
820 ret = GATE_RESULT_FAILED;
821 }
822 11 GATE_HANDLESTORE_DESTROY(thread_handle);
823 }
824 11 return ret;
825 }
826 static pthread_t get_real_pthread(gate_thread_t* thread_handle)
827 {
828 pthread_t* handle = GATE_HANDLESTORE_ACCESS(thread_handle, pthread_t);
829 if (*handle == ((pthread_t)-1))
830 {
831 return pthread_self();
832 }
833 return *handle;
834 }
835
836 19 gate_result_t gate_thread_current(gate_thread_t* thread_handle, gate_thread_id_t* threadid)
837 {
838 19 gate_result_t ret = GATE_RESULT_OK;
839
840
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 18 times.
19 if (thread_handle)
841 {
842 1 pthread_t* handle = GATE_HANDLESTORE_CREATE(thread_handle, pthread_t);
843
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (handle != NULL)
844 {
845 1 *handle = (pthread_t)-1;
846 }
847 else
848 {
849 ret = GATE_RESULT_OUTOFMEMORY;
850 }
851 }
852
853
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
19 if (threadid != NULL)
854 {
855 19 pthread_t th = pthread_self();
856 19 *threadid = (gate_thread_id_t)th;
857 }
858 19 return ret;
859 }
860
861 5 gate_result_t gate_thread_is_current(gate_thread_t* thread_handle, gate_bool_t* is_current)
862 {
863 5 gate_result_t ret = GATE_RESULT_OK;
864 5 pthread_t* handle = GATE_HANDLESTORE_ACCESS(thread_handle, pthread_t);
865 5 pthread_t th = pthread_self();
866 5 *is_current = (pthread_equal(*handle, th) != 0);
867 5 return ret;
868 }
869
870
871 gate_bool_t gate_thread_equals(gate_thread_t* th1, gate_thread_t* th2)
872 {
873 pthread_t pth1 = get_real_pthread(th1);
874 pthread_t pth2 = get_real_pthread(th2);
875 return (pthread_equal(pth1, pth2) == 0) ? false : true;
876 }
877 5 void gate_thread_sleep(gate_uint32_t milliseconds)
878 {
879 gate_uint32_t seconds;
880 gate_uint32_t millis;
881 gate_timecounter_t now, start;
882 gate_int64_t diff;
883 gate_int64_t timeout;
884
885
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if (gate_coroutine_enabled())
886 {
887 gate_timecounter_now(&start);
888 timeout = (gate_int64_t)milliseconds * 1000;
889 do
890 {
891 gate_coroutine_yield();
892 gate_timecounter_now(&now);
893 diff = gate_timecounter_diff(now, start);
894 } while (diff < timeout);
895 }
896 else
897 {
898 5 seconds = milliseconds / 1000;
899 5 millis = (milliseconds % 1000) * 1000;
900
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (seconds > 0)
901 {
902 sleep(seconds);
903 }
904
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (millis > 0)
905 {
906 4 usleep(millis);
907 }
908 }
909 5 }
910 20 void gate_thread_yield(void)
911 {
912 20 sched_yield();
913 20 }
914 1 gate_bool_t gate_thread_yield_if_preemptive(void)
915 {
916 1 sched_yield();
917 1 return true;
918 }
919
920 4 gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id)
921 {
922 4 pthread_key_t* ptr_handle = GATE_HANDLESTORE_CREATE(ptr_store_id, pthread_key_t);
923 int error;
924
925
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (NULL == ptr_handle)
926 {
927 return GATE_RESULT_OUTOFMEMORY;
928 }
929
930 4 error = pthread_key_create(ptr_handle, NULL);
931
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (error)
932 {
933 GATE_HANDLESTORE_DESTROY(ptr_store_id);
934 return GATE_RESULT_OUTOFRESOURCES;
935 }
936 4 return GATE_RESULT_OK;
937 }
938
939 27 gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data)
940 {
941 27 pthread_key_t* ptr_handle = GATE_HANDLESTORE_ACCESS(ptr_store_id, pthread_key_t);
942 27 int error = pthread_setspecific(*ptr_handle, data);
943
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
27 if (error)
944 {
945 return GATE_RESULT_FAILED;
946 }
947 27 return GATE_RESULT_OK;
948 }
949
950 827914 gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data)
951 {
952 827914 pthread_key_t* ptr_handle = GATE_HANDLESTORE_ACCESS(ptr_store_id, pthread_key_t);
953 827914 void* data = pthread_getspecific(*ptr_handle);
954
1/2
✓ Branch 0 taken 827914 times.
✗ Branch 1 not taken.
827914 if (ptr_data)
955 {
956 827914 *ptr_data = data;
957 }
958 827914 return GATE_RESULT_OK;
959 }
960
961 1 gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id)
962 {
963 1 pthread_key_t* ptr_handle = GATE_HANDLESTORE_ACCESS(ptr_store_id, pthread_key_t);
964 1 int error = pthread_key_delete(*ptr_handle);
965
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (error)
966 {
967 return GATE_RESULT_FAILED;
968 }
969 1 GATE_HANDLESTORE_DESTROY(ptr_store_id);
970 1 return GATE_RESULT_OK;
971 }
972
973 #endif /* GATE_THREADING_PTHREAD */
974
975
976
977 #if defined(GATE_THREADING_BEOS)
978
979 #include <kernel/OS.h>
980 #include <support/TLS.h>
981
982 gate_enumint_t gate_thread_model()
983 {
984 return GATE_THREAD_MODEL_NATIVE;
985 }
986
987 gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function,
988 gate_thread_native_param_type entry_param,
989 gate_thread_t* ptr_thread_handle,
990 gate_thread_id_t* ptr_thread_id)
991 {
992 status_t tstat;
993 thread_id tid;
994
995 tid = spawn_thread((thread_func)entry_function, "thread", B_NORMAL_PRIORITY, entry_param);
996
997 if (tid == B_NO_MEMORY)
998 {
999 return GATE_RESULT_OUTOFMEMORY;
1000 }
1001 else if (tid == B_NO_MORE_THREADS)
1002 {
1003 return GATE_RESULT_OUTOFRESOURCES;
1004 }
1005
1006 tstat = resume_thread(tid);
1007 if (B_OK != tstat)
1008 {
1009 kill_thread(tid);
1010 return GATE_RESULT_FAILED;
1011 }
1012
1013
1014 if (ptr_thread_handle)
1015 {
1016 thread_id* ptr_tid = GATE_HANDLESTORE_CREATE(ptr_thread_handle, thread_id);
1017 if (NULL == ptr_tid)
1018 {
1019 kill_thread(tid);
1020 return GATE_RESULT_OUTOFMEMORY;
1021 }
1022 *ptr_tid = tid;
1023 }
1024 if (ptr_thread_id)
1025 {
1026 *ptr_thread_id = (gate_thread_id_t)tid;
1027 }
1028
1029 return GATE_RESULT_OK;
1030 }
1031
1032
1033 gate_result_t gate_thread_detach(gate_thread_t* thread_handle)
1034 {
1035 thread_id* handle = GATE_HANDLESTORE_ACCESS(thread_handle, thread_id);
1036 if (handle)
1037 {
1038 GATE_HANDLESTORE_DESTROY(thread_handle);
1039 }
1040 return GATE_RESULT_OK;
1041 }
1042
1043 gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* result)
1044 {
1045 gate_result_t ret = GATE_RESULT_FAILED;
1046 status_t status;
1047 status_t thread_status;
1048 thread_id* handle = GATE_HANDLESTORE_ACCESS(thread_handle, thread_id);
1049 if (handle)
1050 {
1051 status = wait_for_thread(*handle, &thread_status);
1052 if (B_OK == status)
1053 {
1054 if (result)
1055 {
1056 *result = (gate_result_t)thread_status;
1057 }
1058 GATE_HANDLESTORE_DESTROY(thread_handle);
1059 ret = GATE_RESULT_OK;
1060 }
1061 else if (B_OK == B_INTERRUPTED)
1062 {
1063 if (result)
1064 {
1065 *result = GATE_RESULT_CANCELED;
1066 }
1067 GATE_HANDLESTORE_DESTROY(thread_handle);
1068 ret = GATE_RESULT_OK;
1069 }
1070 else
1071 {
1072 ret = GATE_RESULT_FAILED;
1073 }
1074 }
1075 return ret;
1076 }
1077
1078 gate_result_t gate_thread_current(gate_thread_t* ptr_thread_handle, gate_thread_id_t* ptr_thread_id)
1079 {
1080 thread_id tid = find_thread(NULL);
1081
1082 if (ptr_thread_handle)
1083 {
1084 thread_id* ptr_tid = GATE_HANDLESTORE_CREATE(ptr_thread_handle, thread_id);
1085 if (NULL == ptr_tid)
1086 {
1087 kill_thread(tid);
1088 return GATE_RESULT_OUTOFMEMORY;
1089 }
1090 *ptr_tid = tid;
1091 }
1092 if (ptr_thread_id)
1093 {
1094 *ptr_thread_id = (gate_thread_id_t)tid;
1095 }
1096 return GATE_RESULT_OK;
1097 }
1098
1099 gate_result_t gate_thread_is_current(gate_thread_t* ptr_thread_handle, gate_bool_t* is_current)
1100 {
1101 thread_id cur_tid = find_thread(NULL);
1102 thread_id* ptr_tid = GATE_HANDLESTORE_ACCESS(ptr_thread_handle, thread_id);
1103 if (!ptr_tid)
1104 {
1105 return GATE_RESULT_INVALIDARG;
1106 }
1107 if (is_current)
1108 {
1109 *is_current = *ptr_tid == cur_tid;
1110 }
1111 return GATE_RESULT_OK;
1112 }
1113
1114 gate_bool_t gate_thread_equals(gate_thread_t* thread_handle_1, gate_thread_t* thread_handle_2)
1115 {
1116 thread_id* ptr_tid1 = GATE_HANDLESTORE_ACCESS(thread_handle_1, thread_id);
1117 thread_id* ptr_tid2 = GATE_HANDLESTORE_ACCESS(thread_handle_2, thread_id);
1118 if (ptr_tid1 == ptr_tid2)
1119 {
1120 return true;
1121 }
1122 else if ((ptr_tid1 == NULL) || (ptr_tid2 == NULL))
1123 {
1124 return false;
1125 }
1126 else
1127 {
1128 return *ptr_tid1 == *ptr_tid2;
1129 }
1130 }
1131
1132 void gate_thread_sleep(gate_uint32_t milliseconds)
1133 {
1134 bigtime_t usec = (bigtime_t)milliseconds * 1000;
1135 snooze(usec);
1136 }
1137
1138 void gate_thread_yield(void)
1139 {
1140 }
1141
1142 gate_bool_t gate_thread_yield_if_preemptive(void)
1143 {
1144 return false;
1145 }
1146
1147 gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id)
1148 {
1149 int32* ptr_ts = GATE_HANDLESTORE_CREATE(ptr_store_id, int32);
1150 if (NULL == ptr_ts)
1151 {
1152 return GATE_RESULT_OUTOFMEMORY;
1153 }
1154 *ptr_ts = tls_allocate();
1155 return GATE_RESULT_OK;
1156 }
1157 gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data)
1158 {
1159 int32* ptr_ts = GATE_HANDLESTORE_ACCESS(ptr_store_id, int32);
1160 if (!ptr_ts)
1161 {
1162 return GATE_RESULT_NOTAVAILABLE;
1163 }
1164 tls_set(*ptr_ts, data);
1165 return GATE_RESULT_OK;
1166 }
1167
1168 gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data)
1169 {
1170 int32* ptr_ts = GATE_HANDLESTORE_ACCESS(ptr_store_id, int32);
1171 void* ptr_ts_data = NULL;
1172 if (!ptr_ts)
1173 {
1174 return GATE_RESULT_NOTAVAILABLE;
1175 }
1176 ptr_ts_data = tls_get(*ptr_ts);
1177 if (ptr_data)
1178 {
1179 *ptr_data = ptr_ts_data;
1180 }
1181 return GATE_RESULT_OK;
1182 }
1183
1184 gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id)
1185 {
1186 int32* ptr_ts = GATE_HANDLESTORE_ACCESS(ptr_store_id, int32);
1187 if (!ptr_ts)
1188 {
1189 return GATE_RESULT_NOTAVAILABLE;
1190 }
1191 GATE_HANDLESTORE_DESTROY(ptr_store_id);
1192 return GATE_RESULT_OK;
1193 }
1194
1195 #endif /* GATE_THREADING_BEOS */
1196
1197
1198
1199 #ifdef GATE_THREADING_COROUTINES
1200
1201 #include "gate/platform/efi/efi_gate.h"
1202 #include "gate/coroutines.h"
1203
1204 gate_enumint_t gate_thread_model()
1205 {
1206 return GATE_THREAD_MODEL_MANUAL;
1207 }
1208
1209
1210 gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function,
1211 gate_thread_native_param_type entry_param,
1212 gate_thread_t* thread_handle, gate_thread_id_t* thread_id)
1213 {
1214 gate_result_t ret;
1215 gate_coroutine_id_t* ptr_co_id;
1216
1217 if ((NULL == entry_function) || (NULL == thread_handle))
1218 {
1219 return GATE_RESULT_INVALIDARG;
1220 }
1221
1222 ptr_co_id = GATE_HANDLESTORE_CREATE(thread_handle, gate_coroutine_id_t);
1223 if (NULL == ptr_co_id)
1224 {
1225 return GATE_RESULT_OUTOFMEMORY;
1226 }
1227
1228 ret = gate_coroutine_create(entry_function, entry_param, ptr_co_id);
1229 if (GATE_FAILED(ret))
1230 {
1231 GATE_HANDLESTORE_DESTROY(thread_handle);
1232 return ret;
1233 }
1234
1235 if (thread_id)
1236 {
1237 *thread_id = (gate_thread_id_t)*ptr_co_id;
1238 }
1239 return ret;
1240 }
1241
1242 gate_result_t gate_thread_detach(gate_thread_t* thread_handle)
1243 {
1244 GATE_HANDLESTORE_DESTROY(thread_handle);
1245 return GATE_RESULT_OK;
1246 }
1247
1248 gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* result)
1249 {
1250 gate_result_t ret = GATE_RESULT_FAILED;
1251 gate_coroutine_id_t* ptr_co_id = GATE_HANDLESTORE_ACCESS(thread_handle, gate_coroutine_id_t);
1252
1253 if (ptr_co_id)
1254 {
1255 ret = gate_coroutine_await(*ptr_co_id, result);
1256 }
1257 else
1258 {
1259 ret = GATE_RESULT_NOTAVAILABLE;
1260 }
1261 return ret;
1262 }
1263
1264 gate_result_t gate_thread_current(gate_thread_t* thread_handle, gate_thread_id_t* thread_id)
1265 {
1266 gate_result_t ret = GATE_RESULT_FAILED;
1267 gate_coroutine_id_t co_id;
1268
1269 ret = gate_coroutine_get_current(&co_id);
1270 if (GATE_SUCCEEDED(ret))
1271 {
1272 if (thread_handle)
1273 {
1274 gate_coroutine_id_t* ptr_co_id = GATE_HANDLESTORE_CREATE(thread_handle, gate_coroutine_id_t);
1275 *ptr_co_id = co_id;
1276 }
1277 if (thread_id)
1278 {
1279 *thread_id = (gate_thread_id_t)co_id;
1280 }
1281 }
1282 return ret;
1283 }
1284
1285 gate_result_t gate_thread_is_current(gate_thread_t* thread_handle, gate_bool_t* is_current)
1286 {
1287 gate_result_t ret = GATE_RESULT_FAILED;
1288 gate_coroutine_id_t co_id;
1289
1290 ret = gate_coroutine_get_current(&co_id);
1291 if (GATE_SUCCEEDED(ret))
1292 {
1293 gate_coroutine_id_t* ptr_co_id = GATE_HANDLESTORE_ACCESS(thread_handle, gate_coroutine_id_t);
1294 if (ptr_co_id)
1295 {
1296 if (is_current)
1297 {
1298 *is_current = *ptr_co_id == co_id;
1299 }
1300 }
1301 }
1302 return ret;
1303 }
1304
1305 gate_bool_t gate_thread_equals(gate_thread_t* thread_handle_1, gate_thread_t* thread_handle_2)
1306 {
1307 gate_coroutine_id_t* ptr_co_id1 = GATE_HANDLESTORE_ACCESS(thread_handle_1, gate_coroutine_id_t);
1308 gate_coroutine_id_t* ptr_co_id2 = GATE_HANDLESTORE_ACCESS(thread_handle_2, gate_coroutine_id_t);
1309
1310 if (ptr_co_id1 && ptr_co_id2)
1311 {
1312 return *ptr_co_id1 == *ptr_co_id2;
1313 }
1314 return false;
1315 }
1316
1317 void gate_thread_sleep(gate_uint32_t milliseconds)
1318 {
1319 gate_coroutine_sleep(milliseconds);
1320 //gate_platform_efi_wait(milliseconds);
1321 }
1322
1323 void gate_thread_yield(void)
1324 {
1325 gate_coroutine_yield();
1326 }
1327
1328 gate_bool_t gate_thread_yield_if_preemptive(void)
1329 {
1330 gate_coroutine_yield();
1331 return true;
1332 }
1333
1334 gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id)
1335 {
1336 GATE_UNUSED_ARG(ptr_store_id);
1337 return GATE_RESULT_NOTSUPPORTED;
1338 }
1339
1340 gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data)
1341 {
1342 GATE_UNUSED_ARG(ptr_store_id);
1343 GATE_UNUSED_ARG(data);
1344 return GATE_RESULT_NOTSUPPORTED;
1345 }
1346
1347 gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data)
1348 {
1349 GATE_UNUSED_ARG(ptr_store_id);
1350 GATE_UNUSED_ARG(ptr_data);
1351 return GATE_RESULT_NOTSUPPORTED;
1352 }
1353
1354 gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id)
1355 {
1356 GATE_UNUSED_ARG(ptr_store_id);
1357 return GATE_RESULT_NOTSUPPORTED;
1358 }
1359
1360 #endif /* GATE_THREADING_COROUTINES */
1361
1362
1363
1364 #if defined(GATE_THREADING_WASM)
1365
1366 #include "gate/platform/wasm/wasm_gate.h"
1367 #include <stdlib.h>
1368
1369 gate_enumint_t gate_thread_model()
1370 {
1371 return GATE_THREAD_MODEL_NATIVE;
1372 }
1373
1374
1375 typedef struct
1376 {
1377 gate_thread_native_entry entry_function;
1378 gate_thread_native_param_type entry_param;
1379 } worker_param_t;
1380
1381 static gate_result_t wasm_thread_dispatcher(gate_dataptr_t arg)
1382 {
1383 worker_param_t* ptr_param = (worker_param_t*)arg;
1384 gate_thread_native_entry func = ptr_param->entry_function;
1385 gate_thread_native_param_type func_param = ptr_param->entry_param;
1386 gate_thread_native_return_type func_ret_value = (gate_thread_native_return_type)0;
1387 gate_wasm_worker_id_t worker_id = gate_wasm_worker_id();
1388
1389 if (func)
1390 {
1391 func_ret_value = func(func_param);
1392 }
1393
1394 gate_wasm_worker_completed(worker_id, (gate_result_t)func_ret_value);
1395 return GATE_RESULT_OK;
1396 }
1397
1398 gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function,
1399 gate_thread_native_param_type entry_param,
1400 gate_thread_t* thread_handle,
1401 gate_thread_id_t* thread_id)
1402 {
1403 gate_result_t ret = GATE_RESULT_FAILED;
1404 gate_wasm_worker_id_t worker_id = NULL;
1405 worker_param_t* ptr_worker_param = NULL;
1406
1407 do
1408 {
1409 ptr_worker_param = (worker_param_t*)malloc(sizeof(worker_param_t));
1410 if (ptr_worker_param == NULL)
1411 {
1412 ret = GATE_RESULT_OUTOFMEMORY;
1413 break;
1414 }
1415
1416 ptr_worker_param->entry_function = entry_function;
1417 ptr_worker_param->entry_param = entry_param;
1418
1419 ret = gate_wasm_worker_create(&worker_id);
1420 GATE_BREAK_IF_FAILED(ret);
1421
1422 ret = gate_wasm_worker_post_task(worker_id, &wasm_thread_dispatcher, ptr_worker_param);
1423 GATE_BREAK_IF_FAILED(ret);
1424
1425 /* success case */
1426 ret = GATE_RESULT_OK;
1427
1428 if (thread_handle)
1429 {
1430 gate_wasm_worker_id_t* ptr_handle = GATE_HANDLESTORE_CREATE(thread_handle, gate_wasm_worker_id_t);
1431 *ptr_handle = worker_id;
1432 }
1433
1434 if (thread_id)
1435 {
1436 *thread_id = (gate_thread_id_t)worker_id;
1437 }
1438
1439 worker_id = NULL;
1440 ptr_worker_param = NULL;
1441
1442 } while (0);
1443
1444 if (worker_id)
1445 {
1446 gate_wasm_worker_destroy(worker_id);
1447 }
1448
1449 if (ptr_worker_param)
1450 {
1451 free(ptr_worker_param);
1452 }
1453
1454 return ret;
1455 }
1456
1457
1458 gate_result_t gate_thread_detach(gate_thread_t* thread_handle)
1459 {
1460 GATE_HANDLESTORE_DESTROY(thread_handle);
1461 return GATE_RESULT_OK;
1462 }
1463
1464 gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* result)
1465 {
1466 gate_result_t ret = GATE_RESULT_INVALIDARG;
1467 gate_wasm_worker_id_t* ptr_handle = GATE_HANDLESTORE_ACCESS(thread_handle, gate_wasm_worker_id_t);
1468
1469 if (ptr_handle && *ptr_handle)
1470 {
1471 ret = gate_wasm_worker_join(*ptr_handle, result);
1472 }
1473 return ret;
1474 }
1475
1476 gate_result_t gate_thread_current(gate_thread_t* thread_handle, gate_thread_id_t* thread_id)
1477 {
1478 gate_wasm_worker_id_t worker_id = gate_wasm_worker_id();
1479 if (thread_handle)
1480 {
1481 gate_wasm_worker_id_t* ptr_handle = GATE_HANDLESTORE_CREATE(thread_handle, gate_wasm_worker_id_t);
1482 *ptr_handle = worker_id;
1483 }
1484
1485 if (thread_id)
1486 {
1487 *thread_id = (gate_thread_id_t)worker_id;
1488 }
1489 return GATE_RESULT_OK;
1490 }
1491
1492 gate_result_t gate_thread_is_current(gate_thread_t* thread_handle, gate_bool_t* is_current)
1493 {
1494 gate_wasm_worker_id_t worker_id = gate_wasm_worker_id();
1495 gate_wasm_worker_id_t* ptr_handle = GATE_HANDLESTORE_ACCESS(thread_handle, gate_wasm_worker_id_t);
1496 if (ptr_handle)
1497 {
1498 if (is_current)
1499 {
1500 *is_current = *ptr_handle == worker_id;
1501 }
1502 return GATE_RESULT_OK;
1503 }
1504 return GATE_RESULT_INVALIDARG;
1505 }
1506
1507 gate_bool_t gate_thread_equals(gate_thread_t* thread_handle_1, gate_thread_t* thread_handle_2)
1508 {
1509 gate_wasm_worker_id_t* ptr_handle_1 = GATE_HANDLESTORE_ACCESS(thread_handle_1, gate_wasm_worker_id_t);
1510 gate_wasm_worker_id_t* ptr_handle_2 = GATE_HANDLESTORE_ACCESS(thread_handle_2, gate_wasm_worker_id_t);
1511 if (!ptr_handle_1 || !ptr_handle_2)
1512 {
1513 return false;
1514 }
1515 return *ptr_handle_1 == ptr_handle_2;
1516 }
1517
1518 void gate_thread_sleep(gate_uint32_t milliseconds)
1519 {
1520 gate_wasm_thread_sleep(milliseconds);
1521 }
1522
1523 void gate_thread_yield(void)
1524 {
1525 }
1526
1527 gate_bool_t gate_thread_yield_if_preemptive(void)
1528 {
1529 return false;
1530 }
1531
1532 gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id)
1533 {
1534 void** ptr_tss = GATE_HANDLESTORE_CREATE(ptr_store_id, void*);
1535 if (NULL == ptr_tss)
1536 {
1537 return GATE_RESULT_OUTOFMEMORY;
1538 }
1539 *ptr_tss = NULL;
1540 return GATE_RESULT_OK;
1541 }
1542 gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data)
1543 {
1544 void** ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, void*);
1545 *ptr_tss = data;
1546 return GATE_RESULT_OK;
1547 }
1548
1549 gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data)
1550 {
1551 void** ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, void*);
1552 *ptr_data = *ptr_tss;
1553 return GATE_RESULT_OK;
1554 }
1555
1556 gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id)
1557 {
1558 GATE_HANDLESTORE_DESTROY(ptr_store_id);
1559 return GATE_RESULT_OK;
1560 }
1561
1562 #endif /* GATE_THREADING_WASM */
1563
1564
1565
1566 #if defined(GATE_THREADING_ARDUINO_IMPL)
1567
1568 #include "gate/platform/arduino/arduino_gate.h"
1569
1570 gate_enumint_t gate_thread_model()
1571 {
1572 return GATE_THREAD_MODEL_NONE;
1573 }
1574
1575 gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function,
1576 gate_thread_native_param_type entry_param,
1577 gate_thread_t* thread_handle,
1578 gate_thread_id_t* thread_id)
1579 {
1580 GATE_UNUSED_ARG(entry_function);
1581 GATE_UNUSED_ARG(entry_param);
1582 GATE_UNUSED_ARG(thread_handle);
1583 GATE_UNUSED_ARG(thread_id);
1584 return GATE_RESULT_NOTSUPPORTED;
1585 }
1586
1587
1588 gate_result_t gate_thread_detach(gate_thread_t* thread_handle)
1589 {
1590 GATE_UNUSED_ARG(thread_handle);
1591 return GATE_RESULT_NOTSUPPORTED;
1592 }
1593
1594 gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* result)
1595 {
1596 GATE_UNUSED_ARG(thread_handle);
1597 GATE_UNUSED_ARG(result);
1598 return GATE_RESULT_NOTSUPPORTED;
1599 }
1600
1601 gate_result_t gate_thread_current(gate_thread_t* thread_handle, gate_thread_id_t* thread_id)
1602 {
1603 GATE_UNUSED_ARG(thread_handle);
1604 GATE_UNUSED_ARG(thread_id);
1605 return GATE_RESULT_NOTSUPPORTED;
1606 }
1607
1608 gate_result_t gate_thread_is_current(gate_thread_t* thread_handle, gate_bool_t* is_current)
1609 {
1610 GATE_UNUSED_ARG(thread_handle);
1611 GATE_UNUSED_ARG(is_current);
1612 return GATE_RESULT_NOTSUPPORTED;
1613 }
1614
1615 gate_bool_t gate_thread_equals(gate_thread_t* thread_handle_1, gate_thread_t* thread_handle_2)
1616 {
1617 GATE_UNUSED_ARG(thread_handle_1);
1618 GATE_UNUSED_ARG(thread_handle_2);
1619 return false;
1620 }
1621
1622 void gate_thread_sleep(gate_uint32_t milliseconds)
1623 {
1624 gate_arduino_sleep(milliseconds);
1625 }
1626
1627 void gate_thread_yield(void)
1628 {
1629 }
1630
1631 gate_bool_t gate_thread_yield_if_preemptive(void)
1632 {
1633 return false;
1634 }
1635
1636 gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id)
1637 {
1638 void** ptr_tss = GATE_HANDLESTORE_CREATE(ptr_store_id, void*);
1639 if (NULL == ptr_tss)
1640 {
1641 return GATE_RESULT_OUTOFMEMORY;
1642 }
1643 *ptr_tss = NULL;
1644 return GATE_RESULT_OK;
1645 }
1646 gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data)
1647 {
1648 void** ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, void*);
1649 *ptr_tss = data;
1650 return GATE_RESULT_OK;
1651 }
1652
1653 gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data)
1654 {
1655 void** ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, void*);
1656 *ptr_data = *ptr_tss;
1657 return GATE_RESULT_OK;
1658 }
1659
1660 gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id)
1661 {
1662 GATE_HANDLESTORE_DESTROY(ptr_store_id);
1663 return GATE_RESULT_OK;
1664 }
1665
1666 #endif /* GATE_THREADING_ARDUINO_IMPL */
1667
1668
1669
1670 #if defined(GATE_THREADING_NO_IMPL)
1671
1672 gate_enumint_t gate_thread_model()
1673 {
1674 return GATE_THREAD_MODEL_NONE;
1675 }
1676
1677 gate_result_t gate_thread_start_native(gate_thread_native_entry entry_function,
1678 gate_thread_native_param_type entry_param,
1679 gate_thread_t* thread_handle,
1680 gate_thread_id_t* thread_id)
1681 {
1682 GATE_UNUSED_ARG(entry_function);
1683 GATE_UNUSED_ARG(entry_param);
1684 GATE_UNUSED_ARG(thread_handle);
1685 GATE_UNUSED_ARG(thread_id);
1686 return GATE_RESULT_NOTSUPPORTED;
1687 }
1688
1689
1690 gate_result_t gate_thread_detach(gate_thread_t* thread_handle)
1691 {
1692 GATE_UNUSED_ARG(thread_handle);
1693 return GATE_RESULT_NOTSUPPORTED;
1694 }
1695
1696 gate_result_t gate_thread_join(gate_thread_t* thread_handle, gate_result_t* result)
1697 {
1698 GATE_UNUSED_ARG(thread_handle);
1699 GATE_UNUSED_ARG(result);
1700 return GATE_RESULT_NOTSUPPORTED;
1701 }
1702
1703 gate_result_t gate_thread_current(gate_thread_t* thread_handle, gate_thread_id_t* thread_id)
1704 {
1705 GATE_UNUSED_ARG(thread_handle);
1706 GATE_UNUSED_ARG(thread_id);
1707 return GATE_RESULT_NOTSUPPORTED;
1708 }
1709
1710 gate_result_t gate_thread_is_current(gate_thread_t* thread_handle, gate_bool_t* is_current)
1711 {
1712 GATE_UNUSED_ARG(thread_handle);
1713 GATE_UNUSED_ARG(is_current);
1714 return GATE_RESULT_NOTSUPPORTED;
1715 }
1716
1717 gate_bool_t gate_thread_equals(gate_thread_t* thread_handle_1, gate_thread_t* thread_handle_2)
1718 {
1719 GATE_UNUSED_ARG(thread_handle_1);
1720 GATE_UNUSED_ARG(thread_handle_2);
1721 return false;
1722 }
1723
1724 void gate_thread_sleep(gate_uint32_t milliseconds)
1725 {
1726 GATE_UNUSED_ARG(milliseconds);
1727 }
1728
1729 void gate_thread_yield(void)
1730 {
1731 }
1732
1733 gate_bool_t gate_thread_yield_if_preemptive(void)
1734 {
1735 return false;
1736 }
1737
1738 gate_result_t gate_thread_storage_alloc(gate_thread_storage_t* ptr_store_id)
1739 {
1740 void** ptr_tss = GATE_HANDLESTORE_CREATE(ptr_store_id, void*);
1741 if (NULL == ptr_tss)
1742 {
1743 return GATE_RESULT_OUTOFMEMORY;
1744 }
1745 *ptr_tss = NULL;
1746 return GATE_RESULT_OK;
1747 }
1748 gate_result_t gate_thread_storage_set(gate_thread_storage_t* ptr_store_id, void* data)
1749 {
1750 void** ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, void*);
1751 *ptr_tss = data;
1752 return GATE_RESULT_OK;
1753 }
1754
1755 gate_result_t gate_thread_storage_get(gate_thread_storage_t* ptr_store_id, void** ptr_data)
1756 {
1757 void** ptr_tss = GATE_HANDLESTORE_ACCESS(ptr_store_id, void*);
1758 *ptr_data = *ptr_tss;
1759 return GATE_RESULT_OK;
1760 }
1761
1762 gate_result_t gate_thread_storage_dealloc(gate_thread_storage_t* ptr_store_id)
1763 {
1764 GATE_HANDLESTORE_DESTROY(ptr_store_id);
1765 return GATE_RESULT_OK;
1766 }
1767
1768
1769 #endif /* GATE_THREADING_NO_IMPL */
1770