1
0
mirror of https://github.com/skeeto/w64devkit.git synced 2026-10-23 06:08:56 +03:00

Support both time_t ABIs in C11 threads on x86

thrd_sleep, mtx_timedlock, and cnd_timedwait take a struct timespec,
whose layout follows time_t. libmingwex.a was compiled for 32-bit
time_t only, so x86 programs built with 64-bit time_t read garbage
timeouts. The plain names keep the 32-bit ABI so existing objects still
link correctly, and threads.h redirects 64-bit time_t callers to new
*64 variants. x64 is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Christopher Wellons
2026-10-18 10:08:23 -04:00
parent be339a9847
commit 58dca7f70d
2 changed files with 64 additions and 9 deletions

View File

@@ -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 <threads.h>
#include <time.h>
#include <sys/timeb.h>
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

View File

@@ -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