#ifndef OS_GENERIC_DONT_INCLUDE_DIRECTLY #error Do not include this file directly #endif #include #include #include #include #include #include #include #include #include #include OSG_INLINE void OGSleep(int is) { sleep(is); } OSG_INLINE int OGUSleep(int ius) { struct timespec sleep = {}; sleep.tv_nsec = (ius % 1000000) * 1000; sleep.tv_sec = ius / 1000000; return nanosleep(&sleep, 0); } OSG_INLINE uint64_t OGGetAbsoluteTimeUS() { struct timeval tv; gettimeofday(&tv, NULL); return ((uint64_t)tv.tv_sec * 1000000) + tv.tv_usec; } OSG_INLINE double OGGetAbsoluteTime() { struct timeval tv; gettimeofday(&tv, 0); return ((double)tv.tv_usec) / 1000000. + (tv.tv_sec); } OSG_INLINE double OGGetFileTime(const char *file) { struct stat buff; int r = stat(file, &buff); if (r < 0) { return -1; } return buff.st_mtime; } OSG_INLINE og_thread_t OGCreateThread(void *(routine)(void *), const char *name, void *parameter) { pthread_attr_t tattr = {0}; pthread_attr_init(&tattr); // TODO: Something smarter than this maybe; but it probably doesn't matter since it's all virtualized anyway. This // will be in line with the default stack size on glibc, but musl has a 128kb default which we'll almost certainly // go over. pthread_attr_setstacksize(&tattr, 2000 * 4096); pthread_t *ret = (pthread_t *)malloc(sizeof(pthread_t)); int r = pthread_create(ret, &tattr, routine, parameter); pthread_attr_destroy(&tattr); if (r) { free(ret); return 0; } #ifdef _GNU_SOURCE #ifdef __APPLE__ pthread_setname_np(name); #else pthread_setname_np(*ret, name); #endif #endif return (og_thread_t)ret; } OSG_INLINE void *OGJoinThread(og_thread_t ot) { void *retval; if (!ot) { return 0; } int rc = pthread_join(*(pthread_t *)ot, &retval); if (rc != 0) { fprintf(stderr, "pthread join error %d\n", rc); } free(ot); return retval; } OSG_INLINE void OGCancelThread(og_thread_t ot) { #ifndef ANDROID if (!ot) { return; } pthread_cancel(*(pthread_t *)ot); free(ot); #endif } static inline void _OGHandlePosixError(const char *msg, int err) { if (err != 0) { fprintf(stderr, "%s: %s (%d)\n", msg, strerror(err), err); abort(); } } OSG_INLINE og_mutex_t OGCreateMutex() { pthread_mutexattr_t mta; og_mutex_t r = malloc(sizeof(pthread_mutex_t)); pthread_mutexattr_init(&mta); pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE); _OGHandlePosixError("OGCreateMutex", pthread_mutex_init((pthread_mutex_t *)r, &mta)); return r; } OSG_INLINE int OGTryLockMutex(og_mutex_t om) { if (!om) { return -1; } return pthread_mutex_trylock((pthread_mutex_t *)om); } OSG_INLINE void OGLockMutex(og_mutex_t om) { if (!om) { return; } _OGHandlePosixError("OGLockMutex", pthread_mutex_lock((pthread_mutex_t *)om)); } OSG_INLINE void OGUnlockMutex(og_mutex_t om) { if (!om) { return; } _OGHandlePosixError("OGUnlockMutex", pthread_mutex_unlock((pthread_mutex_t *)om)); } OSG_INLINE void OGDeleteMutex(og_mutex_t om) { if (!om) { return; } pthread_mutex_destroy((pthread_mutex_t *)om); free(om); } OSG_INLINE og_sema_t OGCreateSema() { sem_t *sem = (sem_t *)malloc(sizeof(sem_t)); sem_init(sem, 0, 0); return (og_sema_t)sem; } OSG_INLINE int OGGetSema(og_sema_t os) { int valp; sem_getvalue((sem_t *)os, &valp); return valp; } OSG_INLINE void OGLockSema(og_sema_t os) { sem_wait((sem_t *)os); } OSG_INLINE void OGUnlockSema(og_sema_t os) { sem_post((sem_t *)os); } OSG_INLINE void OGDeleteSema(og_sema_t os) { sem_destroy((sem_t *)os); free(os); } OSG_INLINE void OGSignalCond(og_cv_t cv) { _OGHandlePosixError("OGSignalCond", pthread_cond_signal((pthread_cond_t *)cv)); } OSG_INLINE void OGBroadcastCond(og_cv_t cv) { _OGHandlePosixError("OGBroadcastCond", pthread_cond_broadcast((pthread_cond_t *)cv)); } OSG_INLINE void OGWaitCond(og_cv_t cv, og_mutex_t m) { _OGHandlePosixError("OGWaitCond", pthread_cond_wait((pthread_cond_t *)cv, (pthread_mutex_t *)m)); } OSG_INLINE bool OGWaitCondTimeout(og_cv_t cv, og_mutex_t m, int ms) { struct timespec ts = {}; clock_gettime(CLOCK_REALTIME, &ts); uint64_t waittil = (uint64_t)ts.tv_sec * 1000000000 + ts.tv_nsec + ms * 1000000; ts.tv_sec = waittil / 1000000000; ts.tv_nsec = waittil % 1000000000; int err = pthread_cond_timedwait((pthread_cond_t *)cv, (pthread_mutex_t *)m, &ts); if (err != 0 && err != ETIMEDOUT) _OGHandlePosixError("OGWaitCond", err); return err == 0; } OSG_INLINE void OGDeleteConditionVariable(og_cv_t cv) { pthread_cond_destroy((pthread_cond_t *)cv); free(cv); } OSG_INLINE og_cv_t OGCreateConditionVariable() { pthread_cond_t *cv = (pthread_cond_t *)malloc(sizeof(pthread_cond_t)); int status = pthread_cond_init(cv, 0); if (status != 0) { free(cv); return 0; } return cv; }