mirror of
https://github.com/Jous99/F4MP.git
synced 2026-01-13 00:20:54 +01:00
156 lines
4.5 KiB
C
156 lines
4.5 KiB
C
|
|
// file: source/threading/thread.c
|
||
|
|
|
||
|
|
#ifdef ZPL_EDITOR
|
||
|
|
#include <zpl.h>
|
||
|
|
#endif
|
||
|
|
|
||
|
|
ZPL_BEGIN_C_DECLS
|
||
|
|
|
||
|
|
zpl_b32 zpl_thread_is_running(zpl_thread const *t) { return t->is_running != 0; }
|
||
|
|
|
||
|
|
void zpl_thread_init(zpl_thread *t) {
|
||
|
|
zpl_zero_item(t);
|
||
|
|
|
||
|
|
#if defined(ZPL_SYSTEM_WINDOWS)
|
||
|
|
t->win32_handle = INVALID_HANDLE_VALUE;
|
||
|
|
#else
|
||
|
|
t->posix_handle = 0;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
zpl_semaphore_init(&t->semaphore);
|
||
|
|
}
|
||
|
|
|
||
|
|
void zpl_thread_destroy(zpl_thread *t) {
|
||
|
|
if (t->is_running) zpl_thread_join(t);
|
||
|
|
zpl_semaphore_destroy(&t->semaphore);
|
||
|
|
}
|
||
|
|
|
||
|
|
void zpl__thread_run(zpl_thread *t) {
|
||
|
|
zpl_semaphore_release(&t->semaphore);
|
||
|
|
t->return_value = t->proc(t);
|
||
|
|
}
|
||
|
|
|
||
|
|
#if defined(ZPL_SYSTEM_WINDOWS)
|
||
|
|
DWORD __stdcall zpl__thread_proc(void *arg) {
|
||
|
|
zpl_thread *t = cast(zpl_thread *)arg;
|
||
|
|
zpl__thread_run(t);
|
||
|
|
t->is_running = false;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
#else
|
||
|
|
void *zpl__thread_proc(void *arg) {
|
||
|
|
zpl_thread *t = cast(zpl_thread *)arg;
|
||
|
|
zpl__thread_run(t);
|
||
|
|
t->is_running = false;
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
void zpl_thread_start(zpl_thread *t, zpl_thread_proc proc, void *user_data) {
|
||
|
|
zpl_thread_start_with_stack(t, proc, user_data, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
void zpl_thread_start_with_stack(zpl_thread *t, zpl_thread_proc proc, void *user_data, zpl_isize stack_size) {
|
||
|
|
ZPL_ASSERT(!t->is_running);
|
||
|
|
ZPL_ASSERT(proc != NULL);
|
||
|
|
t->proc = proc;
|
||
|
|
t->user_data = user_data;
|
||
|
|
t->stack_size = stack_size;
|
||
|
|
|
||
|
|
#if defined(ZPL_SYSTEM_WINDOWS)
|
||
|
|
t->win32_handle = CreateThread(NULL, stack_size, zpl__thread_proc, t, 0, NULL);
|
||
|
|
ZPL_ASSERT_MSG(t->win32_handle != NULL, "CreateThread: GetLastError");
|
||
|
|
#else
|
||
|
|
{
|
||
|
|
pthread_attr_t attr;
|
||
|
|
pthread_attr_init(&attr);
|
||
|
|
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||
|
|
if (stack_size != 0)
|
||
|
|
pthread_attr_setstacksize(&attr, stack_size);
|
||
|
|
pthread_create(&t->posix_handle, &attr, zpl__thread_proc, t);
|
||
|
|
pthread_attr_destroy(&attr);
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
t->is_running = true;
|
||
|
|
zpl_semaphore_wait(&t->semaphore);
|
||
|
|
}
|
||
|
|
|
||
|
|
void zpl_thread_join(zpl_thread *t) {
|
||
|
|
if (!t->is_running) return;
|
||
|
|
|
||
|
|
#if defined(ZPL_SYSTEM_WINDOWS)
|
||
|
|
WaitForSingleObject(t->win32_handle, INFINITE);
|
||
|
|
CloseHandle(t->win32_handle);
|
||
|
|
t->win32_handle = INVALID_HANDLE_VALUE;
|
||
|
|
#else
|
||
|
|
pthread_join(t->posix_handle, NULL);
|
||
|
|
t->posix_handle = 0;
|
||
|
|
#endif
|
||
|
|
t->is_running = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
zpl_u32 zpl_thread_current_id(void) {
|
||
|
|
zpl_u32 thread_id;
|
||
|
|
#if defined(ZPL_SYSTEM_WINDOWS)
|
||
|
|
#if defined(ZPL_ARCH_32_BIT) && defined(ZPL_CPU_X86)
|
||
|
|
thread_id = (cast(zpl_u32 *)__readfsdword(24))[9];
|
||
|
|
#elif defined(ZPL_ARCH_64_BIT) && defined(ZPL_CPU_X86)
|
||
|
|
thread_id = (cast(zpl_u32 *)__readgsqword(48))[18];
|
||
|
|
#else
|
||
|
|
thread_id = GetCurrentThreadId();
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#elif defined(ZPL_SYSTEM_OSX) && defined(ZPL_ARCH_64_BIT)
|
||
|
|
thread_id = pthread_mach_thread_np(pthread_self());
|
||
|
|
#elif defined(ZPL_ARCH_32_BIT) && defined(ZPL_CPU_X86)
|
||
|
|
__asm__("mov %%gs:0x08,%0" : "=r"(thread_id));
|
||
|
|
#elif defined(ZPL_ARCH_64_BIT) && defined(ZPL_CPU_X86)
|
||
|
|
__asm__("mov %%fs:0x10,%0" : "=r"(thread_id));
|
||
|
|
#else
|
||
|
|
#error Unsupported architecture for zpl_thread_current_id()
|
||
|
|
#endif
|
||
|
|
|
||
|
|
return thread_id;
|
||
|
|
}
|
||
|
|
|
||
|
|
void zpl_thread_set_name(zpl_thread *t, char const *name) {
|
||
|
|
#if defined(ZPL_COMPILER_MSVC)
|
||
|
|
#pragma pack(push, 8)
|
||
|
|
typedef struct {
|
||
|
|
DWORD type;
|
||
|
|
char const *name;
|
||
|
|
DWORD id;
|
||
|
|
DWORD flags;
|
||
|
|
} zplprivThreadName;
|
||
|
|
#pragma pack(pop)
|
||
|
|
|
||
|
|
zplprivThreadName tn;
|
||
|
|
tn.type = 0x1000;
|
||
|
|
tn.name = name;
|
||
|
|
tn.id = GetThreadId(cast(HANDLE)t->win32_handle);
|
||
|
|
tn.flags = 0;
|
||
|
|
|
||
|
|
__try {
|
||
|
|
RaiseException(0x406d1388, 0, zpl_size_of(tn)/4, cast(ULONG_PTR *)&tn);
|
||
|
|
} __except(1 /*EXCEPTION_EXECUTE_HANDLER*/) {
|
||
|
|
}
|
||
|
|
|
||
|
|
#elif defined(ZPL_SYSTEM_WINDOWS) && !defined(ZPL_COMPILER_MSVC)
|
||
|
|
zpl_unused(t);
|
||
|
|
zpl_unused(name);
|
||
|
|
// IMPORTANT TODO: Set thread name for GCC/Clang on windows
|
||
|
|
return;
|
||
|
|
#elif defined(ZPL_SYSTEM_OSX)
|
||
|
|
// TODO: Test if this works
|
||
|
|
pthread_setname_np(name);
|
||
|
|
#else
|
||
|
|
zpl_unused(t);
|
||
|
|
zpl_unused(name);
|
||
|
|
// TODO: Test if this works
|
||
|
|
// pthread_set_name_np(t->posix_handle, name);
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
ZPL_END_C_DECLS
|