aboutsummaryrefslogtreecommitdiff
path: root/src/mesa/compat
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/compat')
-rw-r--r--src/mesa/compat/c11/threads.h73
-rw-r--r--src/mesa/compat/c11/threads_posix.h396
-rw-r--r--src/mesa/compat/c11/threads_win32.h522
-rw-r--r--src/mesa/compat/c11_compat.h27
-rw-r--r--src/mesa/compat/c99_compat.h138
-rw-r--r--src/mesa/compat/c99_math.h211
-rw-r--r--src/mesa/compat/no_extern_c.h48
7 files changed, 1415 insertions, 0 deletions
diff --git a/src/mesa/compat/c11/threads.h b/src/mesa/compat/c11/threads.h
new file mode 100644
index 00000000..3c3f23a8
--- /dev/null
+++ b/src/mesa/compat/c11/threads.h
@@ -0,0 +1,73 @@
+/*
+ * C11 <threads.h> emulation library
+ *
+ * (C) Copyright yohhoy 2012.
+ * Distributed under the Boost Software License, Version 1.0.
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare [[derivative work]]s of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * 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>
+
+#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*);
+
+
+/*-------------------- enumeration constants --------------------*/
+enum {
+ mtx_plain = 0,
+ mtx_try = 1,
+ mtx_timed = 2,
+ mtx_recursive = 4
+};
+
+enum {
+ thrd_success = 0, // succeeded
+ thrd_timeout, // timeout
+ thrd_error, // failed
+ thrd_busy, // resource busy
+ thrd_nomem // out of memory
+};
+
+/*-------------------------- functions --------------------------*/
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include "threads_win32.h"
+#elif defined(HAVE_PTHREAD)
+#include "threads_posix.h"
+#else
+#error Not supported on this platform.
+#endif
+
+
+
+#endif /* EMULATED_THREADS_H_INCLUDED_ */
diff --git a/src/mesa/compat/c11/threads_posix.h b/src/mesa/compat/c11/threads_posix.h
new file mode 100644
index 00000000..45cb6075
--- /dev/null
+++ b/src/mesa/compat/c11/threads_posix.h
@@ -0,0 +1,396 @@
+/*
+ * C11 <threads.h> emulation library
+ *
+ * (C) Copyright yohhoy 2012.
+ * Distributed under the Boost Software License, Version 1.0.
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare [[derivative work]]s of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * 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.
+ */
+#include <stdlib.h>
+#ifndef assert
+#include <assert.h>
+#endif
+#include <limits.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sched.h>
+#include <stdint.h> /* for intptr_t */
+
+/*
+Configuration macro:
+
+ EMULATED_THREADS_USE_NATIVE_TIMEDLOCK
+ Use pthread_mutex_timedlock() for `mtx_timedlock()'
+ Otherwise use mtx_trylock() + *busy loop* emulation.
+*/
+#if !defined(__CYGWIN__) && !defined(__APPLE__) && !defined(__NetBSD__)
+#define EMULATED_THREADS_USE_NATIVE_TIMEDLOCK
+#endif
+
+
+#include <pthread.h>
+
+/*---------------------------- macros ----------------------------*/
+#define ONCE_FLAG_INIT PTHREAD_ONCE_INIT
+#ifdef INIT_ONCE_STATIC_INIT
+#define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS
+#else
+#define TSS_DTOR_ITERATIONS 1 // assume TSS dtor MAY be called at least once.
+#endif
+
+// FIXME: temporary non-standard hack to ease transition
+#define _MTX_INITIALIZER_NP PTHREAD_MUTEX_INITIALIZER
+
+/*---------------------------- types ----------------------------*/
+typedef pthread_cond_t cnd_t;
+typedef pthread_t thrd_t;
+typedef pthread_key_t tss_t;
+typedef pthread_mutex_t mtx_t;
+typedef pthread_once_t once_flag;
+
+
+/*
+Implementation limits:
+ - Conditionally emulation for "mutex with timeout"
+ (see EMULATED_THREADS_USE_NATIVE_TIMEDLOCK macro)
+*/
+struct impl_thrd_param {
+ thrd_start_t func;
+ void *arg;
+};
+
+static inline void *
+impl_thrd_routine(void *p)
+{
+ struct impl_thrd_param pack = *((struct impl_thrd_param *)p);
+ free(p);
+ return (void*)(intptr_t)pack.func(pack.arg);
+}
+
+
+/*--------------- 7.25.2 Initialization functions ---------------*/
+// 7.25.2.1
+static inline void
+call_once(once_flag *flag, void (*func)(void))
+{
+ pthread_once(flag, func);
+}
+
+
+/*------------- 7.25.3 Condition variable functions -------------*/
+// 7.25.3.1
+static inline int
+cnd_broadcast(cnd_t *cond)
+{
+ assert(cond != NULL);
+ return (pthread_cond_broadcast(cond) == 0) ? thrd_success : thrd_error;
+}
+
+// 7.25.3.2
+static inline void
+cnd_destroy(cnd_t *cond)
+{
+ assert(cond);
+ pthread_cond_destroy(cond);
+}
+
+// 7.25.3.3
+static inline int
+cnd_init(cnd_t *cond)
+{
+ assert(cond != NULL);
+ return (pthread_cond_init(cond, NULL) == 0) ? thrd_success : thrd_error;
+}
+
+// 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 struct timespec *abs_time)
+{
+ int rt;
+
+ assert(mtx != NULL);
+ assert(cond != NULL);
+ assert(abs_time != NULL);
+
+ 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);
+ assert(cond != NULL);
+ return (pthread_cond_wait(cond, mtx) == 0) ? thrd_success : thrd_error;
+}
+
+
+/*-------------------- 7.25.4 Mutex functions --------------------*/
+// 7.25.4.1
+static inline void
+mtx_destroy(mtx_t *mtx)
+{
+ assert(mtx != NULL);
+ pthread_mutex_destroy(mtx);
+}
+
+/*
+ * XXX: Workaround when building with -O0 and without pthreads link.
+ *
+ * In such cases constant folding and dead code elimination won't be
+ * available, thus the compiler will always add the pthread_mutexattr*
+ * functions into the binary. As we try to link, we'll fail as the
+ * symbols are unresolved.
+ *
+ * Ideally we'll enable the optimisations locally, yet that does not
+ * seem to work.
+ *
+ * So the alternative workaround is to annotate the symbols as weak.
+ * Thus the linker will be happy and things don't clash when building
+ * with -O1 or greater.
+ */
+#if defined(HAVE_FUNC_ATTRIBUTE_WEAK) && !defined(__CYGWIN__)
+__attribute__((weak))
+int pthread_mutexattr_init(pthread_mutexattr_t *attr);
+
+__attribute__((weak))
+int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
+
+__attribute__((weak))
+int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
+#endif
+
+// 7.25.4.2
+static inline int
+mtx_init(mtx_t *mtx, int type)
+{
+ pthread_mutexattr_t attr;
+ assert(mtx != NULL);
+ if (type != mtx_plain && type != mtx_timed && type != mtx_try
+ && type != (mtx_plain|mtx_recursive)
+ && type != (mtx_timed|mtx_recursive)
+ && type != (mtx_try|mtx_recursive))
+ return thrd_error;
+
+ if ((type & mtx_recursive) == 0) {
+ pthread_mutex_init(mtx, NULL);
+ return thrd_success;
+ }
+
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(mtx, &attr);
+ pthread_mutexattr_destroy(&attr);
+ return thrd_success;
+}
+
+// 7.25.4.3
+static inline int
+mtx_lock(mtx_t *mtx)
+{
+ assert(mtx != NULL);
+ return (pthread_mutex_lock(mtx) == 0) ? thrd_success : thrd_error;
+}
+
+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 struct timespec *ts)
+{
+ assert(mtx != NULL);
+ assert(ts != NULL);
+
+ {
+#ifdef EMULATED_THREADS_USE_NATIVE_TIMEDLOCK
+ int rt;
+ 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 += 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
+ }
+}
+
+// 7.25.4.5
+static inline int
+mtx_trylock(mtx_t *mtx)
+{
+ assert(mtx != NULL);
+ return (pthread_mutex_trylock(mtx) == 0) ? thrd_success : thrd_busy;
+}
+
+// 7.25.4.6
+static inline int
+mtx_unlock(mtx_t *mtx)
+{
+ assert(mtx != NULL);
+ return (pthread_mutex_unlock(mtx) == 0) ? thrd_success : thrd_error;
+}
+
+
+/*------------------- 7.25.5 Thread functions -------------------*/
+// 7.25.5.1
+static inline int
+thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
+{
+ struct impl_thrd_param *pack;
+ assert(thr != NULL);
+ pack = (struct impl_thrd_param *)malloc(sizeof(struct impl_thrd_param));
+ if (!pack) return thrd_nomem;
+ pack->func = func;
+ pack->arg = arg;
+ if (pthread_create(thr, NULL, impl_thrd_routine, pack) != 0) {
+ free(pack);
+ return thrd_error;
+ }
+ return thrd_success;
+}
+
+// 7.25.5.2
+static inline thrd_t
+thrd_current(void)
+{
+ return pthread_self();
+}
+
+// 7.25.5.3
+static inline int
+thrd_detach(thrd_t thr)
+{
+ return (pthread_detach(thr) == 0) ? thrd_success : thrd_error;
+}
+
+// 7.25.5.4
+static inline int
+thrd_equal(thrd_t thr0, thrd_t thr1)
+{
+ return pthread_equal(thr0, thr1);
+}
+
+// 7.25.5.5
+static inline void
+thrd_exit(int res)
+{
+ pthread_exit((void*)(intptr_t)res);
+}
+
+// 7.25.5.6
+static inline int
+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 struct timespec *time_point, struct timespec *remaining)
+{
+ assert(time_point != NULL);
+ nanosleep(time_point, remaining);
+}
+
+// 7.25.5.8
+static inline void
+thrd_yield(void)
+{
+ sched_yield();
+}
+
+
+/*----------- 7.25.6 Thread-specific storage functions -----------*/
+// 7.25.6.1
+static inline int
+tss_create(tss_t *key, tss_dtor_t dtor)
+{
+ assert(key != NULL);
+ return (pthread_key_create(key, dtor) == 0) ? thrd_success : thrd_error;
+}
+
+// 7.25.6.2
+static inline void
+tss_delete(tss_t key)
+{
+ pthread_key_delete(key);
+}
+
+// 7.25.6.3
+static inline void *
+tss_get(tss_t key)
+{
+ return pthread_getspecific(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
+#ifndef HAVE_TIMESPEC_GET
+static inline int
+timespec_get(struct timespec *ts, int base)
+{
+ if (!ts) return 0;
+ if (base == TIME_UTC) {
+ clock_gettime(CLOCK_REALTIME, ts);
+ return base;
+ }
+ return 0;
+}
+#endif
diff --git a/src/mesa/compat/c11/threads_win32.h b/src/mesa/compat/c11/threads_win32.h
new file mode 100644
index 00000000..02c2a73d
--- /dev/null
+++ b/src/mesa/compat/c11/threads_win32.h
@@ -0,0 +1,522 @@
+/*
+ * C11 <threads.h> emulation library
+ *
+ * (C) Copyright yohhoy 2012.
+ * Distributed under the Boost Software License, Version 1.0.
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare [[derivative work]]s of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * 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 assert
+#include <assert.h>
+#endif
+#include <limits.h>
+#include <errno.h>
+#include <process.h> // MSVCRT
+#include <stdlib.h>
+
+/*
+Configuration macro:
+
+ EMULATED_THREADS_USE_NATIVE_CALL_ONCE
+ Use native WindowsAPI one-time initialization function.
+ (requires WinVista or later)
+ Otherwise emulate by mtx_trylock() + *busy loop* for WinXP.
+
+ EMULATED_THREADS_TSS_DTOR_SLOTNUM
+ Max registerable TSS dtor number.
+*/
+
+#if _WIN32_WINNT >= 0x0600
+// Prefer native WindowsAPI on newer environment.
+#if !defined(__MINGW32__)
+#define EMULATED_THREADS_USE_NATIVE_CALL_ONCE
+#endif
+#endif
+#define EMULATED_THREADS_TSS_DTOR_SLOTNUM 64 // see TLS_MINIMUM_AVAILABLE
+
+
+#include <windows.h>
+
+// 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
+
+/* Visual Studio 2015 and later */
+#ifdef _MSC_VER
+#define HAVE_TIMESPEC_GET
+#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
+#define _MTX_INITIALIZER_NP {(PCRITICAL_SECTION_DEBUG)-1, -1, 0, 0, 0, 0}
+
+/*---------------------------- types ----------------------------*/
+typedef CONDITION_VARIABLE cnd_t;
+
+typedef HANDLE thrd_t;
+
+typedef DWORD tss_t;
+
+typedef CRITICAL_SECTION mtx_t;
+
+#ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE
+typedef INIT_ONCE once_flag;
+#else
+typedef struct once_flag_t {
+ volatile LONG status;
+} once_flag;
+#endif
+
+
+static inline void * tss_get(tss_t key);
+static inline void thrd_yield(void);
+static inline int mtx_trylock(mtx_t *mtx);
+static inline int mtx_lock(mtx_t *mtx);
+static inline int mtx_unlock(mtx_t *mtx);
+
+/*
+Implementation limits:
+ - Conditionally emulation for "Initialization functions"
+ (see EMULATED_THREADS_USE_NATIVE_CALL_ONCE macro)
+ - Emulated `mtx_timelock()' with mtx_trylock() + *busy loop*
+*/
+static void impl_tss_dtor_invoke(void); // forward decl.
+
+struct impl_thrd_param {
+ thrd_start_t func;
+ void *arg;
+};
+
+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 time_t impl_timespec2msec(const struct timespec *ts)
+{
+ return (ts->tv_sec * 1000U) + (ts->tv_nsec / 1000000L);
+}
+
+#ifdef HAVE_TIMESPEC_GET
+static DWORD impl_abs2relmsec(const struct timespec *abs_time)
+{
+ const time_t abs_ms = impl_timespec2msec(abs_time);
+ struct timespec now;
+ timespec_get(&now, TIME_UTC);
+ const time_t now_ms = impl_timespec2msec(&now);
+ const DWORD rel_ms = (abs_ms > now_ms) ? (DWORD)(abs_ms - now_ms) : 0;
+ return rel_ms;
+}
+#endif
+
+#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;
+}
+#endif // ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE
+
+static struct impl_tss_dtor_entry {
+ tss_t key;
+ tss_dtor_t dtor;
+} impl_tss_dtor_tbl[EMULATED_THREADS_TSS_DTOR_SLOTNUM];
+
+static int impl_tss_dtor_register(tss_t key, tss_dtor_t dtor)
+{
+ int i;
+ for (i = 0; i < EMULATED_THREADS_TSS_DTOR_SLOTNUM; i++) {
+ if (!impl_tss_dtor_tbl[i].dtor)
+ break;
+ }
+ if (i == EMULATED_THREADS_TSS_DTOR_SLOTNUM)
+ return 1;
+ impl_tss_dtor_tbl[i].key = key;
+ impl_tss_dtor_tbl[i].dtor = dtor;
+ return 0;
+}
+
+static void impl_tss_dtor_invoke()
+{
+ int i;
+ for (i = 0; i < EMULATED_THREADS_TSS_DTOR_SLOTNUM; i++) {
+ if (impl_tss_dtor_tbl[i].dtor) {
+ void* val = tss_get(impl_tss_dtor_tbl[i].key);
+ if (val)
+ (impl_tss_dtor_tbl[i].dtor)(val);
+ }
+ }
+}
+
+
+/*--------------- 7.25.2 Initialization functions ---------------*/
+// 7.25.2.1
+static inline void
+call_once(once_flag *flag, void (*func)(void))
+{
+ assert(flag && func);
+#ifdef EMULATED_THREADS_USE_NATIVE_CALL_ONCE
+ {
+ struct impl_call_once_param param;
+ param.func = func;
+ InitOnceExecuteOnce(flag, impl_call_once_callback, (PVOID)&param, NULL);
+ }
+#else
+ if (InterlockedCompareExchange(&flag->status, 1, 0) == 0) {
+ (func)();
+ InterlockedExchange(&flag->status, 2);
+ } else {
+ while (flag->status == 1) {
+ // busy loop!
+ thrd_yield();
+ }
+ }
+#endif
+}
+
+
+/*------------- 7.25.3 Condition variable functions -------------*/
+// 7.25.3.1
+static inline int
+cnd_broadcast(cnd_t *cond)
+{
+ assert(cond != NULL);
+ WakeAllConditionVariable(cond);
+ return thrd_success;
+}
+
+// 7.25.3.2
+static inline void
+cnd_destroy(cnd_t *cond)
+{
+ assert(cond != NULL);
+ // do nothing
+}
+
+// 7.25.3.3
+static inline int
+cnd_init(cnd_t *cond)
+{
+ assert(cond != NULL);
+ InitializeConditionVariable(cond);
+ return thrd_success;
+}
+
+// 7.25.3.4
+static inline int
+cnd_signal(cnd_t *cond)
+{
+ assert(cond != NULL);
+ WakeConditionVariable(cond);
+ return thrd_success;
+}
+
+// 7.25.3.5
+static inline int
+cnd_timedwait(cnd_t *cond, mtx_t *mtx, const struct timespec *abs_time)
+{
+ assert(cond != NULL);
+ assert(mtx != NULL);
+ assert(abs_time != NULL);
+#ifdef HAVE_TIMESPEC_GET
+ const DWORD timeout = impl_abs2relmsec(abs_time);
+ if (SleepConditionVariableCS(cond, mtx, timeout))
+ return thrd_success;
+ return (GetLastError() == ERROR_TIMEOUT) ? thrd_busy : thrd_error;
+#else
+ return thrd_error;
+#endif
+}
+
+// 7.25.3.6
+static inline int
+cnd_wait(cnd_t *cond, mtx_t *mtx)
+{
+ assert(cond != NULL);
+ assert(mtx != NULL);
+ SleepConditionVariableCS(cond, mtx, INFINITE);
+ return thrd_success;
+}
+
+
+/*-------------------- 7.25.4 Mutex functions --------------------*/
+// 7.25.4.1
+static inline void
+mtx_destroy(mtx_t *mtx)
+{
+ assert(mtx);
+ DeleteCriticalSection(mtx);
+}
+
+// 7.25.4.2
+static inline int
+mtx_init(mtx_t *mtx, int type)
+{
+ assert(mtx != NULL);
+ if (type != mtx_plain && type != mtx_timed && type != mtx_try
+ && type != (mtx_plain|mtx_recursive)
+ && type != (mtx_timed|mtx_recursive)
+ && type != (mtx_try|mtx_recursive))
+ return thrd_error;
+ InitializeCriticalSection(mtx);
+ return thrd_success;
+}
+
+// 7.25.4.3
+static inline int
+mtx_lock(mtx_t *mtx)
+{
+ assert(mtx != NULL);
+ EnterCriticalSection(mtx);
+ return thrd_success;
+}
+
+// 7.25.4.4
+static inline int
+mtx_timedlock(mtx_t *mtx, const struct timespec *ts)
+{
+ assert(mtx != NULL);
+ assert(ts != NULL);
+#ifdef HAVE_TIMESPEC_GET
+ while (mtx_trylock(mtx) != thrd_success) {
+ if (impl_abs2relmsec(ts) == 0)
+ return thrd_busy;
+ // busy loop!
+ thrd_yield();
+ }
+ return thrd_success;
+#else
+ return thrd_error;
+#endif
+}
+
+// 7.25.4.5
+static inline int
+mtx_trylock(mtx_t *mtx)
+{
+ assert(mtx != NULL);
+ return TryEnterCriticalSection(mtx) ? thrd_success : thrd_busy;
+}
+
+// 7.25.4.6
+static inline int
+mtx_unlock(mtx_t *mtx)
+{
+ assert(mtx != NULL);
+ LeaveCriticalSection(mtx);
+ return thrd_success;
+}
+
+
+/*------------------- 7.25.5 Thread functions -------------------*/
+// 7.25.5.1
+static inline int
+thrd_create(thrd_t *thr, thrd_start_t func, void *arg)
+{
+ struct impl_thrd_param *pack;
+ uintptr_t handle;
+ assert(thr != NULL);
+ pack = (struct impl_thrd_param *)malloc(sizeof(struct impl_thrd_param));
+ if (!pack) return thrd_nomem;
+ pack->func = func;
+ pack->arg = arg;
+ handle = _beginthreadex(NULL, 0, impl_thrd_routine, pack, 0, NULL);
+ if (handle == 0) {
+ if (errno == EAGAIN || errno == EACCES)
+ return thrd_nomem;
+ return thrd_error;
+ }
+ *thr = (thrd_t)handle;
+ return thrd_success;
+}
+
+#if 0
+// 7.25.5.2
+static inline thrd_t
+thrd_current(void)
+{
+ HANDLE hCurrentThread;
+ BOOL bRet;
+
+ /* GetCurrentThread() returns a pseudo-handle, which we need
+ * to pass to DuplicateHandle(). Only the resulting handle can be used
+ * from other threads.
+ *
+ * Note that neither handle can be compared to the one by thread_create.
+ * Only the thread IDs - as returned by GetThreadId() and GetCurrentThreadId()
+ * can be compared directly.
+ *
+ * Other potential solutions would be:
+ * - define thrd_t as a thread Ids, but this would mean we'd need to OpenThread for many operations
+ * - use malloc'ed memory for thrd_t. This would imply using TLS for current thread.
+ *
+ * Neither is particularly nice.
+ *
+ * Life would be much easier if C11 threads had different abstractions for
+ * threads and thread IDs, just like C++11 threads does...
+ */
+
+ bRet = DuplicateHandle(GetCurrentProcess(), // source process (pseudo) handle
+ GetCurrentThread(), // source (pseudo) handle
+ GetCurrentProcess(), // target process
+ &hCurrentThread, // target handle
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS);
+ assert(bRet);
+ if (!bRet) {
+ hCurrentThread = GetCurrentThread();
+ }
+ return hCurrentThread;
+}
+#endif
+
+// 7.25.5.3
+static inline int
+thrd_detach(thrd_t thr)
+{
+ CloseHandle(thr);
+ return thrd_success;
+}
+
+// 7.25.5.4
+static inline int
+thrd_equal(thrd_t thr0, thrd_t thr1)
+{
+ return GetThreadId(thr0) == GetThreadId(thr1);
+}
+
+// 7.25.5.5
+static inline void
+thrd_exit(int res)
+{
+ impl_tss_dtor_invoke();
+ _endthreadex((unsigned)res);
+}
+
+// 7.25.5.6
+static inline int
+thrd_join(thrd_t thr, int *res)
+{
+ DWORD w, code;
+ w = WaitForSingleObject(thr, INFINITE);
+ if (w != WAIT_OBJECT_0)
+ return thrd_error;
+ if (res) {
+ if (!GetExitCodeThread(thr, &code)) {
+ CloseHandle(thr);
+ return thrd_error;
+ }
+ *res = (int)code;
+ }
+ CloseHandle(thr);
+ return thrd_success;
+}
+
+// 7.25.5.7
+static inline void
+thrd_sleep(const struct timespec *time_point, struct timespec *remaining)
+{
+ assert(time_point);
+ assert(!remaining); /* not implemented */
+ Sleep((DWORD)impl_timespec2msec(time_point));
+}
+
+// 7.25.5.8
+static inline void
+thrd_yield(void)
+{
+ SwitchToThread();
+}
+
+
+/*----------- 7.25.6 Thread-specific storage functions -----------*/
+// 7.25.6.1
+static inline int
+tss_create(tss_t *key, tss_dtor_t dtor)
+{
+ assert(key != NULL);
+ *key = TlsAlloc();
+ if (dtor) {
+ if (impl_tss_dtor_register(*key, dtor)) {
+ TlsFree(*key);
+ return thrd_error;
+ }
+ }
+ return (*key != 0xFFFFFFFF) ? thrd_success : thrd_error;
+}
+
+// 7.25.6.2
+static inline void
+tss_delete(tss_t key)
+{
+ TlsFree(key);
+}
+
+// 7.25.6.3
+static inline void *
+tss_get(tss_t key)
+{
+ return TlsGetValue(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_GET
+static inline int
+timespec_get(struct timespec *ts, int base)
+{
+ assert(ts != NULL);
+ if (base == TIME_UTC) {
+ ts->tv_sec = time(NULL);
+ ts->tv_nsec = 0;
+ return base;
+ }
+ return 0;
+}
+#endif
diff --git a/src/mesa/compat/c11_compat.h b/src/mesa/compat/c11_compat.h
new file mode 100644
index 00000000..d35740f4
--- /dev/null
+++ b/src/mesa/compat/c11_compat.h
@@ -0,0 +1,27 @@
+/* Copyright 2019 Intel Corporation */
+/* SPDX-License-Identifier: MIT */
+
+#include "no_extern_c.h"
+
+#ifndef _C11_COMPAT_H_
+#define _C11_COMPAT_H_
+
+#if defined(__cplusplus)
+ /* This is C++ code, not C */
+#elif (__STDC_VERSION__ >= 201112L)
+ /* Already C11 */
+#else
+
+
+/*
+ * C11 static_assert() macro
+ * assert.h only defines that name for C11 and above
+ */
+#ifndef static_assert
+#define static_assert _Static_assert
+#endif
+
+
+#endif /* !C++ && !C11 */
+
+#endif /* _C11_COMPAT_H_ */
diff --git a/src/mesa/compat/c99_compat.h b/src/mesa/compat/c99_compat.h
new file mode 100644
index 00000000..ab1ec53a
--- /dev/null
+++ b/src/mesa/compat/c99_compat.h
@@ -0,0 +1,138 @@
+/**************************************************************************
+ *
+ * Copyright 2007-2013 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "no_extern_c.h"
+
+#ifndef _C99_COMPAT_H_
+#define _C99_COMPAT_H_
+
+
+/*
+ * MSVC hacks.
+ */
+#if defined(_MSC_VER)
+
+# if _MSC_VER < 1900
+# error "Microsoft Visual Studio 2015 or higher required"
+# endif
+
+ /*
+ * Visual Studio will complain if we define the `inline` keyword, but
+ * actually it only supports the keyword on C++.
+ *
+ * To avoid this the _ALLOW_KEYWORD_MACROS must be set.
+ */
+# if !defined(_ALLOW_KEYWORD_MACROS)
+# define _ALLOW_KEYWORD_MACROS
+# endif
+
+ /*
+ * XXX: MSVC has a `__restrict` keyword, but it also has a
+ * `__declspec(restrict)` modifier, so it is impossible to define a
+ * `restrict` macro without interfering with the latter. Furthermore the
+ * MSVC standard library uses __declspec(restrict) under the _CRTRESTRICT
+ * macro. For now resolve this issue by redefining _CRTRESTRICT, but going
+ * forward we should probably should stop using restrict, especially
+ * considering that our code does not obbey strict aliasing rules any way.
+ */
+# include <crtdefs.h>
+# undef _CRTRESTRICT
+# define _CRTRESTRICT
+#endif
+
+
+/*
+ * C99 inline keyword
+ */
+#ifndef inline
+# ifdef __cplusplus
+ /* C++ supports inline keyword */
+# elif defined(__GNUC__)
+# define inline __inline__
+# elif defined(_MSC_VER)
+# define inline __inline
+# elif defined(__ICL)
+# define inline __inline
+# elif defined(__INTEL_COMPILER)
+ /* Intel compiler supports inline keyword */
+# elif defined(__WATCOMC__) && (__WATCOMC__ >= 1100)
+# define inline __inline
+# elif (__STDC_VERSION__ >= 199901L)
+ /* C99 supports inline keyword */
+# else
+# define inline
+# endif
+#endif
+
+
+/*
+ * C99 restrict keyword
+ *
+ * See also:
+ * - http://cellperformance.beyond3d.com/articles/2006/05/demystifying-the-restrict-keyword.html
+ */
+#ifndef restrict
+# if (__STDC_VERSION__ >= 199901L) && !defined(__cplusplus)
+ /* C99 */
+# elif defined(__GNUC__)
+# define restrict __restrict__
+# elif defined(_MSC_VER)
+# define restrict __restrict
+# else
+# define restrict /* */
+# endif
+#endif
+
+
+/*
+ * C99 __func__ macro
+ */
+#ifndef __func__
+# if (__STDC_VERSION__ >= 199901L)
+ /* C99 */
+# elif defined(__GNUC__)
+# define __func__ __FUNCTION__
+# elif defined(_MSC_VER)
+# define __func__ __FUNCTION__
+# else
+# define __func__ "<unknown>"
+# endif
+#endif
+
+
+/* Simple test case for debugging */
+#if 0
+static inline const char *
+test_c99_compat_h(const void * restrict a,
+ const void * restrict b)
+{
+ return __func__;
+}
+#endif
+
+
+#endif /* _C99_COMPAT_H_ */
diff --git a/src/mesa/compat/c99_math.h b/src/mesa/compat/c99_math.h
new file mode 100644
index 00000000..e906c26a
--- /dev/null
+++ b/src/mesa/compat/c99_math.h
@@ -0,0 +1,211 @@
+/**************************************************************************
+ *
+ * Copyright 2007-2015 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+/**
+ * Wrapper for math.h which makes sure we have definitions of all the c99
+ * functions.
+ */
+
+
+#ifndef _C99_MATH_H_
+#define _C99_MATH_H_
+
+#include <math.h>
+#include "c99_compat.h"
+
+
+/* This is to ensure that we get M_PI, etc. definitions */
+#if defined(_MSC_VER) && !defined(_USE_MATH_DEFINES)
+#error _USE_MATH_DEFINES define required when building with MSVC
+#endif
+
+
+#if !defined(_MSC_VER) && \
+ __STDC_VERSION__ < 199901L && \
+ (!defined(_XOPEN_SOURCE) || _XOPEN_SOURCE < 600) && \
+ !defined(__cplusplus)
+
+static inline long int
+lrint(double d)
+{
+ long int rounded = (long int)(d + 0.5);
+
+ if (d - floor(d) == 0.5) {
+ if (rounded % 2 != 0)
+ rounded += (d > 0) ? -1 : 1;
+ }
+
+ return rounded;
+}
+
+static inline long int
+lrintf(float f)
+{
+ long int rounded = (long int)(f + 0.5f);
+
+ if (f - floorf(f) == 0.5f) {
+ if (rounded % 2 != 0)
+ rounded += (f > 0) ? -1 : 1;
+ }
+
+ return rounded;
+}
+
+static inline long long int
+llrint(double d)
+{
+ long long int rounded = (long long int)(d + 0.5);
+
+ if (d - floor(d) == 0.5) {
+ if (rounded % 2 != 0)
+ rounded += (d > 0) ? -1 : 1;
+ }
+
+ return rounded;
+}
+
+static inline long long int
+llrintf(float f)
+{
+ long long int rounded = (long long int)(f + 0.5f);
+
+ if (f - floorf(f) == 0.5f) {
+ if (rounded % 2 != 0)
+ rounded += (f > 0) ? -1 : 1;
+ }
+
+ return rounded;
+}
+
+static inline float
+exp2f(float f)
+{
+ return powf(2.0f, f);
+}
+
+static inline double
+exp2(double d)
+{
+ return pow(2.0, d);
+}
+
+#endif /* C99 */
+
+
+/*
+ * signbit() is a macro on Linux. Not available on Windows.
+ */
+#ifndef signbit
+#define signbit(x) ((x) < 0.0f)
+#endif
+
+
+#ifndef M_PI
+#define M_PI (3.14159265358979323846)
+#endif
+
+#ifndef M_E
+#define M_E (2.7182818284590452354)
+#endif
+
+#ifndef M_LOG2E
+#define M_LOG2E (1.4426950408889634074)
+#endif
+
+#ifndef FLT_MAX_EXP
+#define FLT_MAX_EXP 128
+#endif
+
+
+#if defined(fpclassify)
+/* ISO C99 says that fpclassify is a macro. Assume that any implementation
+ * of fpclassify, whether it's in a C99 compiler or not, will be a macro.
+ */
+#elif defined(__cplusplus)
+/* For C++, fpclassify() should be defined in <cmath> */
+#elif defined(_MSC_VER)
+/* Not required on VS2013 and above. Oddly, the fpclassify() function
+ * doesn't exist in such a form on MSVC. This is an implementation using
+ * slightly different lower-level Windows functions.
+ */
+#include <float.h>
+
+static inline enum {FP_NAN, FP_INFINITE, FP_ZERO, FP_SUBNORMAL, FP_NORMAL}
+fpclassify(double x)
+{
+ switch(_fpclass(x)) {
+ case _FPCLASS_SNAN: /* signaling NaN */
+ case _FPCLASS_QNAN: /* quiet NaN */
+ return FP_NAN;
+ case _FPCLASS_NINF: /* negative infinity */
+ case _FPCLASS_PINF: /* positive infinity */
+ return FP_INFINITE;
+ case _FPCLASS_NN: /* negative normal */
+ case _FPCLASS_PN: /* positive normal */
+ return FP_NORMAL;
+ case _FPCLASS_ND: /* negative denormalized */
+ case _FPCLASS_PD: /* positive denormalized */
+ return FP_SUBNORMAL;
+ case _FPCLASS_NZ: /* negative zero */
+ case _FPCLASS_PZ: /* positive zero */
+ return FP_ZERO;
+ default:
+ /* Should never get here; but if we do, this will guarantee
+ * that the pattern is not treated like a number.
+ */
+ return FP_NAN;
+ }
+}
+#else
+#error "Need to include or define an fpclassify function"
+#endif
+
+
+/* Since C++11, the following functions are part of the std namespace. Their C
+ * counteparts should still exist in the global namespace, however cmath
+ * undefines those functions, which in glibc 2.23, are defined as macros rather
+ * than functions as in glibc 2.22.
+ */
+#if __cplusplus >= 201103L && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 23))
+#include <cmath>
+
+using std::fpclassify;
+using std::isfinite;
+using std::isinf;
+using std::isnan;
+using std::isnormal;
+using std::signbit;
+using std::isgreater;
+using std::isgreaterequal;
+using std::isless;
+using std::islessequal;
+using std::islessgreater;
+using std::isunordered;
+#endif
+
+
+#endif /* #define _C99_MATH_H_ */
diff --git a/src/mesa/compat/no_extern_c.h b/src/mesa/compat/no_extern_c.h
new file mode 100644
index 00000000..f2f14aaf
--- /dev/null
+++ b/src/mesa/compat/no_extern_c.h
@@ -0,0 +1,48 @@
+/**************************************************************************
+ *
+ * Copyright 2014 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+/*
+ * Including system's headers inside `extern "C" { ... }` is not safe, as system
+ * headers may have C++ code in them, and C++ code inside extern "C"
+ * leads to syntactically incorrect code.
+ *
+ * This is because putting code inside extern "C" won't make __cplusplus define
+ * go away, that is, the system header being included thinks is free to use C++
+ * as it sees fits.
+ *
+ * Including non-system headers inside extern "C" is not safe either, because
+ * non-system headers end up including system headers, hence fall in the above
+ * case too.
+ *
+ * Conclusion, includes inside extern "C" is simply not portable.
+ *
+ *
+ * This header helps surface these issues.
+ */
+
+#ifdef __cplusplus
+template<class T> class _IncludeInsideExternCNotPortable;
+#endif