Migrate and remove more from gb.h

This commit is contained in:
gingerBill
2021-08-19 15:38:21 +01:00
parent 5c4d95d539
commit df372dbd5b
8 changed files with 388 additions and 1218 deletions

View File

@@ -4129,7 +4129,7 @@ struct ThreadProcCheckerSection {
};
void check_with_workers(Checker *c, gbThreadProc *proc, isize total_count) {
void check_with_workers(Checker *c, ThreadProc *proc, isize total_count) {
isize thread_count = gb_max(build_context.thread_count, 1);
isize worker_count = thread_count-1; // NOTE(bill): The main thread will also be used for work
if (!build_context.threaded_checker) {
@@ -4143,7 +4143,7 @@ void check_with_workers(Checker *c, gbThreadProc *proc, isize total_count) {
section_all.checker = c;
section_all.offset = 0;
section_all.count = total_count;
gbThread dummy_main_thread = {};
Thread dummy_main_thread = {};
dummy_main_thread.user_data = &section_all;
proc(&dummy_main_thread);
return;
@@ -4162,27 +4162,27 @@ void check_with_workers(Checker *c, gbThreadProc *proc, isize total_count) {
}
GB_ASSERT(remaining_count <= 0);
gbThread *threads = gb_alloc_array(permanent_allocator(), gbThread, worker_count);
Thread *threads = gb_alloc_array(permanent_allocator(), Thread, worker_count);
for (isize i = 0; i < worker_count; i++) {
gb_thread_init(threads+i);
thread_init(threads+i);
}
for (isize i = 0; i < worker_count; i++) {
gb_thread_start(threads+i, proc, thread_data+i);
thread_start(threads+i, proc, thread_data+i);
}
gbThread dummy_main_thread = {};
Thread dummy_main_thread = {};
dummy_main_thread.user_data = thread_data+worker_count;
proc(&dummy_main_thread);
semaphore_wait(&c->info.collect_semaphore);
for (isize i = 0; i < worker_count; i++) {
gb_thread_destroy(threads+i);
thread_destroy(threads+i);
}
}
GB_THREAD_PROC(thread_proc_collect_entities) {
THREAD_PROC(thread_proc_collect_entities) {
auto *data = cast(ThreadProcCheckerSection *)thread->user_data;
Checker *c = data->checker;
CheckerContext collect_entity_ctx = make_checker_context(c);
@@ -4231,7 +4231,7 @@ void check_export_entities_in_pkg(CheckerContext *ctx, AstPackage *pkg, UntypedE
}
}
GB_THREAD_PROC(thread_proc_check_export_entities) {
THREAD_PROC(thread_proc_check_export_entities) {
auto data = cast(ThreadProcCheckerSection *)thread->user_data;
Checker *c = data->checker;
@@ -4720,7 +4720,7 @@ struct ThreadProcBodyData {
ThreadProcBodyData *all_data;
};
GB_THREAD_PROC(thread_proc_body) {
THREAD_PROC(thread_proc_body) {
ThreadProcBodyData *data = cast(ThreadProcBodyData *)thread->user_data;
Checker *c = data->checker;
GB_ASSERT(c != nullptr);
@@ -4797,22 +4797,22 @@ void check_procedure_bodies(Checker *c) {
semaphore_post(&c->procs_to_check_semaphore, cast(i32)thread_count);
gbThread *threads = gb_alloc_array(permanent_allocator(), gbThread, worker_count);
Thread *threads = gb_alloc_array(permanent_allocator(), Thread, worker_count);
for (isize i = 0; i < worker_count; i++) {
gb_thread_init(threads+i);
thread_init(threads+i);
}
for (isize i = 0; i < worker_count; i++) {
gb_thread_start(threads+i, thread_proc_body, thread_data+i);
thread_start(threads+i, thread_proc_body, thread_data+i);
}
gbThread dummy_main_thread = {};
Thread dummy_main_thread = {};
dummy_main_thread.user_data = thread_data+worker_count;
thread_proc_body(&dummy_main_thread);
semaphore_wait(&c->procs_to_check_semaphore);
for (isize i = 0; i < worker_count; i++) {
gb_thread_destroy(threads+i);
thread_destroy(threads+i);
}
isize global_remaining = c->procs_to_check_queue.count.load(std::memory_order_relaxed);

View File

@@ -29,135 +29,9 @@
#include <string.h>
#include <atomic> // Because I wanted the C++11 memory order semantics, of which gb.h does not offer (because it was a C89 library)
gbAllocator heap_allocator(void);
#if defined(GB_SYSTEM_WINDOWS)
struct BlockingMutex {
SRWLOCK srwlock;
};
void mutex_init(BlockingMutex *m) {
}
void mutex_destroy(BlockingMutex *m) {
}
void mutex_lock(BlockingMutex *m) {
AcquireSRWLockExclusive(&m->srwlock);
}
bool mutex_try_lock(BlockingMutex *m) {
return !!TryAcquireSRWLockExclusive(&m->srwlock);
}
void mutex_unlock(BlockingMutex *m) {
ReleaseSRWLockExclusive(&m->srwlock);
}
struct RecursiveMutex {
CRITICAL_SECTION win32_critical_section;
};
void mutex_init(RecursiveMutex *m) {
InitializeCriticalSection(&m->win32_critical_section);
}
void mutex_destroy(RecursiveMutex *m) {
DeleteCriticalSection(&m->win32_critical_section);
}
void mutex_lock(RecursiveMutex *m) {
EnterCriticalSection(&m->win32_critical_section);
}
bool mutex_try_lock(RecursiveMutex *m) {
return TryEnterCriticalSection(&m->win32_critical_section) != 0;
}
void mutex_unlock(RecursiveMutex *m) {
LeaveCriticalSection(&m->win32_critical_section);
}
struct Semaphore {
void *win32_handle;
};
gb_inline void semaphore_init(Semaphore *s) {
s->win32_handle = CreateSemaphoreA(NULL, 0, I32_MAX, NULL);
}
gb_inline void semaphore_destroy(Semaphore *s) {
CloseHandle(s->win32_handle);
}
gb_inline void semaphore_post(Semaphore *s, i32 count) {
ReleaseSemaphore(s->win32_handle, count, NULL);
}
gb_inline void semaphore_wait(Semaphore *s) {
WaitForSingleObjectEx(s->win32_handle, INFINITE, FALSE);
}
gb_inline void semaphore_release(Semaphore *s) {
semaphore_post(s, 1);
}
#else
struct BlockingMutex {
pthread_mutex_t pthread_mutex;
};
void mutex_init(BlockingMutex *m) {
pthread_mutex_init(&m->pthread_mutex, nullptr);
}
void mutex_destroy(BlockingMutex *m) {
pthread_mutex_destroy(&m->pthread_mutex);
}
void mutex_lock(BlockingMutex *m) {
pthread_mutex_lock(&m->pthread_mutex);
}
bool mutex_try_lock(BlockingMutex *m) {
return pthread_mutex_trylock(&m->pthread_mutex) == 0;
}
void mutex_unlock(BlockingMutex *m) {
pthread_mutex_unlock(&m->pthread_mutex);
}
struct RecursiveMutex {
pthread_mutex_t pthread_mutex;
pthread_mutexattr_t pthread_mutexattr;
};
void mutex_init(RecursiveMutex *m) {
pthread_mutexattr_init(&m->pthread_mutexattr);
pthread_mutexattr_settype(&m->pthread_mutexattr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&m->pthread_mutex, &m->pthread_mutexattr);
}
void mutex_destroy(RecursiveMutex *m) {
pthread_mutex_destroy(&m->pthread_mutex);
}
void mutex_lock(RecursiveMutex *m) {
pthread_mutex_lock(&m->pthread_mutex);
}
bool mutex_try_lock(RecursiveMutex *m) {
return pthread_mutex_trylock(&m->pthread_mutex) == 0;
}
void mutex_unlock(RecursiveMutex *m) {
pthread_mutex_unlock(&m->pthread_mutex);
}
#if defined(GB_SYSTEM_OSX)
struct Semaphore {
semaphore_t osx_handle;
};
gb_inline void semaphore_init (Semaphore *s) { semaphore_create(mach_task_self(), &s->osx_handle, SYNC_POLICY_FIFO, 0); }
gb_inline void semaphore_destroy(Semaphore *s) { semaphore_destroy(mach_task_self(), s->osx_handle); }
gb_inline void semaphore_post (Semaphore *s, i32 count) { while (count --> 0) semaphore_signal(s->osx_handle); }
gb_inline void semaphore_wait (Semaphore *s) { semaphore_wait(s->osx_handle); }
#elif defined(GB_SYSTEM_UNIX)
struct Semaphore {
sem_t unix_handle;
};
gb_inline void semaphore_init (Semaphore *s) { sem_init(&s->unix_handle, 0, 0); }
gb_inline void semaphore_destroy(Semaphore *s) { sem_destroy(&s->unix_handle); }
gb_inline void semaphore_post (Semaphore *s, i32 count) { while (count --> 0) sem_post(&s->unix_handle); }
gb_inline void semaphore_wait (Semaphore *s) { int i; do { i = sem_wait(&s->unix_handle); } while (i == -1 && errno == EINTR); }
#else
#error
#endif
gb_inline void semaphore_release(Semaphore *s) {
semaphore_post(s, 1);
}
#endif
#include "threading.cpp"
gb_inline void zero_size(void *ptr, isize len) {
memset(ptr, 0, len);

File diff suppressed because it is too large Load Diff

View File

@@ -136,8 +136,6 @@ struct lbModule {
struct lbGenerator {
CheckerInfo *info;
gbMutex mutex;
Array<String> output_object_paths;
Array<String> output_temp_paths;
String output_base;
@@ -148,8 +146,8 @@ struct lbGenerator {
Map<lbProcedure *> anonymous_proc_lits; // Key: Ast *
gbAtomic32 global_array_index;
gbAtomic32 global_generated_index;
std::atomic<u32> global_array_index;
std::atomic<u32> global_generated_index;
};

View File

@@ -400,7 +400,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
} else {
isize max_len = 7+8+1;
char *str = gb_alloc_array(permanent_allocator(), char, max_len);
u32 id = cast(u32)gb_atomic32_fetch_add(&m->gen->global_array_index, 1);
u32 id = m->gen->global_array_index.fetch_add(1);
isize len = gb_snprintf(str, max_len, "csba$%x", id);
String name = make_string(cast(u8 *)str, len-1);

View File

@@ -127,8 +127,6 @@ bool lb_init_generator(lbGenerator *gen, Checker *c) {
map_init(&gen->modules_through_ctx, permanent_allocator(), gen->info->packages.entries.count*2);
map_init(&gen->anonymous_proc_lits, heap_allocator(), 1024);
gb_mutex_init(&gen->mutex);
if (USE_SEPARATE_MODULES) {
for_array(i, gen->info->packages.entries) {
AstPackage *pkg = gen->info->packages.entries[i].value;
@@ -2163,7 +2161,7 @@ LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) {
isize max_len = 7+8+1;
char *name = gb_alloc_array(permanent_allocator(), char, max_len);
u32 id = cast(u32)gb_atomic32_fetch_add(&m->gen->global_array_index, 1);
u32 id = m->gen->global_array_index.fetch_add(1);
isize len = gb_snprintf(name, max_len, "csbs$%x", id);
len -= 1;
@@ -2205,7 +2203,7 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str)
{
isize max_len = 7+8+1;
name = gb_alloc_array(permanent_allocator(), char, max_len);
u32 id = cast(u32)gb_atomic32_fetch_add(&m->gen->global_array_index, 1);
u32 id = m->gen->global_array_index.fetch_add(1);
isize len = gb_snprintf(name, max_len, "csbs$%x", id);
len -= 1;
}
@@ -2317,7 +2315,7 @@ lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value) {
isize max_len = 7+8+1;
u8 *str = cast(u8 *)gb_alloc_array(permanent_allocator(), u8, max_len);
u32 id = cast(u32)gb_atomic32_fetch_add(&m->gen->global_generated_index, 1);
u32 id = m->gen->global_generated_index.fetch_add(1);
isize len = gb_snprintf(cast(char *)str, max_len, "ggv$%x", id);
String name = make_string(str, len-1);

View File

@@ -20,7 +20,7 @@ struct ThreadPool {
MPMCQueue<WorkerTask> tasks;
gbThread *threads;
Thread *threads;
isize thread_count;
char worker_prefix[10];
@@ -32,13 +32,13 @@ void thread_pool_destroy(ThreadPool *pool);
void thread_pool_start(ThreadPool *pool);
void thread_pool_join(ThreadPool *pool);
void thread_pool_add_task(ThreadPool *pool, WorkerTaskProc *proc, void *data);
GB_THREAD_PROC(worker_thread_internal);
THREAD_PROC(worker_thread_internal);
void thread_pool_init(ThreadPool *pool, gbAllocator const &a, isize thread_count, char const *worker_prefix) {
pool->allocator = a;
mpmc_init(&pool->tasks, a, 1024);
pool->thread_count = gb_max(thread_count, 0);
pool->threads = gb_alloc_array(a, gbThread, pool->thread_count);
pool->threads = gb_alloc_array(a, Thread, pool->thread_count);
mutex_init(&pool->mutex);
semaphore_init(&pool->sem_available);
pool->is_running = true;
@@ -52,15 +52,15 @@ void thread_pool_init(ThreadPool *pool, gbAllocator const &a, isize thread_count
}
for (isize i = 0; i < pool->thread_count; i++) {
gbThread *t = &pool->threads[i];
gb_thread_init(t);
Thread *t = &pool->threads[i];
thread_init(t);
t->user_index = i;
#if 0
// TODO(bill): Fix this on Linux as it causes a seg-fault
if (pool->worker_prefix_len > 0) {
char worker_name[16] = {};
gb_snprintf(worker_name, gb_size_of(worker_name), "%.*s%u", pool->worker_prefix_len, pool->worker_prefix, cast(u16)i);
gb_thread_set_name(t, worker_name);
thread_set_name(t, worker_name);
}
#endif
}
@@ -68,8 +68,8 @@ void thread_pool_init(ThreadPool *pool, gbAllocator const &a, isize thread_count
void thread_pool_start(ThreadPool *pool) {
for (isize i = 0; i < pool->thread_count; i++) {
gbThread *t = &pool->threads[i];
gb_thread_start(t, worker_thread_internal, pool);
Thread *t = &pool->threads[i];
thread_start(t, worker_thread_internal, pool);
}
}
@@ -78,11 +78,11 @@ void thread_pool_join(ThreadPool *pool) {
semaphore_post(&pool->sem_available, cast(i32)pool->thread_count);
gb_yield();
yield();
for (isize i = 0; i < pool->thread_count; i++) {
gbThread *t = &pool->threads[i];
gb_thread_join(t);
Thread *t = &pool->threads[i];
thread_join(t);
}
}
@@ -144,14 +144,14 @@ void thread_pool_wait_to_process(ThreadPool *pool) {
mutex_unlock(&pool->mutex);
}
gb_yield();
yield();
}
thread_pool_join(pool);
}
GB_THREAD_PROC(worker_thread_internal) {
THREAD_PROC(worker_thread_internal) {
ThreadPool *pool = cast(ThreadPool *)thread->user_data;
while (pool->is_running) {
semaphore_wait(&pool->sem_available);

348
src/threading.cpp Normal file
View File

@@ -0,0 +1,348 @@
struct BlockingMutex;
struct RecursiveMutex;
struct Semaphore;
struct Thread;
#define THREAD_PROC(name) isize name(struct Thread *thread)
typedef THREAD_PROC(ThreadProc);
struct Thread {
#if defined(GB_SYSTEM_WINDOWS)
void * win32_handle;
#else
pthread_t posix_handle;
#endif
ThreadProc * proc;
void * user_data;
isize user_index;
isize volatile return_value;
Semaphore *semaphore;
isize stack_size;
b32 volatile is_running;
};
void mutex_init (BlockingMutex *m);
void mutex_destroy (BlockingMutex *m);
void mutex_lock (BlockingMutex *m);
bool mutex_try_lock(BlockingMutex *m);
void mutex_unlock (BlockingMutex *m);
void mutex_init (RecursiveMutex *m);
void mutex_destroy (RecursiveMutex *m);
void mutex_lock (RecursiveMutex *m);
bool mutex_try_lock(RecursiveMutex *m);
void mutex_unlock (RecursiveMutex *m);
void semaphore_init (Semaphore *s);
void semaphore_destroy(Semaphore *s);
void semaphore_post (Semaphore *s, i32 count);
void semaphore_wait (Semaphore *s);
void semaphore_release(Semaphore *s) { semaphore_post(s, 1); }
u32 thread_current_id(void);
void thread_init (Thread *t);
void thread_destroy (Thread *t);
void thread_start (Thread *t, ThreadProc *proc, void *data);
void thread_start_with_stack(Thread *t, ThreadProc *proc, void *data, isize stack_size);
void thread_join (Thread *t);
bool thread_is_running (Thread const *t);
void thread_set_name (Thread *t, char const *name);
void yield_thread(void);
void yield_process(void);
#if defined(GB_SYSTEM_WINDOWS)
struct BlockingMutex {
SRWLOCK srwlock;
};
void mutex_init(BlockingMutex *m) {
}
void mutex_destroy(BlockingMutex *m) {
}
void mutex_lock(BlockingMutex *m) {
AcquireSRWLockExclusive(&m->srwlock);
}
bool mutex_try_lock(BlockingMutex *m) {
return !!TryAcquireSRWLockExclusive(&m->srwlock);
}
void mutex_unlock(BlockingMutex *m) {
ReleaseSRWLockExclusive(&m->srwlock);
}
struct RecursiveMutex {
CRITICAL_SECTION win32_critical_section;
};
void mutex_init(RecursiveMutex *m) {
InitializeCriticalSection(&m->win32_critical_section);
}
void mutex_destroy(RecursiveMutex *m) {
DeleteCriticalSection(&m->win32_critical_section);
}
void mutex_lock(RecursiveMutex *m) {
EnterCriticalSection(&m->win32_critical_section);
}
bool mutex_try_lock(RecursiveMutex *m) {
return TryEnterCriticalSection(&m->win32_critical_section) != 0;
}
void mutex_unlock(RecursiveMutex *m) {
LeaveCriticalSection(&m->win32_critical_section);
}
struct Semaphore {
void *win32_handle;
};
void semaphore_init(Semaphore *s) {
s->win32_handle = CreateSemaphoreA(NULL, 0, I32_MAX, NULL);
}
void semaphore_destroy(Semaphore *s) {
CloseHandle(s->win32_handle);
}
void semaphore_post(Semaphore *s, i32 count) {
ReleaseSemaphore(s->win32_handle, count, NULL);
}
void semaphore_wait(Semaphore *s) {
WaitForSingleObjectEx(s->win32_handle, INFINITE, FALSE);
}
#else
struct BlockingMutex {
pthread_mutex_t pthread_mutex;
};
void mutex_init(BlockingMutex *m) {
pthread_mutex_init(&m->pthread_mutex, nullptr);
}
void mutex_destroy(BlockingMutex *m) {
pthread_mutex_destroy(&m->pthread_mutex);
}
void mutex_lock(BlockingMutex *m) {
pthread_mutex_lock(&m->pthread_mutex);
}
bool mutex_try_lock(BlockingMutex *m) {
return pthread_mutex_trylock(&m->pthread_mutex) == 0;
}
void mutex_unlock(BlockingMutex *m) {
pthread_mutex_unlock(&m->pthread_mutex);
}
struct RecursiveMutex {
pthread_mutex_t pthread_mutex;
pthread_mutexattr_t pthread_mutexattr;
};
void mutex_init(RecursiveMutex *m) {
pthread_mutexattr_init(&m->pthread_mutexattr);
pthread_mutexattr_settype(&m->pthread_mutexattr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&m->pthread_mutex, &m->pthread_mutexattr);
}
void mutex_destroy(RecursiveMutex *m) {
pthread_mutex_destroy(&m->pthread_mutex);
}
void mutex_lock(RecursiveMutex *m) {
pthread_mutex_lock(&m->pthread_mutex);
}
bool mutex_try_lock(RecursiveMutex *m) {
return pthread_mutex_trylock(&m->pthread_mutex) == 0;
}
void mutex_unlock(RecursiveMutex *m) {
pthread_mutex_unlock(&m->pthread_mutex);
}
#if defined(GB_SYSTEM_OSX)
struct Semaphore {
semaphore_t osx_handle;
};
void semaphore_init (Semaphore *s) { semaphore_create(mach_task_self(), &s->osx_handle, SYNC_POLICY_FIFO, 0); }
void semaphore_destroy(Semaphore *s) { semaphore_destroy(mach_task_self(), s->osx_handle); }
void semaphore_post (Semaphore *s, i32 count) { while (count --> 0) semaphore_signal(s->osx_handle); }
void semaphore_wait (Semaphore *s) { semaphore_wait(s->osx_handle); }
#elif defined(GB_SYSTEM_UNIX)
struct Semaphore {
sem_t unix_handle;
};
void semaphore_init (Semaphore *s) { sem_init(&s->unix_handle, 0, 0); }
void semaphore_destroy(Semaphore *s) { sem_destroy(&s->unix_handle); }
void semaphore_post (Semaphore *s, i32 count) { while (count --> 0) sem_post(&s->unix_handle); }
void semaphore_wait (Semaphore *s) { int i; do { i = sem_wait(&s->unix_handle); } while (i == -1 && errno == EINTR); }
#else
#error
#endif
#endif
u32 thread_current_id(void) {
u32 thread_id;
#if defined(GB_SYSTEM_WINDOWS)
#if defined(GB_ARCH_32_BIT) && defined(GB_CPU_X86)
thread_id = (cast(u32 *)__readfsdword(24))[9];
#elif defined(GB_ARCH_64_BIT) && defined(GB_CPU_X86)
thread_id = (cast(u32 *)__readgsqword(48))[18];
#else
thread_id = GetCurrentThreadId();
#endif
#elif defined(GB_SYSTEM_OSX) && defined(GB_ARCH_64_BIT)
thread_id = pthread_mach_thread_np(pthread_self());
#elif defined(GB_ARCH_32_BIT) && defined(GB_CPU_X86)
__asm__("mov %%gs:0x08,%0" : "=r"(thread_id));
#elif defined(GB_ARCH_64_BIT) && defined(GB_CPU_X86)
__asm__("mov %%fs:0x10,%0" : "=r"(thread_id));
#else
#error Unsupported architecture for thread_current_id()
#endif
return thread_id;
}
gb_inline void yield_thread(void) {
#if defined(GB_SYSTEM_WINDOWS)
_mm_pause();
#elif defined(GB_SYSTEM_OSX)
#if defined(GB_CPU_X86)
__asm__ volatile ("" : : : "memory");
#elif defined(GB_CPU_ARM)
__asm__ volatile ("yield" : : : "memory");
#endif
#elif defined(GB_CPU_X86)
_mm_pause();
#else
#error Unknown architecture
#endif
}
gb_inline void yield(void) {
#if defined(GB_SYSTEM_WINDOWS)
YieldProcessor();
#else
sched_yield();
#endif
}
void thread_init(Thread *t) {
gb_zero_item(t);
#if defined(GB_SYSTEM_WINDOWS)
t->win32_handle = INVALID_HANDLE_VALUE;
#else
t->posix_handle = 0;
#endif
t->semaphore = gb_alloc_item(heap_allocator(), Semaphore);
semaphore_init(t->semaphore);
}
void thread_destroy(Thread *t) {
if (t->is_running) thread_join(t);
semaphore_destroy(t->semaphore);
gb_free(heap_allocator(), t->semaphore);
}
void gb__thread_run(Thread *t) {
semaphore_release(t->semaphore);
t->return_value = t->proc(t);
}
#if defined(GB_SYSTEM_WINDOWS)
DWORD __stdcall internal_thread_proc(void *arg) {
Thread *t = cast(Thread *)arg;
gb__thread_run(t);
t->is_running = false;
return 0;
}
#else
void * internal_thread_proc(void *arg) {
Thread *t = cast(Thread *)arg;
gb__thread_run(t);
t->is_running = false;
return NULL;
}
#endif
void thread_start(Thread *t, ThreadProc *proc, void *user_data) { thread_start_with_stack(t, proc, user_data, 0); }
void thread_start_with_stack(Thread *t, ThreadProc *proc, void *user_data, isize stack_size) {
GB_ASSERT(!t->is_running);
GB_ASSERT(proc != NULL);
t->proc = proc;
t->user_data = user_data;
t->stack_size = stack_size;
t->is_running = true;
#if defined(GB_SYSTEM_WINDOWS)
t->win32_handle = CreateThread(NULL, stack_size, internal_thread_proc, t, 0, NULL);
GB_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, internal_thread_proc, t);
pthread_attr_destroy(&attr);
}
#endif
semaphore_wait(t->semaphore);
}
void thread_join(Thread *t) {
if (!t->is_running) return;
#if defined(GB_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;
}
bool thread_is_running(Thread const *t) { return t->is_running != 0; }
void thread_set_name(Thread *t, char const *name) {
#if defined(GB_COMPILER_MSVC)
#pragma pack(push, 8)
typedef struct {
DWORD type;
char const *name;
DWORD id;
DWORD flags;
} gbprivThreadName;
#pragma pack(pop)
gbprivThreadName tn;
tn.type = 0x1000;
tn.name = name;
tn.id = GetThreadId(cast(HANDLE)t->win32_handle);
tn.flags = 0;
__try {
RaiseException(0x406d1388, 0, gb_size_of(tn)/4, cast(ULONG_PTR *)&tn);
} __except(1 /*EXCEPTION_EXECUTE_HANDLER*/) {
}
#elif defined(GB_SYSTEM_WINDOWS) && !defined(GB_COMPILER_MSVC)
// IMPORTANT TODO(bill): Set thread name for GCC/Clang on windows
return;
#elif defined(GB_SYSTEM_OSX)
// TODO(bill): Test if this works
pthread_setname_np(name);
#elif defined(GB_SYSTEM_FREEBSD)
pthread_set_name_np(t->posix_handle, name);
#else
// TODO(bill): Test if this works
pthread_setname_np(t->posix_handle, name);
#endif
}