mirror of
https://github.com/ZDoom/zdoom-macos-deps.git
synced 2024-11-25 05:11:49 +00:00
445 lines
7.1 KiB
C++
445 lines
7.1 KiB
C++
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <pthread.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/time.h>
|
|
#include <mach/mach_time.h>
|
|
|
|
|
|
extern "C"
|
|
{
|
|
|
|
void* g_malloc(size_t size)
|
|
{
|
|
return malloc(size);
|
|
}
|
|
|
|
void g_free(void* ptr)
|
|
{
|
|
free(ptr);
|
|
}
|
|
|
|
|
|
struct GError
|
|
{
|
|
uint32_t domain;
|
|
int code;
|
|
char* message;
|
|
};
|
|
|
|
void g_clear_error(GError** err)
|
|
{
|
|
if (nullptr != err && nullptr != *err)
|
|
{
|
|
free(*err);
|
|
*err = nullptr;
|
|
}
|
|
}
|
|
|
|
|
|
void g_return_if_fail_warning(const char* domain, const char* function, const char* expression)
|
|
{
|
|
}
|
|
|
|
|
|
enum GFileTest
|
|
{
|
|
G_FILE_TEST_IS_REGULAR = 1 << 0,
|
|
G_FILE_TEST_IS_SYMLINK = 1 << 1,
|
|
G_FILE_TEST_IS_DIR = 1 << 2,
|
|
G_FILE_TEST_IS_EXECUTABLE = 1 << 3,
|
|
G_FILE_TEST_EXISTS = 1 << 4
|
|
};
|
|
|
|
int g_file_test(const char* filename, int test)
|
|
{
|
|
if (filename == nullptr)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ((test & G_FILE_TEST_EXISTS) && (access(filename, F_OK) == 0))
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
if ((test & G_FILE_TEST_IS_EXECUTABLE) && (access(filename, X_OK) == 0))
|
|
{
|
|
if (getuid() != 0)
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
test &= ~G_FILE_TEST_IS_EXECUTABLE;
|
|
}
|
|
|
|
if (test & G_FILE_TEST_IS_SYMLINK)
|
|
{
|
|
struct stat s;
|
|
|
|
if ((lstat(filename, &s) == 0) && S_ISLNK(s.st_mode))
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (test & (G_FILE_TEST_IS_REGULAR | G_FILE_TEST_IS_DIR | G_FILE_TEST_IS_EXECUTABLE))
|
|
{
|
|
struct stat s;
|
|
|
|
if (stat(filename, &s) == 0)
|
|
{
|
|
if ((test & G_FILE_TEST_IS_REGULAR) && S_ISREG(s.st_mode))
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
if ((test & G_FILE_TEST_IS_DIR) && S_ISDIR(s.st_mode))
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
if ((test & G_FILE_TEST_IS_EXECUTABLE) && ((s.st_mode & S_IXOTH) || (s.st_mode & S_IXUSR) || (s.st_mode & S_IXGRP)))
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int64_t g_get_monotonic_time()
|
|
{
|
|
static mach_timebase_info_data_t timebase_info;
|
|
|
|
if (timebase_info.denom == 0)
|
|
{
|
|
mach_timebase_info(&timebase_info);
|
|
|
|
if (timebase_info.numer % 1000 == 0)
|
|
{
|
|
timebase_info.numer /= 1000;
|
|
}
|
|
else
|
|
{
|
|
timebase_info.denom *= 1000;
|
|
}
|
|
|
|
if (timebase_info.denom % timebase_info.numer == 0)
|
|
{
|
|
timebase_info.denom /= timebase_info.numer;
|
|
timebase_info.numer = 1;
|
|
}
|
|
}
|
|
|
|
return mach_absolute_time() / timebase_info.denom;
|
|
}
|
|
|
|
|
|
void g_usleep(unsigned long microseconds)
|
|
{
|
|
usleep(microseconds);
|
|
}
|
|
|
|
|
|
struct GMutex
|
|
{
|
|
pthread_mutex_t* p;
|
|
};
|
|
|
|
static pthread_mutex_t* g_mutex_impl_new()
|
|
{
|
|
pthread_mutexattr_t attr;
|
|
pthread_mutexattr_init(&attr);
|
|
|
|
pthread_mutex_t* mutex = new pthread_mutex_t;
|
|
pthread_mutex_init(mutex, &attr);
|
|
|
|
pthread_mutexattr_destroy(&attr);
|
|
|
|
return mutex;
|
|
}
|
|
|
|
static void g_mutex_impl_free(pthread_mutex_t* mutex)
|
|
{
|
|
pthread_mutex_destroy(mutex);
|
|
delete mutex;
|
|
}
|
|
|
|
static pthread_mutex_t* g_mutex_get_impl(GMutex* mutex)
|
|
{
|
|
pthread_mutex_t* impl = mutex->p;
|
|
__sync_synchronize();
|
|
|
|
if (nullptr == impl)
|
|
{
|
|
impl = g_mutex_impl_new();
|
|
|
|
if (__sync_val_compare_and_swap(&mutex->p, nullptr, impl) != nullptr)
|
|
{
|
|
g_mutex_impl_free(impl);
|
|
impl = mutex->p;
|
|
}
|
|
}
|
|
|
|
return impl;
|
|
}
|
|
|
|
void g_mutex_init(GMutex* mutex)
|
|
{
|
|
mutex->p = g_mutex_impl_new();
|
|
}
|
|
|
|
void g_mutex_clear(GMutex* mutex)
|
|
{
|
|
g_mutex_impl_free(mutex->p);
|
|
}
|
|
|
|
void g_mutex_lock(GMutex* mutex)
|
|
{
|
|
pthread_mutex_lock(g_mutex_get_impl(mutex));
|
|
}
|
|
|
|
void g_mutex_unlock(GMutex* mutex)
|
|
{
|
|
pthread_mutex_unlock(g_mutex_get_impl(mutex));
|
|
}
|
|
|
|
|
|
struct GRecMutex
|
|
{
|
|
pthread_mutex_t* p;
|
|
unsigned int i[2];
|
|
};
|
|
|
|
static pthread_mutex_t* g_rec_mutex_impl_new()
|
|
{
|
|
pthread_mutexattr_t attr;
|
|
pthread_mutexattr_init(&attr);
|
|
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
|
|
|
pthread_mutex_t* mutex = new pthread_mutex_t;
|
|
pthread_mutex_init(mutex, &attr);
|
|
|
|
pthread_mutexattr_destroy(&attr);
|
|
|
|
return mutex;
|
|
}
|
|
|
|
static void g_rec_mutex_impl_free(pthread_mutex_t* mutex)
|
|
{
|
|
pthread_mutex_destroy(mutex);
|
|
delete mutex;
|
|
}
|
|
|
|
static pthread_mutex_t* g_rec_mutex_get_impl(GRecMutex* mutex)
|
|
{
|
|
pthread_mutex_t* impl = mutex->p;
|
|
__sync_synchronize();
|
|
|
|
if (nullptr == impl)
|
|
{
|
|
impl = g_rec_mutex_impl_new();
|
|
|
|
if (__sync_val_compare_and_swap(&mutex->p, nullptr, impl) != nullptr)
|
|
{
|
|
g_rec_mutex_impl_free(impl);
|
|
impl = mutex->p;
|
|
}
|
|
}
|
|
|
|
return impl;
|
|
}
|
|
|
|
void g_rec_mutex_init(GRecMutex* mutex)
|
|
{
|
|
mutex->p = g_rec_mutex_impl_new();
|
|
}
|
|
|
|
void g_rec_mutex_clear(GRecMutex* mutex)
|
|
{
|
|
g_rec_mutex_impl_free(mutex->p);
|
|
}
|
|
|
|
void g_rec_mutex_lock(GRecMutex* mutex)
|
|
{
|
|
pthread_mutex_lock(g_rec_mutex_get_impl(mutex));
|
|
}
|
|
|
|
void g_rec_mutex_unlock(GRecMutex* mutex)
|
|
{
|
|
pthread_mutex_unlock(g_rec_mutex_get_impl(mutex));
|
|
}
|
|
|
|
|
|
struct GCond
|
|
{
|
|
pthread_cond_t* p;
|
|
unsigned int i[2];
|
|
};
|
|
|
|
static pthread_cond_t* g_cond_impl_new()
|
|
{
|
|
pthread_condattr_t attr;
|
|
pthread_condattr_init(&attr);
|
|
|
|
pthread_cond_t* cond = new pthread_cond_t;
|
|
pthread_cond_init(cond, &attr);
|
|
|
|
return cond;
|
|
}
|
|
|
|
static void g_cond_impl_free(pthread_cond_t* cond)
|
|
{
|
|
pthread_cond_destroy(cond);
|
|
delete cond;
|
|
}
|
|
|
|
static pthread_cond_t* g_cond_get_impl(GCond* cond)
|
|
{
|
|
pthread_cond_t* impl = cond->p;
|
|
__sync_synchronize();
|
|
|
|
if (nullptr == impl)
|
|
{
|
|
impl = g_cond_impl_new();
|
|
|
|
if (__sync_val_compare_and_swap(&cond->p, nullptr, impl) != nullptr)
|
|
{
|
|
g_cond_impl_free(impl);
|
|
impl = cond->p;
|
|
}
|
|
}
|
|
|
|
return impl;
|
|
}
|
|
|
|
void g_cond_init(GCond* cond)
|
|
{
|
|
cond->p = g_cond_impl_new();
|
|
}
|
|
|
|
void g_cond_clear(GCond* cond)
|
|
{
|
|
g_cond_impl_free(cond->p);
|
|
}
|
|
|
|
void g_cond_wait(GCond* cond, GMutex* mutex)
|
|
{
|
|
pthread_cond_wait(g_cond_get_impl(cond), g_mutex_get_impl(mutex));
|
|
}
|
|
|
|
void g_cond_signal(GCond* cond)
|
|
{
|
|
pthread_cond_signal(g_cond_get_impl(cond));
|
|
}
|
|
|
|
void g_cond_broadcast(GCond* cond)
|
|
{
|
|
pthread_cond_broadcast(g_cond_get_impl(cond));
|
|
}
|
|
|
|
|
|
using GDestroyNotify = void (*)(void* data);
|
|
|
|
struct GPrivate
|
|
{
|
|
pthread_key_t* p;
|
|
GDestroyNotify notify;
|
|
void* future[2];
|
|
};
|
|
|
|
static pthread_key_t* g_private_impl_new(GDestroyNotify notify)
|
|
{
|
|
pthread_key_t* key = new pthread_key_t;
|
|
pthread_key_create(key, notify);
|
|
return key;
|
|
}
|
|
|
|
static void g_private_impl_free(pthread_key_t* key)
|
|
{
|
|
pthread_key_delete(*key);
|
|
delete key;
|
|
}
|
|
|
|
static inline pthread_key_t* g_private_get_impl(GPrivate* key)
|
|
{
|
|
pthread_key_t* impl = key->p;
|
|
__sync_synchronize();
|
|
|
|
if (nullptr == impl)
|
|
{
|
|
impl = g_private_impl_new(key->notify);
|
|
|
|
if (__sync_val_compare_and_swap(&key->p, nullptr, impl) != nullptr)
|
|
{
|
|
g_private_impl_free(impl);
|
|
impl = key->p;
|
|
}
|
|
}
|
|
|
|
return impl;
|
|
}
|
|
|
|
void* g_private_get(GPrivate* key)
|
|
{
|
|
return pthread_getspecific(*g_private_get_impl(key));
|
|
}
|
|
|
|
void g_private_set(GPrivate* key, void* value)
|
|
{
|
|
pthread_setspecific(*g_private_get_impl(key), value);
|
|
}
|
|
|
|
|
|
struct GThread
|
|
{
|
|
pthread_t thread;
|
|
int ref_count;
|
|
};
|
|
|
|
using GThreadFunc = void* (*)(void* data);
|
|
|
|
GThread* g_thread_try_new(const char* name, GThreadFunc func, void* data, GError** error)
|
|
{
|
|
if (error != nullptr)
|
|
{
|
|
*error = nullptr;
|
|
}
|
|
|
|
pthread_attr_t attr;
|
|
pthread_attr_init(&attr);
|
|
|
|
GThread* thread = new GThread;
|
|
pthread_create(&thread->thread, &attr, func, data);
|
|
thread->ref_count = 1;
|
|
|
|
pthread_attr_destroy(&attr);
|
|
|
|
return thread;
|
|
}
|
|
|
|
void* g_thread_join(GThread* thread)
|
|
{
|
|
void* result = nullptr;
|
|
pthread_join(thread->thread, &result);
|
|
return result;
|
|
}
|
|
|
|
void g_thread_unref(GThread* thread)
|
|
{
|
|
if (__sync_sub_and_fetch(&thread->ref_count, 1) == 0)
|
|
{
|
|
g_thread_join(thread);
|
|
delete thread;
|
|
}
|
|
}
|
|
|
|
}
|