#include #include #include #include #include #include #include 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); pthread_condattr_destroy(&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; } } }