F4MP/f4mp_originalcode/thirdparty/zpl/code/source/threading/thread.c

156 lines
4.5 KiB
C
Raw Normal View History

// 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