hoshi-lang dev
Yet another programming language
Loading...
Searching...
No Matches
threading.cpp
Go to the documentation of this file.
3#include <cstdint>
4#include <errno.h>
5
6#if defined (ELYSIA_RUNTIME_HPERF_ENABLE)
8#endif
9
13
14#ifdef _WIN32 // Windows Implementation
15
16#include <windows.h>
17
18unsigned __stdcall thread_starter_wrapper(void* args) {
19 auto* starter_args = (ThreadStarterArgs*)args;
20 YoiVoidCallableInterface* callable = starter_args->callable;
21
22 callable->callable(callable->this_ptr);
23
24 // Now that the thread's work is done, we can release the callable.
25 if (--callable->gc_refcount == 0) {
26 if (callable->gc_dec_func) {
27 callable->gc_dec_func(callable->this_ptr);
28 }
30 }
31
32 // Free the wrapper args struct
33 free(starter_args);
34
35 return 0;
36}
37
39 auto* starter_args = (ThreadStarterArgs*) malloc(sizeof(ThreadStarterArgs));
40 starter_args->callable = callable;
41
42 uintptr_t thread_handle = _beginthreadex(nullptr, 0, &thread_starter_wrapper, starter_args, 0, nullptr);
43
45 yoi_result->gc_refcount = 1;
46 yoi_result->type_id = 16;
47
48 if (thread_handle == 0) {
49 yoi_result->ok = nullptr;
50 yoi_result->err = (YoiIntegerObject *)runtime_object_alloc(sizeof(YoiIntegerObject));
51 yoi_result->err->gc_refcount = 1;
52 yoi_result->err->type_id = 0;
53 yoi_result->err->value = errno;
54 // We must clean up the args if thread creation failed
55 free(starter_args);
56 } else {
57 yoi_result->err = nullptr;
58 yoi_result->ok = (YoiUnsignedObject *)runtime_object_alloc(sizeof(YoiUnsignedObject));
59 yoi_result->ok->gc_refcount = 1;
60 yoi_result->ok->type_id = 0;
61 yoi_result->ok->value = (unsigned long long)thread_handle;
62 }
63
64 // IMPORTANT: the refcount for 'callable' is NOT decremented here.
65 // its ownership is passed to the new thread via the wrapper.
66 return yoi_result;
67}
68
70 auto win_handle = (YoiThreadHandle)thread_handle_obj->value;
71
72 DWORD result = WaitForSingleObject(win_handle, INFINITE);
73
74 CloseHandle(win_handle);
75
76 auto yoi_result = (YoiIntegerObject *)runtime_object_alloc(sizeof(YoiIntegerObject));
77 yoi_result->gc_refcount = 1;
78 yoi_result->type_id = 0;
79
80 if (result == WAIT_OBJECT_0) {
81 yoi_result->value = 0;
82 } else {
83 yoi_result->value = GetLastError();
84 }
85
86 if (--thread_handle_obj->gc_refcount == 0)
87 runtime_finalize_object((YoiObject *)thread_handle_obj);
88 return yoi_result;
89}
90
91uint64_t runtime_get_thread_id() {
92 return (uint64_t)GetCurrentThreadId();
93}
94
96 auto win_handle = (YoiThreadHandle)thread_handle_obj->value;
97 DWORD exit_code;
98
99 auto yoi_result = (YoiIntegerObject *)runtime_object_alloc(sizeof(YoiIntegerObject));
100 yoi_result->gc_refcount = 1;
101 yoi_result->type_id = 0;
102
103 if (GetExitCodeThread(win_handle, &exit_code)) {
104 if (exit_code == STILL_ACTIVE) {
105 yoi_result->value = 0;
106 } else {
107 yoi_result->value = ESRCH;
108 }
109 } else {
110 yoi_result->value = ESRCH;
111 }
112
113 if (--thread_handle_obj->gc_refcount == 0)
114 runtime_finalize_object((YoiObject *)thread_handle_obj);
115 return yoi_result;
116}
117
118extern "C" uint64_t runtime_thread_hardware_concurrency() {
119 SYSTEM_INFO sysinfo;
120 GetSystemInfo(&sysinfo);
121 return (uint64_t)sysinfo.dwNumberOfProcessors;
122}
123
125 auto* cs = (CRITICAL_SECTION*) malloc(sizeof(CRITICAL_SECTION));
126 if (!cs) {
128 yoi_result_obj->gc_refcount = 1;
129 yoi_result_obj->type_id = 16;
130 yoi_result_obj->ok = nullptr;
131
132 yoi_result_obj->err = (YoiIntegerObject *)runtime_object_alloc(sizeof(YoiIntegerObject));
133 yoi_result_obj->err->gc_refcount = 1;
134 yoi_result_obj->err->type_id = 0;
135 yoi_result_obj->err->value = ENOMEM;
136 return yoi_result_obj;
137 }
138
139 InitializeCriticalSection(cs);
140
141 auto yoi_result = (YoiUnsignedObject *)runtime_object_alloc(sizeof(YoiUnsignedObject));
142 yoi_result->gc_refcount = 1;
143 yoi_result->type_id = 0;
144 yoi_result->value = (unsigned long long)cs;
145
147 yoi_result_obj->gc_refcount = 1;
148 yoi_result_obj->type_id = 16;
149 yoi_result_obj->err = nullptr;
150 yoi_result_obj->ok = yoi_result;
151
152 return yoi_result_obj;
153}
154
156 auto *cs = (CRITICAL_SECTION *)handle->value;
157 DeleteCriticalSection(cs);
158 free(cs);
159
160 if (--handle->gc_refcount == 0)
162}
163
165 EnterCriticalSection((CRITICAL_SECTION *)mutex_handle->value);
166
167 if (--mutex_handle->gc_refcount == 0)
168 runtime_finalize_object((YoiObject *)mutex_handle);
169}
170
172 LeaveCriticalSection((CRITICAL_SECTION *)mutex_handle->value);
173
174 if (--mutex_handle->gc_refcount == 0)
175 runtime_finalize_object((YoiObject *)mutex_handle);
176}
177
179 BOOL res = TryEnterCriticalSection((CRITICAL_SECTION *)mutex_handle->value);
180
181 auto yoi_result = (YoiIntegerObject *)runtime_object_alloc(sizeof(YoiIntegerObject));
182 yoi_result->gc_refcount = 1;
183 yoi_result->type_id = 0;
184 yoi_result->value = res ? 0 : EBUSY;
185
186 if (--mutex_handle->gc_refcount == 0)
187 runtime_finalize_object((YoiObject *)mutex_handle);
188
189 return yoi_result;
190}
191
193 auto* cv = (CONDITION_VARIABLE*) malloc(sizeof(CONDITION_VARIABLE));
194
195 if (!cv) {
197 yoi_result_obj->gc_refcount = 1;
198 yoi_result_obj->type_id = 16;
199 yoi_result_obj->ok = nullptr;
200
201 yoi_result_obj->err = (YoiIntegerObject *)runtime_object_alloc(sizeof(YoiIntegerObject));
202 yoi_result_obj->err->gc_refcount = 1;
203 yoi_result_obj->err->type_id = 0;
204 yoi_result_obj->err->value = ENOMEM;
205 return yoi_result_obj;
206 }
207
208 InitializeConditionVariable(cv);
209
210 auto yoi_cv_handle = (YoiUnsignedObject *)runtime_object_alloc(sizeof(YoiUnsignedObject));
211 yoi_cv_handle->gc_refcount = 1;
212 yoi_cv_handle->type_id = 0;
213 yoi_cv_handle->value = (unsigned long long)cv;
214
216 yoi_result_obj->gc_refcount = 1;
217 yoi_result_obj->type_id = 16;
218 yoi_result_obj->err = nullptr;
219 yoi_result_obj->ok = yoi_cv_handle;
220
221 return yoi_result_obj;
222}
223
225 auto *cv = (CONDITION_VARIABLE *)handle->value;
226 // Windows Condition Variables do not require explicit destruction
227 // functions like DeleteCriticalSection, provided no threads are waiting on them.
228 free(cv);
229
230 if (--handle->gc_refcount == 0)
232}
233
235 WakeConditionVariable((CONDITION_VARIABLE *)condition_handle->value);
236
237 if (--condition_handle->gc_refcount == 0)
238 runtime_finalize_object((YoiObject *)condition_handle);
239}
240
241void runtime_thread_condition_wait(YoiUnsignedObject *condition_handle, YoiUnsignedObject *mutex_handle) {
242 auto *cv = (CONDITION_VARIABLE *)condition_handle->value;
243 auto *cs = (CRITICAL_SECTION *)mutex_handle->value;
244
245 // Atomically releases CS, waits on CV, then re-acquires CS.
246 SleepConditionVariableCS(cv, cs, INFINITE);
247
248 if (--condition_handle->gc_refcount == 0)
249 runtime_finalize_object((YoiObject *)condition_handle);
250
251 if (--mutex_handle->gc_refcount == 0)
252 runtime_finalize_object((YoiObject *)mutex_handle);
253}
254
255#else // POSIX (-nix) Implementation
256
257#include <pthread.h>
258#include <unistd.h>
259
260void* thread_starter_wrapper(void* args) {
261 auto* starter_args = (ThreadStarterArgs*)args;
262 YoiVoidCallableInterface* callable = starter_args->callable;
263
264 #if defined (ELYSIA_RUNTIME_HPERF_ENABLE)
265 if (hperf_enabled) {
267 }
268 #endif
269
270 callable->callable(callable->this_ptr);
271
272 // now that the thread's work is done, we can release the callable.
273 if (--callable->gc_refcount == 0) {
274 if (callable->gc_dec_func) {
275 callable->gc_dec_func(callable->this_ptr);
276 }
278 }
279
280 free(starter_args);
281
282 return nullptr;
283}
284
286 auto* starter_args = (ThreadStarterArgs*) malloc(sizeof(ThreadStarterArgs));
287 starter_args->callable = callable;
288
289 YoiThreadHandle thread_id;
290 int result = pthread_create(&thread_id, nullptr, &thread_starter_wrapper, starter_args);
291
293 yoi_result->gc_refcount = 1;
294 yoi_result->type_id = 16;
295
296 if (result != 0) {
297 yoi_result->ok = nullptr;
298 yoi_result->err = (YoiIntegerObject *)runtime_object_alloc(sizeof(YoiIntegerObject));
299 yoi_result->err->gc_refcount = 1;
300 yoi_result->err->type_id = 0;
301 yoi_result->err->value = result;
302 free(starter_args);
303 } else {
304 yoi_result->err = nullptr;
305 yoi_result->ok = (YoiUnsignedObject *)runtime_object_alloc(sizeof(YoiUnsignedObject));
306 yoi_result->ok->gc_refcount = 1;
307 yoi_result->ok->type_id = 0;
308 yoi_result->ok->value = (unsigned long long)thread_id;
309 }
310
311 // IMPORTANT: the refcount for 'callable' is NOT decremented here.
312 // its ownership is passed to the new thread via the wrapper.
313 return yoi_result;
314}
315
317 auto pthread_id = (YoiThreadHandle)thread_id_obj->value;
318 int result = pthread_join(pthread_id, nullptr);
319
320 auto yoi_result = (YoiIntegerObject *)runtime_object_alloc(sizeof(YoiIntegerObject));
321 yoi_result->gc_refcount = 1;
322 yoi_result->type_id = 0;
323 yoi_result->value = result;
324
325 if (--thread_id_obj->gc_refcount == 0)
326 runtime_finalize_object((YoiObject *)thread_id_obj);
327 return yoi_result;
328}
329
331 return (uint64_t)pthread_self();
332}
333
335 int result = pthread_kill((YoiThreadHandle)thread_id_obj->value, 0);
336 auto yoi_result = (YoiIntegerObject *)runtime_object_alloc(sizeof(YoiIntegerObject));
337 yoi_result->gc_refcount = 1;
338 yoi_result->type_id = 0;
339 yoi_result->value = result;
340
341 if (--thread_id_obj->gc_refcount == 0)
342 runtime_finalize_object((YoiObject *) thread_id_obj);
343 return yoi_result;
344}
345
347 auto mutex = (pthread_mutex_t*) malloc(sizeof(pthread_mutex_t));
348 auto result = pthread_mutex_init(mutex, nullptr);
349
350 if (result == 0) {
351 auto yoi_result = (YoiUnsignedObject *)runtime_object_alloc(sizeof(YoiUnsignedObject));
352 yoi_result->gc_refcount = 1;
353 yoi_result->type_id = 0;
354 yoi_result->value = (unsigned long long)mutex;
355
357 yoi_result_obj->gc_refcount = 1;
358 yoi_result_obj->err = nullptr;
359 yoi_result_obj->ok = yoi_result;
360 return yoi_result_obj;
361 } else {
362 auto yoi_result = (YoiIntegerObject *)runtime_object_alloc(sizeof(YoiIntegerObject));
363 yoi_result->gc_refcount = 1;
364 yoi_result->type_id = 0;
365 yoi_result->value = 0;
366
368 yoi_result_obj->gc_refcount = 1;
369 yoi_result_obj->err = yoi_result;
370 yoi_result_obj->ok = nullptr;
371
372 return yoi_result_obj;
373 }
374
375}
376
378 auto *mutex = (pthread_mutex_t *)handle->value;
379 pthread_mutex_destroy(mutex);
380
381 if (--handle->gc_refcount == 0)
383}
384
386 pthread_mutex_lock((pthread_mutex_t *)mutex_handle->value);
387
388 if (--mutex_handle->gc_refcount == 0)
389 runtime_finalize_object((YoiObject *)mutex_handle);
390}
391
393 pthread_mutex_unlock((pthread_mutex_t *)mutex_handle->value);
394
395 if (--mutex_handle->gc_refcount == 0)
396 runtime_finalize_object((YoiObject *)mutex_handle);
397}
398
400 auto res = pthread_mutex_trylock((pthread_mutex_t *)mutex_handle->value);
401 auto yoi_result = (YoiIntegerObject *)runtime_object_alloc(sizeof(YoiIntegerObject));
402 yoi_result->gc_refcount = 1;
403 yoi_result->type_id = 0;
404 yoi_result->value = res;
405
406 if (--mutex_handle->gc_refcount == 0)
407 runtime_finalize_object((YoiObject *)mutex_handle);
408
409 return yoi_result;
410}
411
413 auto* cv = (pthread_cond_t*) malloc(sizeof(pthread_cond_t));
414 int result = -1;
415
416 if (cv) {
417 result = pthread_cond_init(cv, nullptr);
418 } else {
419 result = ENOMEM;
420 }
421
422 if (result == 0) {
423 auto yoi_cv_handle = (YoiUnsignedObject *)runtime_object_alloc(sizeof(YoiUnsignedObject));
424 yoi_cv_handle->gc_refcount = 1;
425 yoi_cv_handle->type_id = 0;
426 yoi_cv_handle->value = (unsigned long long)cv;
427
429 yoi_result_obj->gc_refcount = 1;
430 yoi_result_obj->type_id = 16;
431 yoi_result_obj->err = nullptr;
432 yoi_result_obj->ok = yoi_cv_handle;
433 return yoi_result_obj;
434 } else {
435 if (cv) free(cv); // Clean up if init failed but malloc succeeded
436
438 yoi_result_obj->gc_refcount = 1;
439 yoi_result_obj->type_id = 16;
440 yoi_result_obj->ok = nullptr;
441
442 yoi_result_obj->err = (YoiIntegerObject *)runtime_object_alloc(sizeof(YoiIntegerObject));
443 yoi_result_obj->err->gc_refcount = 1;
444 yoi_result_obj->err->type_id = 0;
445 yoi_result_obj->err->value = result;
446 return yoi_result_obj;
447 }
448}
449
451 auto *cv = (pthread_cond_t *)handle->value;
452 pthread_cond_destroy(cv);
453 free(cv);
454
455 if (--handle->gc_refcount == 0)
457}
458
460 pthread_cond_signal((pthread_cond_t *)condition_handle->value);
461
462 if (--condition_handle->gc_refcount == 0)
463 runtime_finalize_object((YoiObject *)condition_handle);
464}
465
467 auto *cv = (pthread_cond_t *)condition_handle->value;
468 auto *mutex = (pthread_mutex_t *)mutex_handle->value;
469
470 pthread_cond_wait(cv, mutex);
471
472 if (--condition_handle->gc_refcount == 0)
473 runtime_finalize_object((YoiObject *)condition_handle);
474
475 if (--mutex_handle->gc_refcount == 0)
476 runtime_finalize_object((YoiObject *)mutex_handle);
477}
478
480 return (uint64_t)sysconf(_SC_NPROCESSORS_ONLN);
481}
482
483
484#endif // _WIN32
485
HPerfContext * hperf_context_create(size_t unique_id)
Definition hperf.cpp:16
bool hperf_enabled
Definition hperf.cpp:12
void * runtime_object_alloc(unsigned long size)
Definition memory.cpp:96
void runtime_finalize_object(YoiObject *object)
Definition memory.cpp:90
YoiVoidCallableInterface * callable
Definition threading.cpp:11
unsigned long long gc_refcount
Definition threading.h:33
unsigned long long gc_refcount
Definition memory.h:32
unsigned long long value
Definition memory.h:34
unsigned long long gc_refcount
Definition threading.h:24
void *(* gc_dec_func)(void *this_ptr)
Definition threading.h:28
void *(* callable)(void *this_ptr)
Definition threading.h:29
YoiIntegerObject * runtime_thread_join(YoiUnsignedObject *thread_id_obj)
void runtime_thread_mutex_lock(YoiUnsignedObject *mutex_handle)
void runtime_thread_condition_wait(YoiUnsignedObject *condition_handle, YoiUnsignedObject *mutex_handle)
YoiIntegerObject * runtime_ping_thread(YoiUnsignedObject *thread_id_obj)
void * thread_starter_wrapper(void *args)
YoiResultUnsignedAndIntObject * runtime_start_thread(YoiVoidCallableInterface *callable)
void runtime_thread_mutex_unlock(YoiUnsignedObject *mutex_handle)
YoiResultUnsignedAndIntObject * runtime_thread_new_condition()
void runtime_thread_finalize_mutex_lock(YoiUnsignedObject *handle)
YoiResultUnsignedAndIntObject * runtime_thread_new_mutex_lock()
uint64_t runtime_get_thread_id()
uint64_t runtime_thread_hardware_concurrency()
void runtime_thread_condition_signal(YoiUnsignedObject *condition_handle)
YoiIntegerObject * runtime_thread_mutex_try_lock(YoiUnsignedObject *mutex_handle)
void runtime_thread_finalize_condition(YoiUnsignedObject *handle)
pthread_t YoiThreadHandle
Definition threading.h:19