| mythread.h | mythread.h | |||
|---|---|---|---|---|
| skipping to change at line 18 | skipping to change at line 18 | |||
| // This file has been put into the public domain. | // This file has been put into the public domain. | |||
| // You can do whatever you want with this file. | // You can do whatever you want with this file. | |||
| // | // | |||
| /////////////////////////////////////////////////////////////////////////// //// | /////////////////////////////////////////////////////////////////////////// //// | |||
| #ifndef MYTHREAD_H | #ifndef MYTHREAD_H | |||
| #define MYTHREAD_H | #define MYTHREAD_H | |||
| #include "sysdefs.h" | #include "sysdefs.h" | |||
| #ifdef HAVE_PTHREAD | // 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, lin | ||||
| e) | ||||
| #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 // | // Using pthreads // | |||
| //////////////////// | //////////////////// | |||
| #include <sys/time.h> | #include <sys/time.h> | |||
| #include <pthread.h> | #include <pthread.h> | |||
| #include <signal.h> | #include <signal.h> | |||
| #include <time.h> | #include <time.h> | |||
| #include <errno.h> | ||||
| #ifdef __VMS | #define MYTHREAD_RET_TYPE void * | |||
| // Do nothing on OpenVMS. It doesn't have pthread_sigmask(). | #define MYTHREAD_RET_VALUE NULL | |||
| #define mythread_sigmask(how, set, oset) do { } while (0) | ||||
| #else | ||||
| /// \brief Set the process signal mask | ||||
| /// | ||||
| /// If threads are disabled, sigprocmask() is used instead | ||||
| /// of pthread_sigmask(). | ||||
| #define mythread_sigmask(how, set, oset) \ | ||||
| pthread_sigmask(how, set, oset) | ||||
| #endif | ||||
| /// \brief Call the given function once | ||||
| /// | ||||
| /// If threads are disabled, a thread-unsafe version is used. | ||||
| #define mythread_once(func) \ | ||||
| do { \ | ||||
| static pthread_once_t once_ = PTHREAD_ONCE_INIT; \ | ||||
| pthread_once(&once_, &func); \ | ||||
| } while (0) | ||||
| /// \brief Lock a mutex for a duration of a block | typedef pthread_t mythread; | |||
| /// | typedef pthread_mutex_t mythread_mutex; | |||
| /// Perform pthread_mutex_lock(&mutex) in the beginning of a block | ||||
| /// and pthread_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 pthread_mutex_lock(&mutex) | ||||
| /// and pthread_mutex_unlock(&mutex) calls. | ||||
| /// | ||||
| #define mythread_sync(mutex) mythread_sync_helper(mutex, __LINE__) | ||||
| #define mythread_sync_helper(mutex, line) \ | ||||
| for (unsigned int mythread_i_ ## line = 0; \ | ||||
| mythread_i_ ## line \ | ||||
| ? (pthread_mutex_unlock(&(mutex)), 0) \ | ||||
| : (pthread_mutex_lock(&(mutex)), 1); \ | ||||
| mythread_i_ ## line = 1) \ | ||||
| for (unsigned int mythread_j_ ## line = 0; \ | ||||
| !mythread_j_ ## line; \ | ||||
| mythread_j_ ## line = 1) | ||||
| typedef struct { | typedef struct { | |||
| /// Condition variable | ||||
| pthread_cond_t cond; | pthread_cond_t cond; | |||
| #ifdef HAVE_CLOCK_GETTIME | #ifdef HAVE_CLOCK_GETTIME | |||
| /// Clock ID (CLOCK_REALTIME or CLOCK_MONOTONIC) associated with | // Clock ID (CLOCK_REALTIME or CLOCK_MONOTONIC) associated with | |||
| /// the condition variable | // the condition variable. | |||
| clockid_t clk_id; | clockid_t clk_id; | |||
| #endif | #endif | |||
| } mythread_cond; | } mythread_cond; | |||
| /// \brief Initialize a condition variable to use CLOCK_MONOTONIC | typedef struct timespec mythread_condtime; | |||
| /// | ||||
| /// Using CLOCK_MONOTONIC instead of the default CLOCK_REALTIME makes the | // Calls the given function once in a thread-safe way. | |||
| /// timeout in pthread_cond_timedwait() work correctly also if system time | #define mythread_once(func) \ | |||
| /// is suddenly changed. Unfortunately CLOCK_MONOTONIC isn't available | do { \ | |||
| /// everywhere while the default CLOCK_REALTIME is, so the default is | static pthread_once_t once_ = PTHREAD_ONCE_INIT; \ | |||
| /// used if CLOCK_MONOTONIC isn't available. | 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 | static inline int | |||
| mythread_cond_init(mythread_cond *mycond) | mythread_cond_init(mythread_cond *mycond) | |||
| { | { | |||
| #ifdef HAVE_CLOCK_GETTIME | #ifdef HAVE_CLOCK_GETTIME | |||
| // NOTE: HAVE_DECL_CLOCK_MONOTONIC is always defined to 0 or 1. | // NOTE: HAVE_DECL_CLOCK_MONOTONIC is always defined to 0 or 1. | |||
| # if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && HAVE_DECL_CLOCK_MONOTO NIC | # if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && HAVE_DECL_CLOCK_MONOTO NIC | |||
| struct timespec ts; | struct timespec ts; | |||
| pthread_condattr_t condattr; | pthread_condattr_t condattr; | |||
| // POSIX doesn't seem to *require* that pthread_condattr_setclock() | // POSIX doesn't seem to *require* that pthread_condattr_setclock() | |||
| skipping to change at line 128 | skipping to change at line 237 | |||
| pthread_condattr_destroy(&condattr); | pthread_condattr_destroy(&condattr); | |||
| if (ret == 0) { | if (ret == 0) { | |||
| mycond->clk_id = CLOCK_MONOTONIC; | mycond->clk_id = CLOCK_MONOTONIC; | |||
| return 0; | return 0; | |||
| } | } | |||
| } | } | |||
| // If anything above fails, fall back to the default CLOCK_REALTIME. | // 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 | # endif | |||
| mycond->clk_id = CLOCK_REALTIME; | mycond->clk_id = CLOCK_REALTIME; | |||
| #endif | #endif | |||
| return pthread_cond_init(&mycond->cond, NULL); | return pthread_cond_init(&mycond->cond, NULL); | |||
| } | } | |||
| /// \brief Convert relative time to absolute time for use with timed w | ||||
| ait | ||||
| /// | ||||
| /// The current time of the clock associated with the condition variable | ||||
| /// is added to the relative time in *ts. | ||||
| static inline void | static inline void | |||
| mythread_cond_abstime(const mythread_cond *mycond, struct timespec *ts) | 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 *con | ||||
| d, | ||||
| uint32_t timeout_ms) | ||||
| { | ||||
| condtime->tv_sec = timeout_ms / 1000; | ||||
| condtime->tv_nsec = (timeout_ms % 1000) * 1000000; | ||||
| #ifdef HAVE_CLOCK_GETTIME | #ifdef HAVE_CLOCK_GETTIME | |||
| struct timespec now; | struct timespec now; | |||
| clock_gettime(mycond->clk_id, &now); | int ret = clock_gettime(cond->clk_id, &now); | |||
| assert(ret == 0); | ||||
| (void)ret; | ||||
| ts->tv_sec += now.tv_sec; | condtime->tv_sec += now.tv_sec; | |||
| ts->tv_nsec += now.tv_nsec; | condtime->tv_nsec += now.tv_nsec; | |||
| #else | #else | |||
| (void)mycond; | (void)cond; | |||
| struct timeval now; | struct timeval now; | |||
| gettimeofday(&now, NULL); | gettimeofday(&now, NULL); | |||
| ts->tv_sec += now.tv_sec; | condtime->tv_sec += now.tv_sec; | |||
| ts->tv_nsec += now.tv_usec * 1000L; | condtime->tv_nsec += now.tv_usec * 1000L; | |||
| #endif | #endif | |||
| // tv_nsec must stay in the range [0, 999_999_999]. | // tv_nsec must stay in the range [0, 999_999_999]. | |||
| if (ts->tv_nsec >= 1000000000L) { | if (condtime->tv_nsec >= 1000000000L) { | |||
| ts->tv_nsec -= 1000000000L; | condtime->tv_nsec -= 1000000000L; | |||
| ++ts->tv_sec; | ++condtime->tv_sec; | |||
| } | } | |||
| return; | ||||
| } | } | |||
| #define mythread_cond_wait(mycondptr, mutexptr) \ | #elif defined(MYTHREAD_WIN95) || defined(MYTHREAD_VISTA) | |||
| pthread_cond_wait(&(mycondptr)->cond, mutexptr) | ||||
| ///////////////////// | ||||
| // 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 | ||||
| #define mythread_cond_timedwait(mycondptr, mutexptr, abstimeptr) \ | typedef HANDLE mythread; | |||
| pthread_cond_timedwait(&(mycondptr)->cond, mutexptr, abstimeptr) | typedef CRITICAL_SECTION mythread_mutex; | |||
| #define mythread_cond_signal(mycondptr) \ | #ifdef MYTHREAD_WIN95 | |||
| pthread_cond_signal(&(mycondptr)->cond) | typedef HANDLE mythread_cond; | |||
| #else | ||||
| typedef CONDITION_VARIABLE mythread_cond; | ||||
| #endif | ||||
| #define mythread_cond_broadcast(mycondptr) \ | typedef struct { | |||
| pthread_cond_broadcast(&(mycondptr)->cond) | // 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; | ||||
| #define mythread_cond_destroy(mycondptr) \ | // mythread_once() is only available with Vista threads. | |||
| pthread_cond_destroy(&(mycondptr)->cond) | #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 woul | ||||
| d | ||||
| // make no sense because the other POSIX signal functions are missing anywa | ||||
| y. | ||||
| /// \brief Create a thread with all signals blocked | ||||
| static inline int | static inline int | |||
| mythread_create(pthread_t *thread, void *(*func)(void *arg), void *arg) | mythread_create(mythread *thread, | |||
| unsigned int (__stdcall *func)(void *arg), void *arg) | ||||
| { | { | |||
| sigset_t old; | uintptr_t ret = _beginthreadex(NULL, 0, func, arg, 0, NULL); | |||
| sigset_t all; | if (ret == 0) | |||
| sigfillset(&all); | return -1; | |||
| pthread_sigmask(SIG_SETMASK, &all, &old); | *thread = (HANDLE)ret; | |||
| const int ret = pthread_create(thread, NULL, func, arg); | return 0; | |||
| pthread_sigmask(SIG_SETMASK, &old, NULL); | } | |||
| 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; | 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 | #else | |||
| InitializeConditionVariable(cond); | ||||
| return 0; | ||||
| #endif | ||||
| } | ||||
| ////////////////// | static inline void | |||
| // No threading // | mythread_cond_destroy(mythread_cond *cond) | |||
| ////////////////// | { | |||
| #ifdef MYTHREAD_WIN95 | ||||
| CloseHandle(*cond); | ||||
| #else | ||||
| (void)cond; | ||||
| #endif | ||||
| } | ||||
| #define mythread_sigmask(how, set, oset) \ | static inline void | |||
| sigprocmask(how, set, oset) | mythread_cond_signal(mythread_cond *cond) | |||
| { | ||||
| #ifdef MYTHREAD_WIN95 | ||||
| SetEvent(*cond); | ||||
| #else | ||||
| WakeConditionVariable(cond); | ||||
| #endif | ||||
| } | ||||
| #define mythread_once(func) \ | static inline void | |||
| do { \ | mythread_cond_wait(mythread_cond *cond, mythread_mutex *mutex) | |||
| static bool once_ = false; \ | { | |||
| if (!once_) { \ | #ifdef MYTHREAD_WIN95 | |||
| func(); \ | LeaveCriticalSection(mutex); | |||
| once_ = true; \ | WaitForSingleObject(*cond, INFINITE); | |||
| } \ | EnterCriticalSection(mutex); | |||
| } while (0) | #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 *con | ||||
| d, | ||||
| uint32_t timeout) | ||||
| { | ||||
| (void)cond; | ||||
| condtime->start = GetTickCount(); | ||||
| condtime->timeout = timeout; | ||||
| } | ||||
| #endif | #endif | |||
| #endif | #endif | |||
| End of changes. 33 change blocks. | ||||
| 111 lines changed or deleted | 403 lines changed or added | |||
This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ | ||||