[Mesa-dev] [PATCH v2 03/26] threads: update for late C11 changes
Nicolai Hähnle
nhaehnle at gmail.com
Mon Nov 6 10:23:34 UTC 2017
From: Nicolai Hähnle <nicolai.haehnle at amd.com>
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 at vmware.com>
Cc: Brian Paul <brianp at vmware.com>
Reviewed-by: Marek Olšák <marek.olsak at amd.com> (v1)
---
include/c11/threads.h | 11 ---------
include/c11/threads_posix.h | 39 +++++++++++++-------------------
include/c11/threads_win32.h | 50 ++++++++++++++++++++++++++---------------
src/egl/drivers/dri2/egl_dri2.c | 24 +++++++++++---------
4 files changed, 60 insertions(+), 64 deletions(-)
diff --git a/include/c11/threads.h b/include/c11/threads.h
index 573348d8091..3c3f23a8ab8 100644
--- a/include/c11/threads.h
+++ b/include/c11/threads.h
@@ -23,42 +23,31 @@
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef EMULATED_THREADS_H_INCLUDED_
#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
#endif
#include "c99_compat.h" /* for `inline` */
/*---------------------------- types ----------------------------*/
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 {
mtx_plain = 0,
mtx_try = 1,
mtx_timed = 2,
mtx_recursive = 4
};
enum {
diff --git a/include/c11/threads_posix.h b/include/c11/threads_posix.h
index 43e803ee8d1..7bf6a0f6ef6 100644
--- a/include/c11/threads_posix.h
+++ b/include/c11/threads_posix.h
@@ -125,33 +125,29 @@ cnd_init(cnd_t *cond)
// 7.25.3.4
static inline int
cnd_signal(cnd_t *cond)
{
assert(cond != NULL);
return (pthread_cond_signal(cond) == 0) ? thrd_success : thrd_error;
}
// 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;
}
// 7.25.3.6
static inline int
cnd_wait(cnd_t *cond, mtx_t *mtx)
{
assert(mtx != NULL);
@@ -228,38 +224,35 @@ mtx_lock(mtx_t *mtx)
}
static inline int
mtx_trylock(mtx_t *mtx);
static inline void
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)
return thrd_busy;
// busy loop!
thrd_yield();
}
return thrd_success;
#endif
}
@@ -335,27 +328,24 @@ thrd_join(thrd_t thr, int *res)
void *code;
if (pthread_join(thr, &code) != 0)
return thrd_error;
if (res)
*res = (int)(intptr_t)code;
return thrd_success;
}
// 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
static inline void
thrd_yield(void)
{
sched_yield();
}
@@ -385,21 +375,22 @@ tss_get(tss_t key)
// 7.25.6.4
static inline int
tss_set(tss_t key, void *val)
{
return (pthread_setspecific(key, val) == 0) ? thrd_success : thrd_error;
}
/*-------------------- 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
diff --git a/include/c11/threads_win32.h b/include/c11/threads_win32.h
index af7df4b9ef5..77d923aaf49 100644
--- a/include/c11/threads_win32.h
+++ b/include/c11/threads_win32.h
@@ -68,20 +68,31 @@ Configuration macro:
// check configuration
#if defined(EMULATED_THREADS_USE_NATIVE_CALL_ONCE) && (_WIN32_WINNT < 0x0600)
#error EMULATED_THREADS_USE_NATIVE_CALL_ONCE requires _WIN32_WINNT>=0x0600
#endif
#if defined(EMULATED_THREADS_USE_NATIVE_CV) && (_WIN32_WINNT < 0x0600)
#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
#define ONCE_FLAG_INIT INIT_ONCE_STATIC_INIT
#else
#define ONCE_FLAG_INIT {0}
#endif
#define TSS_DTOR_ITERATIONS 1
// FIXME: temporary non-standard hack to ease transition
@@ -139,23 +150,23 @@ static unsigned __stdcall impl_thrd_routine(void *p)
{
struct impl_thrd_param pack;
int code;
memcpy(&pack, p, sizeof(struct impl_thrd_param));
free(p);
code = pack.func(pack.arg);
impl_tss_dtor_invoke();
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
struct impl_call_once_param { void (*func)(void); };
static BOOL CALLBACK impl_call_once_callback(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
{
struct impl_call_once_param *param = (struct impl_call_once_param*)Parameter;
(param->func)();
((void)InitOnce); ((void)Context); // suppress warning
return TRUE;
@@ -199,34 +210,34 @@ static void impl_cond_do_signal(cnd_t *cond, int broadcast)
nsignal = cond->to_unblock = 1;
cond->blocked--;
}
}
LeaveCriticalSection(&cond->monitor);
if (0 < nsignal)
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;
int timeout = 0;
DWORD w;
WaitForSingleObject(cond->sem_gate, INFINITE);
cond->blocked++;
ReleaseSemaphore(cond->sem_gate, 1, NULL);
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);
if ((nleft = cond->to_unblock) != 0) {
if (timeout) {
if (cond->blocked != 0) {
cond->blocked--;
} else {
cond->gone++;
}
@@ -371,29 +382,29 @@ cnd_signal(cnd_t *cond)
#ifdef EMULATED_THREADS_USE_NATIVE_CV
WakeConditionVariable(&cond->condvar);
#else
impl_cond_do_signal(cond, 0);
#endif
return thrd_success;
}
// 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
}
// 7.25.3.6
static inline int
cnd_wait(cnd_t *cond, mtx_t *mtx)
{
if (!cond || !mtx) return thrd_error;
#ifdef EMULATED_THREADS_USE_NATIVE_CV
SleepConditionVariableCS(&cond->condvar, mtx, INFINITE);
@@ -431,26 +442,26 @@ mtx_init(mtx_t *mtx, int type)
static inline int
mtx_lock(mtx_t *mtx)
{
if (!mtx) return thrd_error;
EnterCriticalSection(mtx);
return thrd_success;
}
// 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)
return thrd_busy;
// busy loop!
thrd_yield();
}
return thrd_success;
}
@@ -572,24 +583,25 @@ thrd_join(thrd_t thr, int *res)
return thrd_error;
}
*res = (int)code;
}
CloseHandle(thr);
return thrd_success;
}
// 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
static inline void
thrd_yield(void)
{
SwitchToThread();
}
@@ -626,21 +638,23 @@ tss_get(tss_t key)
// 7.25.6.4
static inline int
tss_set(tss_t key, void *val)
{
return TlsSetValue(key, val) ? thrd_success : thrd_error;
}
/*-------------------- 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
diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c
index 503450542e5..c4771cb45e7 100644
--- a/src/egl/drivers/dri2/egl_dri2.c
+++ b/src/egl/drivers/dri2/egl_dri2.c
@@ -3065,24 +3065,20 @@ dri2_dup_native_fence_fd(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync)
static EGLint
dri2_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
EGLint flags, EGLTime timeout)
{
_EGLContext *ctx = _eglGetCurrentContext();
struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
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:
*
* "If no context is current for the bound API,
* the EGL_SYNC_FLUSH_COMMANDS_BIT_KHR bit is ignored.
*/
if (dri2_ctx && flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR)
wait_flags |= __DRI2_FENCE_FLAG_FLUSH_COMMANDS;
@@ -3109,33 +3105,39 @@ dri2_client_wait_sync(_EGLDriver *drv, _EGLDisplay *dpy, _EGLSync *sync,
}
/* if timeout is EGL_FOREVER_KHR, it should wait without any timeout.*/
if (timeout == EGL_FOREVER_KHR) {
mtx_lock(&dri2_sync->mutex);
cnd_wait(&dri2_sync->cond, &dri2_sync->mutex);
mtx_unlock(&dri2_sync->mutex);
} 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);
ret = cnd_timedwait(&dri2_sync->cond, &dri2_sync->mutex, &expire);
mtx_unlock(&dri2_sync->mutex);
if (ret == thrd_busy) {
if (dri2_sync->base.SyncStatus == EGL_UNSIGNALED_KHR) {
ret = EGL_TIMEOUT_EXPIRED_KHR;
} else {
--
2.11.0
More information about the mesa-dev
mailing list