threads: update for late C11 changes
C11 threads were changed to use struct timespec instead of xtime, and thrd_sleep got a second argument. See http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1554.htm and http://en.cppreference.com/w/c/thread/{thrd_sleep,cnd_timedwait,mtx_timedlock} Note that cnd_timedwait is spec'd to be relative to TIME_UTC / CLOCK_REALTIME. v2: Fix Windows build errors. Tested with a default Appveyor config that uses Visual Studio 2013. Judging from Brian's email and random internet sources, Visual Studio 2015 does have timespec and timespec_get, hence the _MSC_VER-based guard which I have not tested. Cc: Jose Fonseca <jfonseca@vmware.com> Cc: Brian Paul <brianp@vmware.com> Reviewed-by: Marek Olšák <marek.olsak@amd.com> (v1)
This commit is contained in:
@@ -30,9 +30,6 @@
|
||||
#define EMULATED_THREADS_H_INCLUDED_
|
||||
|
||||
#include <time.h>
|
||||
#ifdef _MSC_VER
|
||||
#include <thr/xtimec.h> // for xtime
|
||||
#endif
|
||||
|
||||
#ifndef TIME_UTC
|
||||
#define TIME_UTC 1
|
||||
@@ -44,14 +41,6 @@
|
||||
typedef void (*tss_dtor_t)(void*);
|
||||
typedef int (*thrd_start_t)(void*);
|
||||
|
||||
#ifndef _MSC_VER
|
||||
struct xtime {
|
||||
time_t sec;
|
||||
long nsec;
|
||||
};
|
||||
typedef struct xtime xtime;
|
||||
#endif
|
||||
|
||||
|
||||
/*-------------------- enumeration constants --------------------*/
|
||||
enum {
|
||||
|
@@ -132,19 +132,15 @@ cnd_signal(cnd_t *cond)
|
||||
|
||||
// 7.25.3.5
|
||||
static inline int
|
||||
cnd_timedwait(cnd_t *cond, mtx_t *mtx, const xtime *xt)
|
||||
cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *abs_time)
|
||||
{
|
||||
struct timespec abs_time;
|
||||
int rt;
|
||||
|
||||
assert(mtx != NULL);
|
||||
assert(cond != NULL);
|
||||
assert(xt != NULL);
|
||||
assert(abs_time != NULL);
|
||||
|
||||
abs_time.tv_sec = xt->sec;
|
||||
abs_time.tv_nsec = xt->nsec;
|
||||
|
||||
rt = pthread_cond_timedwait(cond, mtx, &abs_time);
|
||||
rt = pthread_cond_timedwait(cond, mtx, abs_time);
|
||||
if (rt == ETIMEDOUT)
|
||||
return thrd_busy;
|
||||
return (rt == 0) ? thrd_success : thrd_error;
|
||||
@@ -235,24 +231,21 @@ thrd_yield(void);
|
||||
|
||||
// 7.25.4.4
|
||||
static inline int
|
||||
mtx_timedlock(mtx_t *mtx, const xtime *xt)
|
||||
mtx_timedlock(mtx_t *mtx, const struct timespec *ts)
|
||||
{
|
||||
assert(mtx != NULL);
|
||||
assert(xt != NULL);
|
||||
assert(ts != NULL);
|
||||
|
||||
{
|
||||
#ifdef EMULATED_THREADS_USE_NATIVE_TIMEDLOCK
|
||||
struct timespec ts;
|
||||
int rt;
|
||||
ts.tv_sec = xt->sec;
|
||||
ts.tv_nsec = xt->nsec;
|
||||
rt = pthread_mutex_timedlock(mtx, &ts);
|
||||
rt = pthread_mutex_timedlock(mtx, ts);
|
||||
if (rt == 0)
|
||||
return thrd_success;
|
||||
return (rt == ETIMEDOUT) ? thrd_busy : thrd_error;
|
||||
#else
|
||||
time_t expire = time(NULL);
|
||||
expire += xt->sec;
|
||||
expire += ts->tv_sec;
|
||||
while (mtx_trylock(mtx) != thrd_success) {
|
||||
time_t now = time(NULL);
|
||||
if (expire < now)
|
||||
@@ -342,13 +335,10 @@ thrd_join(thrd_t thr, int *res)
|
||||
|
||||
// 7.25.5.7
|
||||
static inline void
|
||||
thrd_sleep(const xtime *xt)
|
||||
thrd_sleep(const struct timespec *time_point, struct timespec *remaining)
|
||||
{
|
||||
struct timespec req;
|
||||
assert(xt);
|
||||
req.tv_sec = xt->sec;
|
||||
req.tv_nsec = xt->nsec;
|
||||
nanosleep(&req, NULL);
|
||||
assert(time_point != NULL);
|
||||
nanosleep(time_point, remaining);
|
||||
}
|
||||
|
||||
// 7.25.5.8
|
||||
@@ -392,14 +382,15 @@ tss_set(tss_t key, void *val)
|
||||
|
||||
/*-------------------- 7.25.7 Time functions --------------------*/
|
||||
// 7.25.6.1
|
||||
#if 0
|
||||
static inline int
|
||||
xtime_get(xtime *xt, int base)
|
||||
timespec_get(struct timespec *ts, int base)
|
||||
{
|
||||
if (!xt) return 0;
|
||||
if (!ts) return 0;
|
||||
if (base == TIME_UTC) {
|
||||
xt->sec = time(NULL);
|
||||
xt->nsec = 0;
|
||||
clock_gettime(CLOCK_REALTIME, ts);
|
||||
return base;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@@ -75,6 +75,17 @@ Configuration macro:
|
||||
#error EMULATED_THREADS_USE_NATIVE_CV requires _WIN32_WINNT>=0x0600
|
||||
#endif
|
||||
|
||||
/* Visual Studio 2015 and later */
|
||||
#if _MSC_VER >= 1900
|
||||
#define HAVE_TIMESPEC
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_TIMESPEC
|
||||
struct timespec {
|
||||
time_t tv_sec;
|
||||
long tv_nsec;
|
||||
};
|
||||
#endif
|
||||
|
||||
/*---------------------------- macros ----------------------------*/
|
||||
#ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE
|
||||
@@ -146,9 +157,9 @@ static unsigned __stdcall impl_thrd_routine(void *p)
|
||||
return (unsigned)code;
|
||||
}
|
||||
|
||||
static DWORD impl_xtime2msec(const xtime *xt)
|
||||
static DWORD impl_timespec2msec(const struct timespec *ts)
|
||||
{
|
||||
return (DWORD)((xt->sec * 1000U) + (xt->nsec / 1000000L));
|
||||
return (DWORD)((ts->tv_sec * 1000U) + (ts->tv_nsec / 1000000L));
|
||||
}
|
||||
|
||||
#ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE
|
||||
@@ -206,7 +217,7 @@ static void impl_cond_do_signal(cnd_t *cond, int broadcast)
|
||||
ReleaseSemaphore(cond->sem_queue, nsignal, NULL);
|
||||
}
|
||||
|
||||
static int impl_cond_do_wait(cnd_t *cond, mtx_t *mtx, const xtime *xt)
|
||||
static int impl_cond_do_wait(cnd_t *cond, mtx_t *mtx, const struct timespec *ts)
|
||||
{
|
||||
int nleft = 0;
|
||||
int ngone = 0;
|
||||
@@ -219,7 +230,7 @@ static int impl_cond_do_wait(cnd_t *cond, mtx_t *mtx, const xtime *xt)
|
||||
|
||||
mtx_unlock(mtx);
|
||||
|
||||
w = WaitForSingleObject(cond->sem_queue, xt ? impl_xtime2msec(xt) : INFINITE);
|
||||
w = WaitForSingleObject(cond->sem_queue, ts ? impl_timespec2msec(ts) : INFINITE);
|
||||
timeout = (w == WAIT_TIMEOUT);
|
||||
|
||||
EnterCriticalSection(&cond->monitor);
|
||||
@@ -378,15 +389,15 @@ cnd_signal(cnd_t *cond)
|
||||
|
||||
// 7.25.3.5
|
||||
static inline int
|
||||
cnd_timedwait(cnd_t *cond, mtx_t *mtx, const xtime *xt)
|
||||
cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *abs_time)
|
||||
{
|
||||
if (!cond || !mtx || !xt) return thrd_error;
|
||||
if (!cond || !mtx || !abs_time) return thrd_error;
|
||||
#ifdef EMULATED_THREADS_USE_NATIVE_CV
|
||||
if (SleepConditionVariableCS(&cond->condvar, mtx, impl_xtime2msec(xt)))
|
||||
if (SleepConditionVariableCS(&cond->condvar, mtx, impl_timespec2msec(abs_time)))
|
||||
return thrd_success;
|
||||
return (GetLastError() == ERROR_TIMEOUT) ? thrd_busy : thrd_error;
|
||||
#else
|
||||
return impl_cond_do_wait(cond, mtx, xt);
|
||||
return impl_cond_do_wait(cond, mtx, abs_time);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -438,12 +449,12 @@ mtx_lock(mtx_t *mtx)
|
||||
|
||||
// 7.25.4.4
|
||||
static inline int
|
||||
mtx_timedlock(mtx_t *mtx, const xtime *xt)
|
||||
mtx_timedlock(mtx_t *mtx, const struct timespec *ts)
|
||||
{
|
||||
time_t expire, now;
|
||||
if (!mtx || !xt) return thrd_error;
|
||||
if (!mtx || !ts) return thrd_error;
|
||||
expire = time(NULL);
|
||||
expire += xt->sec;
|
||||
expire += ts->tv_sec;
|
||||
while (mtx_trylock(mtx) != thrd_success) {
|
||||
now = time(NULL);
|
||||
if (expire < now)
|
||||
@@ -579,10 +590,11 @@ thrd_join(thrd_t thr, int *res)
|
||||
|
||||
// 7.25.5.7
|
||||
static inline void
|
||||
thrd_sleep(const xtime *xt)
|
||||
thrd_sleep(const struct timespec *time_point, struct timespec *remaining)
|
||||
{
|
||||
assert(xt);
|
||||
Sleep(impl_xtime2msec(xt));
|
||||
assert(time_point);
|
||||
assert(!remaining); /* not implemented */
|
||||
Sleep(impl_timespec2msec(time_point));
|
||||
}
|
||||
|
||||
// 7.25.5.8
|
||||
@@ -633,14 +645,16 @@ tss_set(tss_t key, void *val)
|
||||
|
||||
/*-------------------- 7.25.7 Time functions --------------------*/
|
||||
// 7.25.6.1
|
||||
#ifndef HAVE_TIMESPEC
|
||||
static inline int
|
||||
xtime_get(xtime *xt, int base)
|
||||
timespec_get(struct timespec *ts, int base)
|
||||
{
|
||||
if (!xt) return 0;
|
||||
if (!ts) return 0;
|
||||
if (base == TIME_UTC) {
|
||||
xt->sec = time(NULL);
|
||||
xt->nsec = 0;
|
||||
ts->tv_sec = time(NULL);
|
||||
ts->tv_nsec = 0;
|
||||
return base;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@@ -3064,10 +3064,6 @@ dri2_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
|
||||
struct dri2_egl_sync *dri2_sync = dri2_egl_sync(sync);
|
||||
unsigned wait_flags = 0;
|
||||
|
||||
/* timespecs for cnd_timedwait */
|
||||
struct timespec current;
|
||||
xtime expire;
|
||||
|
||||
EGLint ret = EGL_CONDITION_SATISFIED_KHR;
|
||||
|
||||
/* The EGL_KHR_fence_sync spec states:
|
||||
@@ -3108,19 +3104,25 @@ dri2_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
|
||||
} else {
|
||||
/* if reusable sync has not been yet signaled */
|
||||
if (dri2_sync->base.SyncStatus != EGL_SIGNALED_KHR) {
|
||||
/* timespecs for cnd_timedwait */
|
||||
struct timespec current;
|
||||
struct timespec expire;
|
||||
|
||||
/* We override the clock to monotonic when creating the condition
|
||||
* variable. */
|
||||
clock_gettime(CLOCK_MONOTONIC, ¤t);
|
||||
|
||||
/* calculating when to expire */
|
||||
expire.nsec = timeout % 1000000000L;
|
||||
expire.sec = timeout / 1000000000L;
|
||||
expire.tv_nsec = timeout % 1000000000L;
|
||||
expire.tv_sec = timeout / 1000000000L;
|
||||
|
||||
expire.nsec += current.tv_nsec;
|
||||
expire.sec += current.tv_sec;
|
||||
expire.tv_nsec += current.tv_nsec;
|
||||
expire.tv_sec += current.tv_sec;
|
||||
|
||||
/* expire.nsec now is a number between 0 and 1999999998 */
|
||||
if (expire.nsec > 999999999L) {
|
||||
expire.sec++;
|
||||
expire.nsec -= 1000000000L;
|
||||
if (expire.tv_nsec > 999999999L) {
|
||||
expire.tv_sec++;
|
||||
expire.tv_nsec -= 1000000000L;
|
||||
}
|
||||
|
||||
mtx_lock(&dri2_sync->mutex);
|
||||
|
Reference in New Issue
Block a user