diff options
author | thegeorg <thegeorg@yandex-team.ru> | 2022-02-10 16:45:08 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:08 +0300 |
commit | 4e839db24a3bbc9f1c610c43d6faaaa99824dcca (patch) | |
tree | 506dac10f5df94fab310584ee51b24fc5a081c22 /contrib/libs/xz/common/mythread.h | |
parent | 2d37894b1b037cf24231090eda8589bbb44fb6fc (diff) | |
download | ydb-4e839db24a3bbc9f1c610c43d6faaaa99824dcca.tar.gz |
Restoring authorship annotation for <thegeorg@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/libs/xz/common/mythread.h')
-rw-r--r-- | contrib/libs/xz/common/mythread.h | 1042 |
1 files changed, 521 insertions, 521 deletions
diff --git a/contrib/libs/xz/common/mythread.h b/contrib/libs/xz/common/mythread.h index be22654240..fe678c3bf7 100644 --- a/contrib/libs/xz/common/mythread.h +++ b/contrib/libs/xz/common/mythread.h @@ -1,521 +1,521 @@ -/////////////////////////////////////////////////////////////////////////////// -// -/// \file mythread.h -/// \brief Some threading related helper macros and functions -// -// Author: Lasse Collin -// -// This file has been put into the public domain. -// You can do whatever you want with this file. -// -/////////////////////////////////////////////////////////////////////////////// - -#ifndef MYTHREAD_H -#define MYTHREAD_H - -#include "sysdefs.h" - -// If any type of threading is enabled, #define MYTHREAD_ENABLED. -#if defined(MYTHREAD_POSIX) || defined(MYTHREAD_WIN95) \ - || defined(MYTHREAD_VISTA) -# define MYTHREAD_ENABLED 1 -#endif - - -#ifdef MYTHREAD_ENABLED - -//////////////////////////////////////// -// Shared between all threading types // -//////////////////////////////////////// - -// Locks a mutex for a duration of a block. -// -// Perform mythread_mutex_lock(&mutex) in the beginning of a block -// and mythread_mutex_unlock(&mutex) at the end of the block. "break" -// may be used to unlock the mutex and jump out of the block. -// mythread_sync blocks may be nested. -// -// Example: -// -// mythread_sync(mutex) { -// foo(); -// if (some_error) -// break; // Skips bar() -// bar(); -// } -// -// At least GCC optimizes the loops completely away so it doesn't slow -// things down at all compared to plain mythread_mutex_lock(&mutex) -// and mythread_mutex_unlock(&mutex) calls. -// -#define mythread_sync(mutex) mythread_sync_helper1(mutex, __LINE__) -#define mythread_sync_helper1(mutex, line) mythread_sync_helper2(mutex, line) -#define mythread_sync_helper2(mutex, line) \ - for (unsigned int mythread_i_ ## line = 0; \ - mythread_i_ ## line \ - ? (mythread_mutex_unlock(&(mutex)), 0) \ - : (mythread_mutex_lock(&(mutex)), 1); \ - mythread_i_ ## line = 1) \ - for (unsigned int mythread_j_ ## line = 0; \ - !mythread_j_ ## line; \ - mythread_j_ ## line = 1) -#endif - - -#if !defined(MYTHREAD_ENABLED) - -////////////////// -// No threading // -////////////////// - -// Calls the given function once. This isn't thread safe. -#define mythread_once(func) \ -do { \ - static bool once_ = false; \ - if (!once_) { \ - func(); \ - once_ = true; \ - } \ -} while (0) - - -#if !(defined(_WIN32) && !defined(__CYGWIN__)) -// Use sigprocmask() to set the signal mask in single-threaded programs. -#include <signal.h> - -static inline void -mythread_sigmask(int how, const sigset_t *restrict set, - sigset_t *restrict oset) -{ - int ret = sigprocmask(how, set, oset); - assert(ret == 0); - (void)ret; -} -#endif - - -#elif defined(MYTHREAD_POSIX) - -//////////////////// -// Using pthreads // -//////////////////// - -#include <sys/time.h> -#include <pthread.h> -#include <signal.h> -#include <time.h> -#include <errno.h> - -#define MYTHREAD_RET_TYPE void * -#define MYTHREAD_RET_VALUE NULL - -typedef pthread_t mythread; -typedef pthread_mutex_t mythread_mutex; - -typedef struct { - pthread_cond_t cond; -#ifdef HAVE_CLOCK_GETTIME - // Clock ID (CLOCK_REALTIME or CLOCK_MONOTONIC) associated with - // the condition variable. - clockid_t clk_id; -#endif -} mythread_cond; - -typedef struct timespec mythread_condtime; - - -// Calls the given function once in a thread-safe way. -#define mythread_once(func) \ - do { \ - static pthread_once_t once_ = PTHREAD_ONCE_INIT; \ - pthread_once(&once_, &func); \ - } while (0) - - -// Use pthread_sigmask() to set the signal mask in multi-threaded programs. -// Do nothing on OpenVMS since it lacks pthread_sigmask(). -static inline void -mythread_sigmask(int how, const sigset_t *restrict set, - sigset_t *restrict oset) -{ -#ifdef __VMS - (void)how; - (void)set; - (void)oset; -#else - int ret = pthread_sigmask(how, set, oset); - assert(ret == 0); - (void)ret; -#endif -} - - -// Creates a new thread with all signals blocked. Returns zero on success -// and non-zero on error. -static inline int -mythread_create(mythread *thread, void *(*func)(void *arg), void *arg) -{ - sigset_t old; - sigset_t all; - sigfillset(&all); - - mythread_sigmask(SIG_SETMASK, &all, &old); - const int ret = pthread_create(thread, NULL, func, arg); - mythread_sigmask(SIG_SETMASK, &old, NULL); - - return ret; -} - -// Joins a thread. Returns zero on success and non-zero on error. -static inline int -mythread_join(mythread thread) -{ - return pthread_join(thread, NULL); -} - - -// Initiatlizes a mutex. Returns zero on success and non-zero on error. -static inline int -mythread_mutex_init(mythread_mutex *mutex) -{ - return pthread_mutex_init(mutex, NULL); -} - -static inline void -mythread_mutex_destroy(mythread_mutex *mutex) -{ - int ret = pthread_mutex_destroy(mutex); - assert(ret == 0); - (void)ret; -} - -static inline void -mythread_mutex_lock(mythread_mutex *mutex) -{ - int ret = pthread_mutex_lock(mutex); - assert(ret == 0); - (void)ret; -} - -static inline void -mythread_mutex_unlock(mythread_mutex *mutex) -{ - int ret = pthread_mutex_unlock(mutex); - assert(ret == 0); - (void)ret; -} - - -// Initializes a condition variable. -// -// Using CLOCK_MONOTONIC instead of the default CLOCK_REALTIME makes the -// timeout in pthread_cond_timedwait() work correctly also if system time -// is suddenly changed. Unfortunately CLOCK_MONOTONIC isn't available -// everywhere while the default CLOCK_REALTIME is, so the default is -// used if CLOCK_MONOTONIC isn't available. -// -// If clock_gettime() isn't available at all, gettimeofday() will be used. -static inline int -mythread_cond_init(mythread_cond *mycond) -{ -#ifdef HAVE_CLOCK_GETTIME - // NOTE: HAVE_DECL_CLOCK_MONOTONIC is always defined to 0 or 1. -# if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && HAVE_DECL_CLOCK_MONOTONIC - struct timespec ts; - pthread_condattr_t condattr; - - // POSIX doesn't seem to *require* that pthread_condattr_setclock() - // will fail if given an unsupported clock ID. Test that - // CLOCK_MONOTONIC really is supported using clock_gettime(). - if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0 - && pthread_condattr_init(&condattr) == 0) { - int ret = pthread_condattr_setclock( - &condattr, CLOCK_MONOTONIC); - if (ret == 0) - ret = pthread_cond_init(&mycond->cond, &condattr); - - pthread_condattr_destroy(&condattr); - - if (ret == 0) { - mycond->clk_id = CLOCK_MONOTONIC; - return 0; - } - } - - // If anything above fails, fall back to the default CLOCK_REALTIME. - // POSIX requires that all implementations of clock_gettime() must - // support at least CLOCK_REALTIME. -# endif - - mycond->clk_id = CLOCK_REALTIME; -#endif - - return pthread_cond_init(&mycond->cond, NULL); -} - -static inline void -mythread_cond_destroy(mythread_cond *cond) -{ - int ret = pthread_cond_destroy(&cond->cond); - assert(ret == 0); - (void)ret; -} - -static inline void -mythread_cond_signal(mythread_cond *cond) -{ - int ret = pthread_cond_signal(&cond->cond); - assert(ret == 0); - (void)ret; -} - -static inline void -mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex) -{ - int ret = pthread_cond_wait(&cond->cond, mutex); - assert(ret == 0); - (void)ret; -} - -// Waits on a condition or until a timeout expires. If the timeout expires, -// non-zero is returned, otherwise zero is returned. -static inline int -mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex, - const mythread_condtime *condtime) -{ - int ret = pthread_cond_timedwait(&cond->cond, mutex, condtime); - assert(ret == 0 || ret == ETIMEDOUT); - return ret; -} - -// Sets condtime to the absolute time that is timeout_ms milliseconds -// in the future. The type of the clock to use is taken from cond. -static inline void -mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond, - uint32_t timeout_ms) -{ - condtime->tv_sec = timeout_ms / 1000; - condtime->tv_nsec = (timeout_ms % 1000) * 1000000; - -#ifdef HAVE_CLOCK_GETTIME - struct timespec now; - int ret = clock_gettime(cond->clk_id, &now); - assert(ret == 0); - (void)ret; - - condtime->tv_sec += now.tv_sec; - condtime->tv_nsec += now.tv_nsec; -#else - (void)cond; - - struct timeval now; - gettimeofday(&now, NULL); - - condtime->tv_sec += now.tv_sec; - condtime->tv_nsec += now.tv_usec * 1000L; -#endif - - // tv_nsec must stay in the range [0, 999_999_999]. - if (condtime->tv_nsec >= 1000000000L) { - condtime->tv_nsec -= 1000000000L; - ++condtime->tv_sec; - } -} - - -#elif defined(MYTHREAD_WIN95) || defined(MYTHREAD_VISTA) - -///////////////////// -// Windows threads // -///////////////////// - -#define WIN32_LEAN_AND_MEAN -#ifdef MYTHREAD_VISTA -# undef _WIN32_WINNT -# define _WIN32_WINNT 0x0600 -#endif -#include <windows.h> -#include <process.h> - -#define MYTHREAD_RET_TYPE unsigned int __stdcall -#define MYTHREAD_RET_VALUE 0 - -typedef HANDLE mythread; -typedef CRITICAL_SECTION mythread_mutex; - -#ifdef MYTHREAD_WIN95 -typedef HANDLE mythread_cond; -#else -typedef CONDITION_VARIABLE mythread_cond; -#endif - -typedef struct { - // Tick count (milliseconds) in the beginning of the timeout. - // NOTE: This is 32 bits so it wraps around after 49.7 days. - // Multi-day timeouts may not work as expected. - DWORD start; - - // Length of the timeout in milliseconds. The timeout expires - // when the current tick count minus "start" is equal or greater - // than "timeout". - DWORD timeout; -} mythread_condtime; - - -// mythread_once() is only available with Vista threads. -#ifdef MYTHREAD_VISTA -#define mythread_once(func) \ - do { \ - static INIT_ONCE once_ = INIT_ONCE_STATIC_INIT; \ - BOOL pending_; \ - if (!InitOnceBeginInitialize(&once_, 0, &pending_, NULL)) \ - abort(); \ - if (pending_) \ - func(); \ - if (!InitOnceComplete(&once, 0, NULL)) \ - abort(); \ - } while (0) -#endif - - -// mythread_sigmask() isn't available on Windows. Even a dummy version would -// make no sense because the other POSIX signal functions are missing anyway. - - -static inline int -mythread_create(mythread *thread, - unsigned int (__stdcall *func)(void *arg), void *arg) -{ - uintptr_t ret = _beginthreadex(NULL, 0, func, arg, 0, NULL); - if (ret == 0) - return -1; - - *thread = (HANDLE)ret; - return 0; -} - -static inline int -mythread_join(mythread thread) -{ - int ret = 0; - - if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0) - ret = -1; - - if (!CloseHandle(thread)) - ret = -1; - - return ret; -} - - -static inline int -mythread_mutex_init(mythread_mutex *mutex) -{ - InitializeCriticalSection(mutex); - return 0; -} - -static inline void -mythread_mutex_destroy(mythread_mutex *mutex) -{ - DeleteCriticalSection(mutex); -} - -static inline void -mythread_mutex_lock(mythread_mutex *mutex) -{ - EnterCriticalSection(mutex); -} - -static inline void -mythread_mutex_unlock(mythread_mutex *mutex) -{ - LeaveCriticalSection(mutex); -} - - -static inline int -mythread_cond_init(mythread_cond *cond) -{ -#ifdef MYTHREAD_WIN95 - *cond = CreateEvent(NULL, FALSE, FALSE, NULL); - return *cond == NULL ? -1 : 0; -#else - InitializeConditionVariable(cond); - return 0; -#endif -} - -static inline void -mythread_cond_destroy(mythread_cond *cond) -{ -#ifdef MYTHREAD_WIN95 - CloseHandle(*cond); -#else - (void)cond; -#endif -} - -static inline void -mythread_cond_signal(mythread_cond *cond) -{ -#ifdef MYTHREAD_WIN95 - SetEvent(*cond); -#else - WakeConditionVariable(cond); -#endif -} - -static inline void -mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex) -{ -#ifdef MYTHREAD_WIN95 - LeaveCriticalSection(mutex); - WaitForSingleObject(*cond, INFINITE); - EnterCriticalSection(mutex); -#else - BOOL ret = SleepConditionVariableCS(cond, mutex, INFINITE); - assert(ret); - (void)ret; -#endif -} - -static inline int -mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex, - const mythread_condtime *condtime) -{ -#ifdef MYTHREAD_WIN95 - LeaveCriticalSection(mutex); -#endif - - DWORD elapsed = GetTickCount() - condtime->start; - DWORD timeout = elapsed >= condtime->timeout - ? 0 : condtime->timeout - elapsed; - -#ifdef MYTHREAD_WIN95 - DWORD ret = WaitForSingleObject(*cond, timeout); - assert(ret == WAIT_OBJECT_0 || ret == WAIT_TIMEOUT); - - EnterCriticalSection(mutex); - - return ret == WAIT_TIMEOUT; -#else - BOOL ret = SleepConditionVariableCS(cond, mutex, timeout); - assert(ret || GetLastError() == ERROR_TIMEOUT); - return !ret; -#endif -} - -static inline void -mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond, - uint32_t timeout) -{ - (void)cond; - condtime->start = GetTickCount(); - condtime->timeout = timeout; -} - -#endif - -#endif +/////////////////////////////////////////////////////////////////////////////// +// +/// \file mythread.h +/// \brief Some threading related helper macros and functions +// +// Author: Lasse Collin +// +// This file has been put into the public domain. +// You can do whatever you want with this file. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef MYTHREAD_H +#define MYTHREAD_H + +#include "sysdefs.h" + +// If any type of threading is enabled, #define MYTHREAD_ENABLED. +#if defined(MYTHREAD_POSIX) || defined(MYTHREAD_WIN95) \ + || defined(MYTHREAD_VISTA) +# define MYTHREAD_ENABLED 1 +#endif + + +#ifdef MYTHREAD_ENABLED + +//////////////////////////////////////// +// Shared between all threading types // +//////////////////////////////////////// + +// Locks a mutex for a duration of a block. +// +// Perform mythread_mutex_lock(&mutex) in the beginning of a block +// and mythread_mutex_unlock(&mutex) at the end of the block. "break" +// may be used to unlock the mutex and jump out of the block. +// mythread_sync blocks may be nested. +// +// Example: +// +// mythread_sync(mutex) { +// foo(); +// if (some_error) +// break; // Skips bar() +// bar(); +// } +// +// At least GCC optimizes the loops completely away so it doesn't slow +// things down at all compared to plain mythread_mutex_lock(&mutex) +// and mythread_mutex_unlock(&mutex) calls. +// +#define mythread_sync(mutex) mythread_sync_helper1(mutex, __LINE__) +#define mythread_sync_helper1(mutex, line) mythread_sync_helper2(mutex, line) +#define mythread_sync_helper2(mutex, line) \ + for (unsigned int mythread_i_ ## line = 0; \ + mythread_i_ ## line \ + ? (mythread_mutex_unlock(&(mutex)), 0) \ + : (mythread_mutex_lock(&(mutex)), 1); \ + mythread_i_ ## line = 1) \ + for (unsigned int mythread_j_ ## line = 0; \ + !mythread_j_ ## line; \ + mythread_j_ ## line = 1) +#endif + + +#if !defined(MYTHREAD_ENABLED) + +////////////////// +// No threading // +////////////////// + +// Calls the given function once. This isn't thread safe. +#define mythread_once(func) \ +do { \ + static bool once_ = false; \ + if (!once_) { \ + func(); \ + once_ = true; \ + } \ +} while (0) + + +#if !(defined(_WIN32) && !defined(__CYGWIN__)) +// Use sigprocmask() to set the signal mask in single-threaded programs. +#include <signal.h> + +static inline void +mythread_sigmask(int how, const sigset_t *restrict set, + sigset_t *restrict oset) +{ + int ret = sigprocmask(how, set, oset); + assert(ret == 0); + (void)ret; +} +#endif + + +#elif defined(MYTHREAD_POSIX) + +//////////////////// +// Using pthreads // +//////////////////// + +#include <sys/time.h> +#include <pthread.h> +#include <signal.h> +#include <time.h> +#include <errno.h> + +#define MYTHREAD_RET_TYPE void * +#define MYTHREAD_RET_VALUE NULL + +typedef pthread_t mythread; +typedef pthread_mutex_t mythread_mutex; + +typedef struct { + pthread_cond_t cond; +#ifdef HAVE_CLOCK_GETTIME + // Clock ID (CLOCK_REALTIME or CLOCK_MONOTONIC) associated with + // the condition variable. + clockid_t clk_id; +#endif +} mythread_cond; + +typedef struct timespec mythread_condtime; + + +// Calls the given function once in a thread-safe way. +#define mythread_once(func) \ + do { \ + static pthread_once_t once_ = PTHREAD_ONCE_INIT; \ + pthread_once(&once_, &func); \ + } while (0) + + +// Use pthread_sigmask() to set the signal mask in multi-threaded programs. +// Do nothing on OpenVMS since it lacks pthread_sigmask(). +static inline void +mythread_sigmask(int how, const sigset_t *restrict set, + sigset_t *restrict oset) +{ +#ifdef __VMS + (void)how; + (void)set; + (void)oset; +#else + int ret = pthread_sigmask(how, set, oset); + assert(ret == 0); + (void)ret; +#endif +} + + +// Creates a new thread with all signals blocked. Returns zero on success +// and non-zero on error. +static inline int +mythread_create(mythread *thread, void *(*func)(void *arg), void *arg) +{ + sigset_t old; + sigset_t all; + sigfillset(&all); + + mythread_sigmask(SIG_SETMASK, &all, &old); + const int ret = pthread_create(thread, NULL, func, arg); + mythread_sigmask(SIG_SETMASK, &old, NULL); + + return ret; +} + +// Joins a thread. Returns zero on success and non-zero on error. +static inline int +mythread_join(mythread thread) +{ + return pthread_join(thread, NULL); +} + + +// Initiatlizes a mutex. Returns zero on success and non-zero on error. +static inline int +mythread_mutex_init(mythread_mutex *mutex) +{ + return pthread_mutex_init(mutex, NULL); +} + +static inline void +mythread_mutex_destroy(mythread_mutex *mutex) +{ + int ret = pthread_mutex_destroy(mutex); + assert(ret == 0); + (void)ret; +} + +static inline void +mythread_mutex_lock(mythread_mutex *mutex) +{ + int ret = pthread_mutex_lock(mutex); + assert(ret == 0); + (void)ret; +} + +static inline void +mythread_mutex_unlock(mythread_mutex *mutex) +{ + int ret = pthread_mutex_unlock(mutex); + assert(ret == 0); + (void)ret; +} + + +// Initializes a condition variable. +// +// Using CLOCK_MONOTONIC instead of the default CLOCK_REALTIME makes the +// timeout in pthread_cond_timedwait() work correctly also if system time +// is suddenly changed. Unfortunately CLOCK_MONOTONIC isn't available +// everywhere while the default CLOCK_REALTIME is, so the default is +// used if CLOCK_MONOTONIC isn't available. +// +// If clock_gettime() isn't available at all, gettimeofday() will be used. +static inline int +mythread_cond_init(mythread_cond *mycond) +{ +#ifdef HAVE_CLOCK_GETTIME + // NOTE: HAVE_DECL_CLOCK_MONOTONIC is always defined to 0 or 1. +# if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && HAVE_DECL_CLOCK_MONOTONIC + struct timespec ts; + pthread_condattr_t condattr; + + // POSIX doesn't seem to *require* that pthread_condattr_setclock() + // will fail if given an unsupported clock ID. Test that + // CLOCK_MONOTONIC really is supported using clock_gettime(). + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0 + && pthread_condattr_init(&condattr) == 0) { + int ret = pthread_condattr_setclock( + &condattr, CLOCK_MONOTONIC); + if (ret == 0) + ret = pthread_cond_init(&mycond->cond, &condattr); + + pthread_condattr_destroy(&condattr); + + if (ret == 0) { + mycond->clk_id = CLOCK_MONOTONIC; + return 0; + } + } + + // If anything above fails, fall back to the default CLOCK_REALTIME. + // POSIX requires that all implementations of clock_gettime() must + // support at least CLOCK_REALTIME. +# endif + + mycond->clk_id = CLOCK_REALTIME; +#endif + + return pthread_cond_init(&mycond->cond, NULL); +} + +static inline void +mythread_cond_destroy(mythread_cond *cond) +{ + int ret = pthread_cond_destroy(&cond->cond); + assert(ret == 0); + (void)ret; +} + +static inline void +mythread_cond_signal(mythread_cond *cond) +{ + int ret = pthread_cond_signal(&cond->cond); + assert(ret == 0); + (void)ret; +} + +static inline void +mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex) +{ + int ret = pthread_cond_wait(&cond->cond, mutex); + assert(ret == 0); + (void)ret; +} + +// Waits on a condition or until a timeout expires. If the timeout expires, +// non-zero is returned, otherwise zero is returned. +static inline int +mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex, + const mythread_condtime *condtime) +{ + int ret = pthread_cond_timedwait(&cond->cond, mutex, condtime); + assert(ret == 0 || ret == ETIMEDOUT); + return ret; +} + +// Sets condtime to the absolute time that is timeout_ms milliseconds +// in the future. The type of the clock to use is taken from cond. +static inline void +mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond, + uint32_t timeout_ms) +{ + condtime->tv_sec = timeout_ms / 1000; + condtime->tv_nsec = (timeout_ms % 1000) * 1000000; + +#ifdef HAVE_CLOCK_GETTIME + struct timespec now; + int ret = clock_gettime(cond->clk_id, &now); + assert(ret == 0); + (void)ret; + + condtime->tv_sec += now.tv_sec; + condtime->tv_nsec += now.tv_nsec; +#else + (void)cond; + + struct timeval now; + gettimeofday(&now, NULL); + + condtime->tv_sec += now.tv_sec; + condtime->tv_nsec += now.tv_usec * 1000L; +#endif + + // tv_nsec must stay in the range [0, 999_999_999]. + if (condtime->tv_nsec >= 1000000000L) { + condtime->tv_nsec -= 1000000000L; + ++condtime->tv_sec; + } +} + + +#elif defined(MYTHREAD_WIN95) || defined(MYTHREAD_VISTA) + +///////////////////// +// Windows threads // +///////////////////// + +#define WIN32_LEAN_AND_MEAN +#ifdef MYTHREAD_VISTA +# undef _WIN32_WINNT +# define _WIN32_WINNT 0x0600 +#endif +#include <windows.h> +#include <process.h> + +#define MYTHREAD_RET_TYPE unsigned int __stdcall +#define MYTHREAD_RET_VALUE 0 + +typedef HANDLE mythread; +typedef CRITICAL_SECTION mythread_mutex; + +#ifdef MYTHREAD_WIN95 +typedef HANDLE mythread_cond; +#else +typedef CONDITION_VARIABLE mythread_cond; +#endif + +typedef struct { + // Tick count (milliseconds) in the beginning of the timeout. + // NOTE: This is 32 bits so it wraps around after 49.7 days. + // Multi-day timeouts may not work as expected. + DWORD start; + + // Length of the timeout in milliseconds. The timeout expires + // when the current tick count minus "start" is equal or greater + // than "timeout". + DWORD timeout; +} mythread_condtime; + + +// mythread_once() is only available with Vista threads. +#ifdef MYTHREAD_VISTA +#define mythread_once(func) \ + do { \ + static INIT_ONCE once_ = INIT_ONCE_STATIC_INIT; \ + BOOL pending_; \ + if (!InitOnceBeginInitialize(&once_, 0, &pending_, NULL)) \ + abort(); \ + if (pending_) \ + func(); \ + if (!InitOnceComplete(&once, 0, NULL)) \ + abort(); \ + } while (0) +#endif + + +// mythread_sigmask() isn't available on Windows. Even a dummy version would +// make no sense because the other POSIX signal functions are missing anyway. + + +static inline int +mythread_create(mythread *thread, + unsigned int (__stdcall *func)(void *arg), void *arg) +{ + uintptr_t ret = _beginthreadex(NULL, 0, func, arg, 0, NULL); + if (ret == 0) + return -1; + + *thread = (HANDLE)ret; + return 0; +} + +static inline int +mythread_join(mythread thread) +{ + int ret = 0; + + if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0) + ret = -1; + + if (!CloseHandle(thread)) + ret = -1; + + return ret; +} + + +static inline int +mythread_mutex_init(mythread_mutex *mutex) +{ + InitializeCriticalSection(mutex); + return 0; +} + +static inline void +mythread_mutex_destroy(mythread_mutex *mutex) +{ + DeleteCriticalSection(mutex); +} + +static inline void +mythread_mutex_lock(mythread_mutex *mutex) +{ + EnterCriticalSection(mutex); +} + +static inline void +mythread_mutex_unlock(mythread_mutex *mutex) +{ + LeaveCriticalSection(mutex); +} + + +static inline int +mythread_cond_init(mythread_cond *cond) +{ +#ifdef MYTHREAD_WIN95 + *cond = CreateEvent(NULL, FALSE, FALSE, NULL); + return *cond == NULL ? -1 : 0; +#else + InitializeConditionVariable(cond); + return 0; +#endif +} + +static inline void +mythread_cond_destroy(mythread_cond *cond) +{ +#ifdef MYTHREAD_WIN95 + CloseHandle(*cond); +#else + (void)cond; +#endif +} + +static inline void +mythread_cond_signal(mythread_cond *cond) +{ +#ifdef MYTHREAD_WIN95 + SetEvent(*cond); +#else + WakeConditionVariable(cond); +#endif +} + +static inline void +mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex) +{ +#ifdef MYTHREAD_WIN95 + LeaveCriticalSection(mutex); + WaitForSingleObject(*cond, INFINITE); + EnterCriticalSection(mutex); +#else + BOOL ret = SleepConditionVariableCS(cond, mutex, INFINITE); + assert(ret); + (void)ret; +#endif +} + +static inline int +mythread_cond_timedwait(mythread_cond *cond, mythread_mutex *mutex, + const mythread_condtime *condtime) +{ +#ifdef MYTHREAD_WIN95 + LeaveCriticalSection(mutex); +#endif + + DWORD elapsed = GetTickCount() - condtime->start; + DWORD timeout = elapsed >= condtime->timeout + ? 0 : condtime->timeout - elapsed; + +#ifdef MYTHREAD_WIN95 + DWORD ret = WaitForSingleObject(*cond, timeout); + assert(ret == WAIT_OBJECT_0 || ret == WAIT_TIMEOUT); + + EnterCriticalSection(mutex); + + return ret == WAIT_TIMEOUT; +#else + BOOL ret = SleepConditionVariableCS(cond, mutex, timeout); + assert(ret || GetLastError() == ERROR_TIMEOUT); + return !ret; +#endif +} + +static inline void +mythread_condtime_set(mythread_condtime *condtime, const mythread_cond *cond, + uint32_t timeout) +{ + (void)cond; + condtime->start = GetTickCount(); + condtime->timeout = timeout; +} + +#endif + +#endif |