Created
June 11, 2021 02:38
-
-
Save kayws426/3fafdc7e216692c8db45633e58f5b486 to your computer and use it in GitHub Desktop.
a single-header library to provide some pthread functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Cross Platform Thread Wrapper | |
// Refer: https://nachtimwald.com/2019/04/05/cross-platform-thread-wrapper/ | |
// | |
// This file is a single-header library to provide some pthread functions | |
// | |
#ifndef __PTHREAD_WRAPPER_H__ | |
#define __PTHREAD_WRAPPER_H__ | |
#ifdef _WIN32 | |
#include <stdbool.h> | |
#include <windows.h> | |
#include <synchapi.h> | |
#else | |
#include <pthread.h> | |
#endif | |
#include <time.h> | |
#ifdef __cplusplus | |
extern "C" { | |
#endif | |
#ifdef _WIN32 | |
#define PTHREAD_WRAPPER_API static inline | |
typedef CRITICAL_SECTION pthread_mutex_t; | |
typedef void pthread_attr_t; | |
typedef void pthread_mutexattr_t; | |
typedef void pthread_condattr_t; | |
typedef void pthread_rwlockattr_t; | |
typedef HANDLE pthread_t; | |
typedef CONDITION_VARIABLE pthread_cond_t; | |
#if defined(WINVER) && (WINVER >= _WIN32_WINNT_WIN7) | |
typedef struct { | |
SRWLOCK lock; | |
bool exclusive; | |
} pthread_rwlock_t; | |
#define PTHREAD_RWLOCK_DEFINED 1 | |
#endif | |
#if defined(_MSC_VER) && !defined(TIME_UTC) | |
struct timespec { | |
long tv_sec; | |
long tv_nsec; | |
}; | |
#endif | |
#endif | |
#ifdef _WIN32 | |
PTHREAD_WRAPPER_API int pthread_create(pthread_t* thread, pthread_attr_t* attr, void* (*start_routine)(void*), void* arg); | |
PTHREAD_WRAPPER_API int pthread_join(pthread_t thread, void** value_ptr); | |
PTHREAD_WRAPPER_API int pthread_detach(pthread_t); | |
PTHREAD_WRAPPER_API int pthread_mutex_init(pthread_mutex_t* mutex, pthread_mutexattr_t* attr); | |
PTHREAD_WRAPPER_API int pthread_mutex_destroy(pthread_mutex_t* mutex); | |
PTHREAD_WRAPPER_API int pthread_mutex_lock(pthread_mutex_t* mutex); | |
PTHREAD_WRAPPER_API int pthread_mutex_unlock(pthread_mutex_t* mutex); | |
PTHREAD_WRAPPER_API int pthread_cond_init(pthread_cond_t* cond, pthread_condattr_t* attr); | |
PTHREAD_WRAPPER_API int pthread_cond_destroy(pthread_cond_t* cond); | |
PTHREAD_WRAPPER_API int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex); | |
PTHREAD_WRAPPER_API int pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, const struct timespec* abstime); | |
PTHREAD_WRAPPER_API int pthread_cond_signal(pthread_cond_t* cond); | |
PTHREAD_WRAPPER_API int pthread_cond_broadcast(pthread_cond_t* cond); | |
#if PTHREAD_RWLOCK_DEFINED | |
PTHREAD_WRAPPER_API int pthread_rwlock_init(pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr); | |
PTHREAD_WRAPPER_API int pthread_rwlock_destroy(pthread_rwlock_t* rwlock); | |
PTHREAD_WRAPPER_API int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock); | |
PTHREAD_WRAPPER_API int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock); | |
PTHREAD_WRAPPER_API int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock); | |
PTHREAD_WRAPPER_API int pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock); | |
PTHREAD_WRAPPER_API int pthread_rwlock_unlock(pthread_rwlock_t* rwlock); | |
#endif | |
#endif | |
PTHREAD_WRAPPER_API unsigned int pcthread_get_num_procs(); | |
PTHREAD_WRAPPER_API void msec_to_timespec(struct timespec* ts, unsigned int ms); | |
PTHREAD_WRAPPER_API DWORD timespec_to_msec(const struct timespec* ts); | |
#ifdef _WIN32 // Implementations | |
// Thread: Create | |
PTHREAD_WRAPPER_API int pthread_create(pthread_t* thread, pthread_attr_t* attr, void* (*start_routine)(void*), void* arg) { | |
(void)(attr); | |
if (thread == NULL || start_routine == NULL) | |
return 1; | |
*thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)start_routine, arg, 0, NULL); | |
if (*thread == NULL) { | |
return 1; | |
} | |
return 0; | |
} | |
// Thread: Join | |
PTHREAD_WRAPPER_API int pthread_join(pthread_t thread, void** value_ptr) { | |
(void)value_ptr; | |
WaitForSingleObject(thread, INFINITE); | |
CloseHandle(thread); | |
return 0; | |
} | |
// Thread: Detach | |
PTHREAD_WRAPPER_API int pthread_detach(pthread_t thread) { | |
CloseHandle(thread); | |
return 0; | |
} | |
// Mutex: Init | |
PTHREAD_WRAPPER_API int pthread_mutex_init(pthread_mutex_t* mutex, pthread_mutexattr_t* attr) { | |
(void)attr; | |
if (mutex == NULL) { | |
return 1; | |
} | |
InitializeCriticalSection(mutex); | |
return 0; | |
} | |
// Mutex: Destroy | |
PTHREAD_WRAPPER_API int pthread_mutex_destroy(pthread_mutex_t* mutex) { | |
if (mutex == NULL) { | |
return 1; | |
} | |
DeleteCriticalSection(mutex); | |
return 0; | |
} | |
// Mutex: Lock | |
PTHREAD_WRAPPER_API int pthread_mutex_lock(pthread_mutex_t* mutex) { | |
if (mutex == NULL) { | |
return 1; | |
} | |
EnterCriticalSection(mutex); | |
return 0; | |
} | |
// Mutex: Unlock | |
PTHREAD_WRAPPER_API int pthread_mutex_unlock(pthread_mutex_t* mutex) { | |
if (mutex == NULL) { | |
return 1; | |
} | |
LeaveCriticalSection(mutex); | |
return 0; | |
} | |
// Conditional Variable: Init | |
PTHREAD_WRAPPER_API int pthread_cond_init(pthread_cond_t* cond, pthread_condattr_t* attr) { | |
(void)attr; | |
if (cond == NULL) { | |
return 1; | |
} | |
InitializeConditionVariable(cond); | |
return 0; | |
} | |
// Conditional Variable: Destroy | |
PTHREAD_WRAPPER_API int pthread_cond_destroy(pthread_cond_t* cond) { | |
/* Windows does not have a destroy for conditionals */ | |
(void)cond; | |
return 0; | |
} | |
// Conditional Variable: Wait | |
PTHREAD_WRAPPER_API int pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex) { | |
if (cond == NULL || mutex == NULL) { | |
return 1; | |
} | |
return pthread_cond_timedwait(cond, mutex, NULL); | |
} | |
// Conditional Variable: TimedWait | |
PTHREAD_WRAPPER_API int pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, const struct timespec* abstime) { | |
if (cond == NULL || mutex == NULL) { | |
return 1; | |
} | |
if (!SleepConditionVariableCS(cond, mutex, timespec_to_msec(abstime))) { | |
return 1; | |
} | |
return 0; | |
} | |
// Conditional Variable: Signal | |
PTHREAD_WRAPPER_API int pthread_cond_signal(pthread_cond_t* cond) { | |
if (cond == NULL) { | |
return 1; | |
} | |
WakeConditionVariable(cond); | |
return 0; | |
} | |
// Conditional Variable: Broadcast | |
PTHREAD_WRAPPER_API int pthread_cond_broadcast(pthread_cond_t* cond) { | |
if (cond == NULL) { | |
return 1; | |
} | |
WakeAllConditionVariable(cond); | |
return 0; | |
} | |
#if PTHREAD_RWLOCK_DEFINED | |
// Read Write Lock: Init | |
PTHREAD_WRAPPER_API int pthread_rwlock_init(pthread_rwlock_t* rwlock, const pthread_rwlockattr_t* attr) { | |
(void)attr; | |
if (rwlock == NULL) { | |
return 1; | |
} | |
InitializeSRWLock(&(rwlock->lock)); | |
rwlock->exclusive = false; | |
return 0; | |
} | |
// Read Write Lock: Destroy | |
PTHREAD_WRAPPER_API int pthread_rwlock_destroy(pthread_rwlock_t* rwlock) { | |
(void)rwlock; | |
} | |
// Read Write Lock: ReadLock | |
PTHREAD_WRAPPER_API int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock) { | |
if (rwlock == NULL) { | |
return 1; | |
} | |
AcquireSRWLockShared(&(rwlock->lock)); | |
} | |
// Read Write Lock: TryReadLock | |
PTHREAD_WRAPPER_API int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock) { | |
if (rwlock == NULL) { | |
return 1; | |
} | |
return !TryAcquireSRWLockShared(&(rwlock->lock)); | |
} | |
// Read Write Lock: WriteLock | |
PTHREAD_WRAPPER_API int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock) { | |
if (rwlock == NULL) { | |
return 1; | |
} | |
AcquireSRWLockExclusive(&(rwlock->lock)); | |
rwlock->exclusive = true; | |
} | |
// Read Write Lock: TryWriteLock | |
PTHREAD_WRAPPER_API int pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock) { | |
BOOLEAN ret; | |
if (rwlock == NULL) { | |
return 1; | |
} | |
ret = TryAcquireSRWLockExclusive(&(rwlock->lock)); | |
if (ret) { | |
rwlock->exclusive = true; | |
} | |
return ret; | |
} | |
// Read Write Lock: Unlock | |
PTHREAD_WRAPPER_API int pthread_rwlock_unlock(pthread_rwlock_t* rwlock) { | |
if (rwlock == NULL) { | |
return 1; | |
} | |
if (rwlock->exclusive) { | |
rwlock->exclusive = false; | |
ReleaseSRWLockExclusive(&(rwlock->lock)); | |
} | |
else { | |
ReleaseSRWLockShared(&(rwlock->lock)); | |
} | |
} | |
#endif | |
// Time conversion: ms to timespec | |
PTHREAD_WRAPPER_API void msec_to_timespec(struct timespec* ts, unsigned int msec) { | |
if (ts == NULL) { | |
return; | |
} | |
#if defined(_MSC_VER) && defined(TIME_UTC) | |
if (TIME_UTC == timespec_get(ts, TIME_UTC)) { | |
long _nsec = ts->tv_nsec + ((msec % 1000) * 1000000); | |
if (_nsec >= 1000000000) { | |
_nsec -= 1000000000; | |
ts->tv_sec += ((msec / 1000) + 1); | |
ts->tv_nsec = _nsec; | |
} | |
else { | |
ts->tv_sec += (msec / 1000); | |
ts->tv_nsec = _nsec; | |
} | |
} | |
else { | |
// if 'timespec_get' returns fail, try with 'time' function | |
ts->tv_sec = (msec / 1000) + time(NULL); | |
ts->tv_nsec = (msec % 1000) * 1000000; | |
} | |
#else | |
ts->tv_sec = (msec / 1000) + time(NULL); | |
ts->tv_nsec = (msec % 1000) * 1000000; | |
#endif | |
} | |
// Time conversion: timespec to ms | |
PTHREAD_WRAPPER_API DWORD timespec_to_msec(const struct timespec* abstime) { | |
time_t t; | |
if (abstime == NULL) { | |
return INFINITE; | |
} | |
#if defined(_MSC_VER) && defined(TIME_UTC) | |
struct timespec _ts_now; | |
if (TIME_UTC == timespec_get(&_ts_now, TIME_UTC)) { | |
register time_t _sec = (abstime->tv_sec - _ts_now.tv_sec); | |
register long _msec = ((abstime->tv_nsec - _ts_now.tv_nsec) / 1000000); | |
if (_msec < 0) { | |
_msec += 1000; | |
_sec -= 1; | |
} | |
t = (_sec * 1000) + _msec; | |
} | |
else { | |
// if 'timespec_get' returns fail, try with 'time' function | |
t = ((abstime->tv_sec - time(NULL)) * 1000) + (abstime->tv_nsec / 1000000); | |
} | |
if (t < 0) { | |
t = 1; | |
} | |
#else | |
t = ((abstime->tv_sec - time(NULL)) * 1000) + (abstime->tv_nsec / 1000000); | |
if (t < 0) { | |
t = 1; | |
} | |
#endif | |
return (DWORD)t; | |
} | |
// Number of Cores / Processors | |
#ifdef _WIN32 | |
PTHREAD_WRAPPER_API unsigned int pcthread_get_num_procs() { | |
SYSTEM_INFO sysinfo; | |
GetSystemInfo(&sysinfo); | |
return sysinfo.dwNumberOfProcessors; | |
} | |
#else | |
#include <unistd.h> | |
PTHREAD_WRAPPER_API unsigned int pcthread_get_num_procs() { | |
return (unsigned int)sysconf(_SC_NPROCESSORS_ONLN); | |
} | |
#endif | |
#endif // Implementations | |
#ifdef __cplusplus | |
} // end of extern "C" | |
#endif | |
#endif /* __PTHREAD_WRAPPER_H__ */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment