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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user