From 569b238ec415da087a4a19f45bbd10a1137151c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Tue, 2 Apr 2024 21:50:42 +0200 Subject: [PATCH] Add cross-platform Atomics support Fixes: https://github.com/quickjs-ng/quickjs/issues/1 --- CMakeLists.txt | 12 ++- cutils.c | 222 +++++++++++++++++++++++++++++++++++++++++- cutils.h | 41 +++++++- gen/function_source.c | Bin 3177 -> 3177 bytes gen/hello.c | Bin 1329 -> 1329 bytes gen/hello_module.c | Bin 3953 -> 3953 bytes gen/repl.c | Bin 627485 -> 627485 bytes gen/test_fib.c | Bin 1948 -> 1948 bytes quickjs-atom.h | 2 - quickjs.c | 57 +++++------ test262.conf | 2 +- 11 files changed, 296 insertions(+), 40 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f2eb540..1eb5a2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,7 +51,7 @@ if(MSVC) xcheck_add_c_compiler_flag(-Wno-reserved-macro-identifier) xcheck_add_c_compiler_flag(-Wno-reserved-identifier) xcheck_add_c_compiler_flag(-Wdeprecated-declarations) - add_compile_definitions(WIN32_LEAN_AND_MEAN) + xcheck_add_c_compiler_flag(/experimental:c11atomics) endif() if(CMAKE_SYSTEM_NAME STREQUAL "WASI") @@ -153,10 +153,16 @@ if(BUILD_QJS_LIBC) list(APPEND qjs_sources quickjs-libc.c) endif() list(APPEND qjs_defines _GNU_SOURCE) +if(WIN32) + list(APPEND qjs_defines WIN32_LEAN_AND_MEAN _WIN32_WINNT=0x0602) +endif() list(APPEND qjs_libs qjs ${CMAKE_DL_LIBS}) +find_package(Threads) +if(NOT CMAKE_SYSTEM_NAME STREQUAL "WASI") + list(APPEND qjs_libs ${CMAKE_THREAD_LIBS_INIT}) +endif() if(NOT MSVC) - find_package(Threads) - list(APPEND qjs_libs ${CMAKE_THREAD_LIBS_INIT} m) + list(APPEND qjs_libs m) endif() add_library(qjs ${qjs_sources}) diff --git a/cutils.c b/cutils.c index 088e75e..0b21d47 100644 --- a/cutils.c +++ b/cutils.c @@ -34,6 +34,9 @@ #include "cutils.h" +#undef NANOSEC +#define NANOSEC ((uint64_t) 1e9) + #pragma GCC visibility push(default) void pstrcpy(char *buf, int buf_size, const char *str) @@ -649,7 +652,7 @@ uint64_t js__hrtime_ns(void) { * performance counter interval, integer math could cause this computation * to overflow. Therefore we resort to floating point math. */ - scaled_freq = (double) frequency.QuadPart / 1e9; + scaled_freq = (double) frequency.QuadPart / NANOSEC; result = (double) counter.QuadPart / scaled_freq; return (uint64_t) result; } @@ -660,7 +663,7 @@ uint64_t js__hrtime_ns(void) { if (clock_gettime(CLOCK_MONOTONIC, &t)) abort(); - return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec; + return t.tv_sec * NANOSEC + t.tv_nsec; } #endif @@ -674,4 +677,219 @@ int64_t js__gettimeofday_us(void) { return ((int64_t)tv.tv_sec * 1000000) + tv.tv_usec; } +/* Cross-platform threading APIs. */ + +#if !defined(EMSCRIPTEN) && !defined(__wasi__) + +#if defined(_WIN32) +typedef void (*js__once_cb)(void); + +typedef struct { + js__once_cb callback; +} js__once_data_t; + +static BOOL WINAPI js__once_inner(INIT_ONCE *once, void *param, void **context) { + js__once_data_t *data = param; + + data->callback(); + + return TRUE; +} + +void js_once(js_once_t *guard, js__once_cb callback) { + js__once_data_t data = { .callback = callback }; + InitOnceExecuteOnce(guard, js__once_inner, (void*) &data, NULL); +} + +void js_mutex_init(js_mutex_t *mutex) { + InitializeCriticalSection(mutex); +} + +void js_mutex_destroy(js_mutex_t *mutex) { + DeleteCriticalSection(mutex); +} + +void js_mutex_lock(js_mutex_t *mutex) { + EnterCriticalSection(mutex); +} + +void js_mutex_unlock(js_mutex_t *mutex) { + LeaveCriticalSection(mutex); +} + +void js_cond_init(js_cond_t *cond) { + InitializeConditionVariable(cond); +} + +void js_cond_destroy(js_cond_t *cond) { + /* nothing to do */ + (void) cond; +} + +void js_cond_signal(js_cond_t *cond) { + WakeConditionVariable(cond); +} + +void js_cond_broadcast(js_cond_t *cond) { + WakeAllConditionVariable(cond); +} + +void js_cond_wait(js_cond_t *cond, js_mutex_t *mutex) { + if (!SleepConditionVariableCS(cond, mutex, INFINITE)) + abort(); +} + +int js_cond_timedwait(js_cond_t *cond, js_mutex_t *mutex, uint64_t timeout) { + if (SleepConditionVariableCS(cond, mutex, (DWORD)(timeout / 1e6))) + return 0; + if (GetLastError() != ERROR_TIMEOUT) + abort(); + return -1; +} + +#else /* !defined(_WIN32) */ + +void js_once(js_once_t *guard, void (*callback)(void)) { + if (pthread_once(guard, callback)) + abort(); +} + +void js_mutex_init(js_mutex_t *mutex) { + if (pthread_mutex_init(mutex, NULL)) + abort(); +} + +void js_mutex_destroy(js_mutex_t *mutex) { + if (pthread_mutex_destroy(mutex)) + abort(); +} + +void js_mutex_lock(js_mutex_t *mutex) { + if (pthread_mutex_lock(mutex)) + abort(); +} + +void js_mutex_unlock(js_mutex_t *mutex) { + if (pthread_mutex_unlock(mutex)) + abort(); +} + +void js_cond_init(js_cond_t *cond) { +#if defined(__APPLE__) && defined(__MACH__) + if (pthread_cond_init(cond, NULL)) + abort(); +#else + pthread_condattr_t attr; + int err; + + if (pthread_condattr_init(&attr)) + abort(); + + if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) + abort(); + + if (pthread_cond_init(cond, &attr)) + abort(); + + if (pthread_condattr_destroy(&attr)) + abort(); +#endif +} + +void js_cond_destroy(js_cond_t *cond) { +#if defined(__APPLE__) && defined(__MACH__) + /* It has been reported that destroying condition variables that have been + * signalled but not waited on can sometimes result in application crashes. + * See https://codereview.chromium.org/1323293005. + */ + pthread_mutex_t mutex; + struct timespec ts; + int err; + + if (pthread_mutex_init(&mutex, NULL)) + abort(); + + if (pthread_mutex_lock(&mutex)) + abort(); + + ts.tv_sec = 0; + ts.tv_nsec = 1; + + err = pthread_cond_timedwait_relative_np(cond, &mutex, &ts); + if (err != 0 && err != ETIMEDOUT) + abort(); + + if (pthread_mutex_unlock(&mutex)) + abort(); + + if (pthread_mutex_destroy(&mutex)) + abort(); +#endif /* defined(__APPLE__) && defined(__MACH__) */ + + if (pthread_cond_destroy(cond)) + abort(); +} + +void js_cond_signal(js_cond_t *cond) { + if (pthread_cond_signal(cond)) + abort(); +} + +void js_cond_broadcast(js_cond_t *cond) { + if (pthread_cond_broadcast(cond)) + abort(); +} + +void js_cond_wait(js_cond_t *cond, js_mutex_t *mutex) { +#if defined(__APPLE__) && defined(__MACH__) + int r; + + errno = 0; + r = pthread_cond_wait(cond, mutex); + + /* Workaround for a bug in OS X at least up to 13.6 + * See https://github.com/libuv/libuv/issues/4165 + */ + if (r == EINVAL && errno == EBUSY) + return; + if (r) + abort(); +#else + if (pthread_cond_wait(cond, mutex)) + abort(); +#endif +} + +int js_cond_timedwait(js_cond_t *cond, js_mutex_t *mutex, uint64_t timeout) { + int r; + struct timespec ts; + +#if !defined(__APPLE__) + timeout += js__hrtime_ns(); +#endif + + ts.tv_sec = timeout / NANOSEC; + ts.tv_nsec = timeout % NANOSEC; +#if defined(__APPLE__) && defined(__MACH__) + r = pthread_cond_timedwait_relative_np(cond, mutex, &ts); +#else + r = pthread_cond_timedwait(cond, mutex, &ts); +#endif + + if (r == 0) + return 0; + + if (r == ETIMEDOUT) + return -1; + + abort(); + + /* Pacify some compilers. */ + return -1; +} + +#endif + +#endif /* !defined(EMSCRIPTEN) && !defined(__wasi__) */ + #pragma GCC visibility pop diff --git a/cutils.h b/cutils.h index 447a72a..f731eb9 100644 --- a/cutils.h +++ b/cutils.h @@ -29,8 +29,10 @@ #include #include -#if defined(_MSC_VER) +#if defined(_WIN32) #include +#endif +#if defined(_MSC_VER) #include #include #define alloca _alloca @@ -43,7 +45,10 @@ #elif defined(__FreeBSD__) #include #endif - +#if !defined(_WIN32) +#include +#include +#endif #if defined(_MSC_VER) && !defined(__clang__) # define likely(x) (x) @@ -426,4 +431,36 @@ static inline size_t js__malloc_usable_size(const void *ptr) #endif } +/* Cross-platform threading APIs. */ + +#if !defined(EMSCRIPTEN) && !defined(__wasi__) + +#if defined(_WIN32) +#define JS_ONCE_INIT INIT_ONCE_STATIC_INIT +typedef INIT_ONCE js_once_t; +typedef CRITICAL_SECTION js_mutex_t; +typedef CONDITION_VARIABLE js_cond_t; +#else +#define JS_ONCE_INIT PTHREAD_ONCE_INIT +typedef pthread_once_t js_once_t; +typedef pthread_mutex_t js_mutex_t; +typedef pthread_cond_t js_cond_t; +#endif + +void js_once(js_once_t *guard, void (*callback)(void)); + +void js_mutex_init(js_mutex_t *mutex); +void js_mutex_destroy(js_mutex_t *mutex); +void js_mutex_lock(js_mutex_t *mutex); +void js_mutex_unlock(js_mutex_t *mutex); + +void js_cond_init(js_cond_t *cond); +void js_cond_destroy(js_cond_t *cond); +void js_cond_signal(js_cond_t *cond); +void js_cond_broadcast(js_cond_t *cond); +void js_cond_wait(js_cond_t *cond, js_mutex_t *mutex); +int js_cond_timedwait(js_cond_t *cond, js_mutex_t *mutex, uint64_t timeout); + +#endif /* !defined(EMSCRIPTEN) && !defined(__wasi__) */ + #endif /* CUTILS_H */ diff --git a/gen/function_source.c b/gen/function_source.c index 7f4c0130eb7abbf6578c5671d24bce5de6893c63..2a6ce3e80b24d99136c5c7c4989262c6f4aeb908 100644 GIT binary patch delta 235 zcmaDU@ls;K9>&Ctdo!4rl8h#+Gs`L@ndm4OR2Ue8NeJ5j#5M<$Kt(CcZH!5i*RzQ8 zS%8I%(?HTGiIW9bRDco!EMk+rS)>?2e6h(2ENol`U{g|(b+{%AvWW5}TOf>1NdX!p z2i5fis!M#b7;6l~ipgE95=@pxAloMIX3c~sgc+C!F>rDe+bp2OS2lf+N;UR$#^lX? U>;{ZXNhXsIaQFjx0-TY|0DSU2761SM delta 235 zcmaDU@ls;K9!ATJdo!4r5|byZGs`L@rs^mdR2Ue8NfR(>03yx7Bv4Tba~q?@UEXEoGv0`!;s|1rp8pyWEyIC_K3SkDCLkyf8#Wo8l@s&*%i9?lEhh^wiE)@1=_nXfq$E!EWs+k|0troSVp3qV*u0pjj|l)` Cbq#?4 delta 48 zcmdnUwUKMWGDgdd%i9?l%_a*liE)@1=_nXfq?k|kWs+mG00~WQVp3o<+Ps*lj|l)( CL=5}@ diff --git a/gen/hello_module.c b/gen/hello_module.c index 91c962ced2919e2c9d27a16c4bbed046f9fc4574..a656f05e472ee9d9535cb28a8b74b0e430245c31 100644 GIT binary patch delta 203 zcmew;_fc-bCdR~xn-4K38R<;^#U#yPV4$O5P?2OZc{XD%6OiI!@?}agnjFcL0OIXt zvSBov{DVmr#1UuS29(--o_Qq;W8&sYj(3bAKvRIa4UEC0A=IR5E)}4r1zhQ1Qf#su zw*q7GTk< Ll+os39yw+Jly*9o delta 203 zcmew;_fc-bCPvGNn-4K3ChJW8#U#yPV4$O5P?4BAc{XD%6OiI!@?}a)o*c=P0OIXt zvSBos{DVmr#1UuS29(--o_Qq;qvhsGj(3bAKvRIa4UEC0A=IR5E)}4r1zhQ1Qf#su zw*sT(-1rQwu5LL;OKXL;d LmApBaM~)c)LKr)> diff --git a/gen/repl.c b/gen/repl.c index 8fd7b249c9cebe82b17b9cd0f39c5b622bbcac19..2097e644cebc9f13ad75c5a69cac417266243544 100644 GIT binary patch delta 17314 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 delta 112 zcmbQkKZk$9I!4Ql>sK*~CMN4B7*rS->u`Z6Ll7r1b#fk)GNZxdNlY0)@;8$iqvhm$ xW-$&EBan1T;^Y8kImRTQ5J+MfkevvYHZTE8Cj+I$C;wvhWJ*ll?8*|(3;-73A4mWI diff --git a/quickjs-atom.h b/quickjs-atom.h index c00b23d..01d1910 100644 --- a/quickjs-atom.h +++ b/quickjs-atom.h @@ -170,11 +170,9 @@ DEF(status, "status") DEF(reason, "reason") DEF(globalThis, "globalThis") DEF(bigint, "bigint") -#ifdef CONFIG_ATOMICS DEF(not_equal, "not-equal") DEF(timed_out, "timed-out") DEF(ok, "ok") -#endif DEF(toJSON, "toJSON") /* class names */ DEF(Object, "Object") diff --git a/quickjs.c b/quickjs.c index 8698067..601afc8 100644 --- a/quickjs.c +++ b/quickjs.c @@ -67,6 +67,11 @@ #define NO_TM_GMTOFF #endif +#if !defined(EMSCRIPTEN) && !defined(__wasi__) +#include "quickjs-c-atomics.h" +#define CONFIG_ATOMICS +#endif + /* dump object free */ //#define DUMP_FREE //#define DUMP_CLOSURE @@ -99,12 +104,6 @@ /* test the GC by forcing it before each object allocation */ //#define FORCE_GC_AT_MALLOC -#ifdef CONFIG_ATOMICS -#include -#include "quickjs-c-atomics.h" -#include -#endif - #define STRINGIFY_(x) #x #define STRINGIFY(x) STRINGIFY_(x) @@ -32561,7 +32560,7 @@ typedef enum BCTagEnum { BC_TAG_OBJECT_REFERENCE, } BCTagEnum; -#define BC_VERSION 9 +#define BC_VERSION 10 typedef struct BCWriterState { JSContext *ctx; @@ -51497,11 +51496,12 @@ static JSValue js_atomics_isLockFree(JSContext *ctx, typedef struct JSAtomicsWaiter { struct list_head link; BOOL linked; - pthread_cond_t cond; + js_cond_t cond; int32_t *ptr; } JSAtomicsWaiter; -static pthread_mutex_t js_atomics_mutex = PTHREAD_MUTEX_INITIALIZER; +static js_once_t js_atomics_once = JS_ONCE_INIT; +static js_mutex_t js_atomics_mutex; static struct list_head js_atomics_waiter_list = LIST_HEAD_INIT(js_atomics_waiter_list); @@ -51543,44 +51543,34 @@ static JSValue js_atomics_wait(JSContext *ctx, /* XXX: inefficient if large number of waiters, should hash on 'ptr' value */ - /* XXX: use Linux futexes when available ? */ - pthread_mutex_lock(&js_atomics_mutex); + js_mutex_lock(&js_atomics_mutex); if (size_log2 == 3) { res = *(int64_t *)ptr != v; } else { res = *(int32_t *)ptr != v; } if (res) { - pthread_mutex_unlock(&js_atomics_mutex); + js_mutex_unlock(&js_atomics_mutex); return JS_AtomToString(ctx, JS_ATOM_not_equal); } waiter = &waiter_s; waiter->ptr = ptr; - pthread_cond_init(&waiter->cond, NULL); + js_cond_init(&waiter->cond); waiter->linked = TRUE; list_add_tail(&waiter->link, &js_atomics_waiter_list); if (timeout == INT64_MAX) { - pthread_cond_wait(&waiter->cond, &js_atomics_mutex); + js_cond_wait(&waiter->cond, &js_atomics_mutex); ret = 0; } else { - /* XXX: use clock monotonic */ - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += timeout / 1000; - ts.tv_nsec += (timeout % 1000) * 1000000; - if (ts.tv_nsec >= 1000000000) { - ts.tv_nsec -= 1000000000; - ts.tv_sec++; - } - ret = pthread_cond_timedwait(&waiter->cond, &js_atomics_mutex, - &ts); + ret = js_cond_timedwait(&waiter->cond, &js_atomics_mutex, timeout * 1e6 /* to ns */); } if (waiter->linked) list_del(&waiter->link); - pthread_mutex_unlock(&js_atomics_mutex); - pthread_cond_destroy(&waiter->cond); - if (ret == ETIMEDOUT) { + js_mutex_unlock(&js_atomics_mutex); + js_cond_destroy(&waiter->cond); + if (ret == -1) { return JS_AtomToString(ctx, JS_ATOM_timed_out); } else { return JS_AtomToString(ctx, JS_ATOM_ok); @@ -51612,7 +51602,7 @@ static JSValue js_atomics_notify(JSContext *ctx, n = 0; if (abuf->shared && count > 0) { - pthread_mutex_lock(&js_atomics_mutex); + js_mutex_lock(&js_atomics_mutex); init_list_head(&waiter_list); list_for_each_safe(el, el1, &js_atomics_waiter_list) { waiter = list_entry(el, JSAtomicsWaiter, link); @@ -51627,9 +51617,9 @@ static JSValue js_atomics_notify(JSContext *ctx, } list_for_each(el, &waiter_list) { waiter = list_entry(el, JSAtomicsWaiter, link); - pthread_cond_signal(&waiter->cond); + js_cond_signal(&waiter->cond); } - pthread_mutex_unlock(&js_atomics_mutex); + js_mutex_unlock(&js_atomics_mutex); } return js_int32(n); } @@ -51654,8 +51644,15 @@ static const JSCFunctionListEntry js_atomics_obj[] = { JS_OBJECT_DEF("Atomics", js_atomics_funcs, countof(js_atomics_funcs), JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE ), }; +static void js__atomics_init(void) { + js_mutex_init(&js_atomics_mutex); +} + +/* TODO(saghul) make this public and not dependent on typed arrays? */ void JS_AddIntrinsicAtomics(JSContext *ctx) { + js_once(&js_atomics_once, js__atomics_init); + /* add Atomics as autoinit object */ JS_SetPropertyFunctionList(ctx, ctx->global_obj, js_atomics_obj, countof(js_atomics_obj)); } diff --git a/test262.conf b/test262.conf index 1763269..c004bd8 100644 --- a/test262.conf +++ b/test262.conf @@ -69,7 +69,7 @@ arraybuffer-transfer arrow-function async-functions async-iteration -Atomics=skip # disabled because of Windows <-> pthreads +Atomics Atomics.waitAsync=skip BigInt caller