diff options
Diffstat (limited to 'src/mesa/compat')
-rw-r--r-- | src/mesa/compat/c11/threads.h | 73 | ||||
-rw-r--r-- | src/mesa/compat/c11/threads_posix.h | 396 | ||||
-rw-r--r-- | src/mesa/compat/c11/threads_win32.h | 522 | ||||
-rw-r--r-- | src/mesa/compat/c11_compat.h | 27 | ||||
-rw-r--r-- | src/mesa/compat/c99_compat.h | 138 | ||||
-rw-r--r-- | src/mesa/compat/c99_math.h | 211 | ||||
-rw-r--r-- | src/mesa/compat/no_extern_c.h | 48 |
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)¶m, 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 |