diff --git a/src/threads.c b/src/threads.c index 30671ff..1bf6f53 100644 --- a/src/threads.c +++ b/src/threads.c @@ -1,7 +1,13 @@ // C11 threads implementation for w64devkit // This is free and unencumbered software released into the public domain. +#ifdef __i386__ +// Compile the plain functions for 32-bit time_t, and define the 64-bit +// time_t variants explicitly at the end. See threads.h. +# define _USE_32BIT_TIME_T +#endif #include #include +#include typedef __UINTPTR_TYPE__ uz; typedef __INT32_TYPE__ i32; @@ -81,19 +87,24 @@ thrd_t thrd_current() return (thrd_t){0, GetCurrentThreadId()}; } -int thrd_sleep(const struct timespec *d, struct timespec *r) +static void sleep_for(i64 sec, i64 nsec) { // Convert to milliseconds with overflow detection. If the duration // doesn't fit in i32 (or the math overflows), degrade to an infinite // sleep — no real program will run long enough to notice the difference. i64 ms; i32 timeout = -1; - if (!__builtin_mul_overflow((i64)d->tv_sec, (i64)1000, &ms) && - !__builtin_add_overflow(ms, (i64)((d->tv_nsec + 999999)/1000000), &ms)) { + if (!__builtin_mul_overflow(sec, (i64)1000, &ms) && + !__builtin_add_overflow(ms, (nsec + 999999)/1000000, &ms)) { if (ms < 0) ms = 0; if (ms <= 0x7fffffff) timeout = (i32)ms; } Sleep(timeout); +} + +int thrd_sleep(const struct timespec *d, struct timespec *r) +{ + sleep_for(d->tv_sec, d->tv_nsec); if (r) { r->tv_sec = 0; r->tv_nsec = 0; @@ -204,7 +215,7 @@ int cnd_wait(cnd_t *c, mtx_t *m) return thrd_success; } -int cnd_timedwait(cnd_t *c, mtx_t *m, const struct timespec *abs) +static int timedwait(cnd_t *c, mtx_t *m, i64 sec, i64 nsec) { // FILETIME is 100ns ticks since 1601-01-01 UTC. // Unix epoch (1970-01-01) is 11644473600 seconds later: @@ -216,8 +227,8 @@ int cnd_timedwait(cnd_t *c, mtx_t *m, const struct timespec *abs) GetSystemTimeAsFileTime(&now); i64 abs_ft; i32 timeout = -1; - if (!__builtin_mul_overflow((i64)abs->tv_sec, (i64)10000000, &abs_ft) && - !__builtin_add_overflow(abs_ft, (i64)(abs->tv_nsec/100), &abs_ft) && + if (!__builtin_mul_overflow(sec, (i64)10000000, &abs_ft) && + !__builtin_add_overflow(abs_ft, nsec/100, &abs_ft) && !__builtin_add_overflow(abs_ft, (i64)116444736000000000, &abs_ft)) { i64 diff = abs_ft - (i64)now; i64 ms = diff <= 0 ? 0 : diff/10000; @@ -229,6 +240,11 @@ int cnd_timedwait(cnd_t *c, mtx_t *m, const struct timespec *abs) return thrd_success; } +int cnd_timedwait(cnd_t *c, mtx_t *m, const struct timespec *abs) +{ + return timedwait(c, m, abs->tv_sec, abs->tv_nsec); +} + void cnd_destroy(cnd_t *) { } @@ -255,3 +271,25 @@ void tss_delete(tss_t key) { FlsFree(key.__); } + +#ifdef __i386__ +int thrd_sleep64(const struct _timespec64 *d, struct _timespec64 *r) +{ + sleep_for(d->tv_sec, d->tv_nsec); + if (r) { + r->tv_sec = 0; + r->tv_nsec = 0; + } + return 0; +} + +int mtx_timedlock64(mtx_t *, const struct _timespec64 *) +{ + __builtin_trap(); +} + +int cnd_timedwait64(cnd_t *c, mtx_t *m, const struct _timespec64 *abs) +{ + return timedwait(c, m, abs->tv_sec, abs->tv_nsec); +} +#endif diff --git a/src/threads.h b/src/threads.h index 61f8918..3a634e3 100644 --- a/src/threads.h +++ b/src/threads.h @@ -24,6 +24,18 @@ enum { struct timespec; +// On x86, time_t may be 32 or 64 bits. The plain names keep the 32-bit +// time_t ABI so that older objects still link correctly, and 64-bit +// time_t callers are routed to *64 variants. +#if defined(__i386__) +# include <_mingw.h> +#endif +#if defined(__i386__) && !defined(_USE_32BIT_TIME_T) +# define __THRD_TIME64(f) __MINGW_ASM_CALL(f##64) +#else +# define __THRD_TIME64(f) +#endif + typedef struct { __INT32_TYPE__ __handle; __INT32_TYPE__ __tid; @@ -31,7 +43,8 @@ typedef struct { int thrd_create(thrd_t *, thrd_start_t, void *); int thrd_equal(thrd_t, thrd_t); thrd_t thrd_current(void); -int thrd_sleep(const struct timespec *, struct timespec *); +int thrd_sleep(const struct timespec *, struct timespec *) + __THRD_TIME64(thrd_sleep); void thrd_yield(void); void thrd_exit[[noreturn]](int); int thrd_detach(thrd_t); @@ -40,7 +53,8 @@ int thrd_join(thrd_t, int *); typedef struct { __UINTPTR_TYPE__ __; } mtx_t; int mtx_init(mtx_t *, int); int mtx_lock(mtx_t *); -int mtx_timedlock(mtx_t *, const struct timespec *); +int mtx_timedlock(mtx_t *, const struct timespec *) + __THRD_TIME64(mtx_timedlock); int mtx_trylock(mtx_t *); int mtx_unlock(mtx_t *); void mtx_destroy(mtx_t *); @@ -54,7 +68,8 @@ int cnd_init(cnd_t *); int cnd_signal(cnd_t *); int cnd_broadcast(cnd_t *); int cnd_wait(cnd_t *, mtx_t *); -int cnd_timedwait(cnd_t *, mtx_t *, const struct timespec *); +int cnd_timedwait(cnd_t *, mtx_t *, const struct timespec *) + __THRD_TIME64(cnd_timedwait); void cnd_destroy(cnd_t *); #if !defined(__cplusplus) && __STDC_VERSION__ < 202311L @@ -71,6 +86,8 @@ void *tss_get(tss_t); int tss_set(tss_t, void *); void tss_delete(tss_t); +#undef __THRD_TIME64 + #ifdef __cplusplus } #endif