OS X Support

This commit is contained in:
gingerBill 2016-04-28 16:20:47 +01:00
parent 4e3e5ff12f
commit 2f413e88dd
1 changed files with 202 additions and 17 deletions

217
gb.h
View File

@ -1,4 +1,4 @@
/* gb.h - v0.06a - Ginger Bill's C Helper Library - public domain /* gb.h - v0.06b - Ginger Bill's C Helper Library - public domain
- no warranty implied; use at your own risk - no warranty implied; use at your own risk
This is a single header file with a bunch of useful stuff This is a single header file with a bunch of useful stuff
@ -26,6 +26,7 @@ Conventions used:
Version History: Version History:
0.06b - OS X Support
0.06a - Linux Support 0.06a - Linux Support
0.06 - Windows GCC Support and MSVC x86 Support 0.06 - Windows GCC Support and MSVC x86 Support
0.05b - Formatting 0.05b - Formatting
@ -183,6 +184,10 @@ extern "C" {
#include <process.h> #include <process.h>
#else #else
#include <pthread.h> #include <pthread.h>
#include <time.h>
#include <mach/mach_time.h>
#include <sys/stat.h>
#include <dlfcn.h>
#endif #endif
@ -450,7 +455,7 @@ namespace gb {
/* NOTE(bill): "Move" semantics - invented because the C++ committee are idiots (as a collective not as indiviuals (well a least some aren't)) */ /* NOTE(bill): "Move" semantics - invented because the C++ committee are idiots (as a collective not as indiviuals (well a least some aren't)) */
template <typename T> inline T &&forward(typename RemoveReference<T>::Type &t) { return static_cast<T &&>(t); } template <typename T> inline T &&forward(typename RemoveReference<T>::Type &t) { return static_cast<T &&>(t); }
template <typename T> inline T &&forward(typename RemoveReference<T>::Type &&t) { return static_cast<T &&>(t); } template <typename T> inline T &&forward(typename RemoveReference<T>::Type &&t) { return static_cast<T &&>(t); }
template <typename T> inline T &&move (T &&t) { return static<typename RemoveReference<T>::Type &&>(t); } template <typename T> inline T &&move (T &&t) { return static_cast<typename RemoveReference<T>::Type &&>(t); }
template <typename F> template <typename F>
struct privDefer { struct privDefer {
F f; F f;
@ -1477,7 +1482,7 @@ gb_snprintf_va(char *str, isize n, char const *fmt, va_list va)
#if defined(_WIN32) #if defined(_WIN32)
res = _vsnprintf(str, n, fmt, va); res = _vsnprintf(str, n, fmt, va);
#else #else
res = vsnprintf(str, n, fmt, va) res = vsnprintf(str, n, fmt, va);
#endif #endif
if (n) str[n-1] = 0; if (n) str[n-1] = 0;
/* NOTE(bill): Unix returns length output would require, Windows returns negative when truncated. */ /* NOTE(bill): Unix returns length output would require, Windows returns negative when truncated. */
@ -1491,7 +1496,7 @@ gb_inline i32
gb_fprintln(FILE *f, char const *str) gb_fprintln(FILE *f, char const *str)
{ {
i32 res; i32 res;
res = gb_fprintf(f, str); res = gb_fprintf(f, "%s", str);
gb_fprintf(f, "\n"); gb_fprintf(f, "\n");
res++; res++;
return res; return res;
@ -1802,7 +1807,7 @@ gb_inline i32
gb_fetch_and_atomic32(gbAtomic32 volatile *a, i32 operand) gb_fetch_and_atomic32(gbAtomic32 volatile *a, i32 operand)
{ {
i32 original; i32 original;
register i32 tmp; /* NOTE(bill): One of the only cases when you need to use the register keyword! */ i32 tmp;
__asm__ volatile( __asm__ volatile(
"1: movl %1, %0\n" "1: movl %1, %0\n"
" movl %0, %2\n" " movl %0, %2\n"
@ -1819,7 +1824,7 @@ gb_inline i32
gb_fetch_or_atomic32(gbAtomic32 volatile *a, i32 operand) gb_fetch_or_atomic32(gbAtomic32 volatile *a, i32 operand)
{ {
i32 original; i32 original;
register i32 temp; i32 temp;
__asm__ volatile( __asm__ volatile(
"1: movl %1, %0\n" "1: movl %1, %0\n"
" movl %0, %2\n" " movl %0, %2\n"
@ -1936,7 +1941,7 @@ gb_fetch_and_atomic64(gbAtomic64 volatile *a, i64 operand)
{ {
#if defined(GB_ARCH_64_BIT) #if defined(GB_ARCH_64_BIT)
i64 original; i64 original;
register i64 tmp; i64 tmp;
__asm__ volatile( __asm__ volatile(
"1: movq %1, %0\n" "1: movq %1, %0\n"
" movq %0, %2\n" " movq %0, %2\n"
@ -1961,7 +1966,7 @@ gb_fetch_or_atomic64(gbAtomic64 volatile *a, i64 operand)
{ {
#if defined(GB_ARCH_64_BIT) #if defined(GB_ARCH_64_BIT)
i64 original; i64 original;
register i64 temp; i64 temp;
__asm__ volatile( __asm__ volatile(
"1: movq %1, %0\n" "1: movq %1, %0\n"
" movq %0, %2\n" " movq %0, %2\n"
@ -2037,9 +2042,45 @@ gb_unlock_mutex(gbMutex *m)
#else #else
gb_inline void
gb_init_mutex(gbMutex *m)
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
#if defined (PTHREAD_MUTEX_RECURSIVE) || defined(__FreeBSD__)
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
#else
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
#endif
pthread_mutex_init(&m->posix_handle, &attr);
}
gb_inline void
gb_destroy_mutex(gbMutex *m)
{
pthread_mutex_destroy(&m->posix_handle);
}
gb_inline void
gb_lock_mutex(gbMutex *m)
{
pthread_mutex_lock(&m->posix_handle);
}
gb_inline b32
gb_try_lock_mutex(gbMutex *m)
{
return pthread_mutex_trylock(&m->posix_handle) == 0;
}
gb_inline void
gb_unlock_mutex(gbMutex *m)
{
pthread_mutex_unlock(&m->posix_handle);
}
#endif #endif
#if defined(GB_SYSTEM_WINDOWS)
gb_inline void gb_inline void
gb_init_semaphore(gbSemaphore *s) gb_init_semaphore(gbSemaphore *s)
{ {
@ -2068,12 +2109,58 @@ gb_wait_semaphore(gbSemaphore *s)
GB_ASSERT_MSG(result == WAIT_OBJECT_0, "WaitForSingleObject: GetLastError"); GB_ASSERT_MSG(result == WAIT_OBJECT_0, "WaitForSingleObject: GetLastError");
} }
#else
gb_inline void
gb_init_semaphore(gbSemaphore *s)
{
int err = pthread_cond_init(&s->cond, NULL);
GB_ASSERT(err == 0);
gb_init_mutex(&s->mutex);
}
gb_inline void
gb_destroy_semaphore(gbSemaphore *s)
{
int err = pthread_cond_destroy(&s->cond);
GB_ASSERT(err == 0);
gb_destroy_mutex(&s->mutex);
}
gb_inline void
gb_post_semaphore(gbSemaphore *s, i32 count)
{
i32 i;
gb_lock_mutex(&s->mutex);
for (i = 0; i < count; i++)
pthread_cond_signal(&s->cond);
s->count += count;
gb_unlock_mutex(&s->mutex);
}
gb_inline void
gb_wait_semaphore(gbSemaphore *s)
{
gb_lock_mutex(&s->mutex);
while (s->count <= 0)
pthread_cond_wait(&s->cond, &s->mutex.posix_handle);
s->count--;
gb_unlock_mutex(&s->mutex);
}
#endif
void void
gb_init_thread(gbThread *t) gb_init_thread(gbThread *t)
{ {
gb_zero_struct(t); gb_zero_struct(t);
#if defined(GB_SYSTEM_WINDOWS)
t->win32_handle = INVALID_HANDLE_VALUE; t->win32_handle = INVALID_HANDLE_VALUE;
#else
t->posix_handle = 0;
#endif
gb_init_semaphore(&t->semaphore); gb_init_semaphore(&t->semaphore);
} }
@ -2109,8 +2196,20 @@ gb_start_thread_with_stack(gbThread *t, gbThreadProc *proc, void *data, isize st
t->data = data; t->data = data;
t->stack_size = stack_size; t->stack_size = stack_size;
#if defined(GB_SYSTEM_WINDOWS)
t->win32_handle = CreateThread(NULL, stack_size, gb__thread_proc, t, 0, NULL); t->win32_handle = CreateThread(NULL, stack_size, gb__thread_proc, t, 0, NULL);
GB_ASSERT_MSG(t->win32_handle != NULL, "CreateThread: GetLastError"); 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, gb__thread_proc, t);
pthread_attr_destroy(&attr);
}
#endif
t->is_running = true; t->is_running = true;
gb_wait_semaphore(&t->semaphore); gb_wait_semaphore(&t->semaphore);
@ -2121,9 +2220,14 @@ gb_join_thread(gbThread *t)
{ {
if (!t->is_running) return; if (!t->is_running) return;
#if defined(GB_SYSTEM_WINDOWS)
WaitForSingleObject(t->win32_handle, INFINITE); WaitForSingleObject(t->win32_handle, INFINITE);
CloseHandle(t->win32_handle); CloseHandle(t->win32_handle);
t->win32_handle = INVALID_HANDLE_VALUE; t->win32_handle = INVALID_HANDLE_VALUE;
#else
pthread_join(t->posix_handle, NULL);
t->posix_handle = 0;
#endif
t->is_running = false; t->is_running = false;
} }
@ -2136,11 +2240,11 @@ gb_current_thread_id(void)
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
thread_id = GetCurrentThreadId(); thread_id = GetCurrentThreadId();
#elif defined(GB_SYSTEM_OSX) && defined(GB_ARCH_64_BIT) #elif defined(GB_SYSTEM_OSX) && defined(GB_ARCH_64_BIT)
asm("mov %%gs:0x00,%0" : "=r"(thread_id)); __asm__("mov %%gs:0x00,%0" : "=r"(thread_id));
#elif defined(GB_ARCH_32_BIT) #elif defined(GB_ARCH_32_BIT)
asm("mov %%gs:0x08,%0" : "=r"(thread_id)); __asm__("mov %%gs:0x08,%0" : "=r"(thread_id));
#elif defined(GB_ARCH_64_BIT) #elif defined(GB_ARCH_64_BIT)
asm("mov %%gs:0x10,%0" : "=r"(thread_id)); __asm__("mov %%gs:0x10,%0" : "=r"(thread_id));
#else #else
#error Unsupported architecture for thread::current_id() #error Unsupported architecture for thread::current_id()
#endif #endif
@ -3413,7 +3517,38 @@ gb_move_file(char const *existing_filename, char const *new_filename)
#else #else
#error
gbFileTime
gb_file_last_write_time(char const *filepath, ...)
{
time_t result = 0;
struct stat file_stat;
va_list va;
va_start(va, filepath);
if (stat(gb_sprintf_va(filepath, va), &file_stat)) {
result = file_stat.st_mtimespec.tv_sec;
}
va_end(va);
return cast(gbFileTime)result;
}
gb_inline b32
gb_copy_file(char const *existing_filename, char const *new_filename, b32 fail_if_exists)
{
GB_PANIC("TODO(bill): Implement");
return false;
}
gb_inline b32
gb_move_file(char const *existing_filename, char const *new_filename)
{
GB_PANIC("TODO(bill): Implement");
return false;
}
#endif #endif
@ -3503,7 +3638,7 @@ gb_path_extension(char const *path)
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
gb_inline void gb_exit(u32 code) { ExitProcess(code); } gb_inline void gb_exit(u32 code) { ExitProcess(code); }
#else #else
#error gb_inline void gb_exit(u32 code) { exit(code); }
#endif #endif
@ -3529,7 +3664,21 @@ gb_inline void gb_unload_dll (gbDllHandle dll)
gb_inline gbDllProc gb_dll_proc_address(gbDllHandle dll, char const *proc_name) { return cast(gbDllProc)GetProcAddress(cast(HMODULE)dll, proc_name); } gb_inline gbDllProc gb_dll_proc_address(gbDllHandle dll, char const *proc_name) { return cast(gbDllProc)GetProcAddress(cast(HMODULE)dll, proc_name); }
#else #else
#error
gbDllHandle
gb_load_dll(char const *filepath, ...)
{
gb_local_persist char buffer[512];
va_list va;
va_start(va, filepath);
gb_snprintf_va(buffer, gb_size_of(buffer), filepath, va);
va_end(va);
return cast(gbDllHandle)dlopen(buffer, RTLD_LAZY|RTLD_GLOBAL);
}
gb_inline void gb_unload_dll (gbDllHandle dll) { dlclose(dll); }
gb_inline gbDllProc gb_dll_proc_address(gbDllHandle dll, char const *proc_name) { return cast(gbDllProc)dlsym(dll, proc_name); }
#endif #endif
@ -3538,7 +3687,6 @@ gb_inline gbDllProc gb_dll_proc_address(gbDllHandle dll, char const *proc_name)
* Time * Time
* *
*/ */
#if defined(GB_SYSTEM_WINDOWS)
#if defined(_MSC_VER) #if defined(_MSC_VER)
gb_inline u64 gb_rdtsc(void) { return __rdtsc(); } gb_inline u64 gb_rdtsc(void) { return __rdtsc(); }
@ -3581,6 +3729,8 @@ gb_inline gbDllProc gb_dll_proc_address(gbDllHandle dll, char const *proc_name)
} }
#endif #endif
#if defined(GB_SYSTEM_WINDOWS)
gb_inline f64 gb_inline f64
gb_time_now(void) gb_time_now(void)
{ {
@ -3630,7 +3780,42 @@ gb_get_local_date(gbDate *date)
} }
#else #else
#error
gb_global f64 gb__timebase = 0.0;
gb_global u64 gb__timestart = 0;
gb_inline f64
gb_time_now(void)
{
struct timespec t;
f64 result;
if (gb__timestart) {
mach_timebase_info_data_t tb = {0};
mach_timebase_info(&tb);
gb__timebase = tb.numer;
gb__timebase /= tb.denom;
gb__timestart = mach_absolute_time();
}
result = (mach_absolute_time() - gb__timestart) * gb__timebase;
return result;
}
gb_inline void
gb_get_system_date(gbDate *date)
{
GB_PANIC("TODO(bill): Implement");
}
gb_inline void
gb_get_local_date(gbDate *date)
{
GB_PANIC("TODO(bill): Implement");
}
#endif #endif