diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b174f0144..901d4dd8f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -209,31 +209,6 @@ jobs: cl.exe /DJS_NAN_BOXING=0 /Zs cxxtest.cc cl.exe /DJS_NAN_BOXING=1 /Zs cxxtest.cc - windows-msvc-vs2019: - runs-on: windows-2019 - strategy: - fail-fast: false - matrix: - arch: [x64, Win32] - buildType: [Debug, Release] - steps: - - uses: actions/checkout@v4 - - name: build - run: | - cmake -B build -DQJS_BUILD_EXAMPLES=ON -G "Visual Studio 16 2019" -A ${{matrix.arch}} - cmake --build build --config ${{matrix.buildType}} --target qjs_exe - - name: stats - run: | - build\${{matrix.buildType}}\qjs.exe -qd - - name: Set up Visual Studio shell - uses: egor-tensin/vs-shell@v2 - with: - arch: ${{ matrix.arch == 'x64' && 'x64' || 'x86' }} - - name: cxxtest - run: | - cl.exe /DJS_NAN_BOXING=0 /Zs cxxtest.cc - cl.exe /DJS_NAN_BOXING=1 /Zs cxxtest.cc - windows-clang: runs-on: windows-latest strategy: diff --git a/CMakeLists.txt b/CMakeLists.txt index 133de63f5..5d7d19511 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,17 @@ set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS ON) set(CMAKE_C_STANDARD 11) +# MINGW doesn't exist in older cmake versions, newer versions don't know +# about CMAKE_COMPILER_IS_MINGW, and there is no unique CMAKE_C_COMPILER_ID +# for mingw-based compilers... +if(MINGW) + # do nothing +elseif(CMAKE_C_COMPILER MATCHES "mingw") + set(MINGW TRUE) +else() + set(MINGW FALSE) +endif() + if(NOT CMAKE_BUILD_TYPE) message(STATUS "No build type selected, default to Release") set(CMAKE_BUILD_TYPE "Release") diff --git a/cutils.c b/cutils.c index 438087d06..a9efdcbd6 100644 --- a/cutils.c +++ b/cutils.c @@ -31,6 +31,10 @@ #if !defined(_MSC_VER) #include #endif +#if defined(_WIN32) +#include +#include // _beginthread +#endif #include "cutils.h" @@ -1199,8 +1203,7 @@ int64_t js__gettimeofday_us(void) { /*--- Cross-platform threading APIs. ----*/ -#if !defined(EMSCRIPTEN) && !defined(__wasi__) - +#if JS_HAVE_THREADS #if defined(_WIN32) typedef void (*js__once_cb)(void); @@ -1267,6 +1270,37 @@ int js_cond_timedwait(js_cond_t *cond, js_mutex_t *mutex, uint64_t timeout) { return -1; } +int js_thread_create(js_thread_t *thrd, void (*start)(void *), void *arg, + int flags) +{ + HANDLE h, cp; + + *thrd = INVALID_HANDLE_VALUE; + if (flags & ~JS_THREAD_CREATE_DETACHED) + return -1; + h = (HANDLE)_beginthread(start, /*stacksize*/2<<20, arg); + if (!h) + return -1; + if (flags & JS_THREAD_CREATE_DETACHED) + return 0; + // _endthread() automatically closes the handle but we want to wait on + // it so make a copy. Race-y for very short-lived threads. Can be solved + // by switching to _beginthreadex(CREATE_SUSPENDED) but means changing + // |start| from __cdecl to __stdcall. + cp = GetCurrentProcess(); + if (DuplicateHandle(cp, h, cp, thrd, 0, FALSE, DUPLICATE_SAME_ACCESS)) + return 0; + return -1; +} + +int js_thread_join(js_thread_t thrd) +{ + if (WaitForSingleObject(thrd, INFINITE)) + return -1; + CloseHandle(thrd); + return 0; +} + #else /* !defined(_WIN32) */ void js_once(js_once_t *guard, void (*callback)(void)) { @@ -1407,9 +1441,43 @@ int js_cond_timedwait(js_cond_t *cond, js_mutex_t *mutex, uint64_t timeout) { return -1; } -#endif +int js_thread_create(js_thread_t *thrd, void (*start)(void *), void *arg, + int flags) +{ + union { + void (*x)(void *); + void *(*f)(void *); + } u = {start}; + pthread_attr_t attr; + int ret; + + if (flags & ~JS_THREAD_CREATE_DETACHED) + return -1; + if (pthread_attr_init(&attr)) + return -1; + ret = -1; + if (pthread_attr_setstacksize(&attr, 2<<20)) + goto fail; + if (flags & JS_THREAD_CREATE_DETACHED) + if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) + goto fail; + if (pthread_create(thrd, &attr, u.f, arg)) + goto fail; + ret = 0; +fail: + pthread_attr_destroy(&attr); + return ret; +} + +int js_thread_join(js_thread_t thrd) +{ + if (pthread_join(thrd, NULL)) + return -1; + return 0; +} -#endif /* !defined(EMSCRIPTEN) && !defined(__wasi__) */ +#endif /* !defined(_WIN32) */ +#endif /* JS_HAVE_THREADS */ #ifdef __GNUC__ #pragma GCC visibility pop diff --git a/cutils.h b/cutils.h index 4639a6b93..b15328765 100644 --- a/cutils.h +++ b/cutils.h @@ -563,18 +563,26 @@ static inline size_t js__malloc_usable_size(const void *ptr) /* Cross-platform threading APIs. */ -#if !defined(EMSCRIPTEN) && !defined(__wasi__) +#if defined(EMSCRIPTEN) || defined(__wasi__) + +#define JS_HAVE_THREADS 0 + +#else + +#define JS_HAVE_THREADS 1 #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; +typedef HANDLE js_thread_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; +typedef pthread_t js_thread_t; #endif void js_once(js_once_t *guard, void (*callback)(void)); @@ -591,6 +599,15 @@ 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); +enum { + JS_THREAD_CREATE_DETACHED = 1, +}; + +// creates threads with 2 MB stacks (glibc default) +int js_thread_create(js_thread_t *thrd, void (*start)(void *), void *arg, + int flags); +int js_thread_join(js_thread_t thrd); + #endif /* !defined(EMSCRIPTEN) && !defined(__wasi__) */ #ifdef __cplusplus diff --git a/docs/docs/supported_platforms.md b/docs/docs/supported_platforms.md index 94149ed9c..bb817b3d4 100644 --- a/docs/docs/supported_platforms.md +++ b/docs/docs/supported_platforms.md @@ -8,7 +8,7 @@ sidebar_position: 8 |---|---|---| | GNU/Linux | * | glibc and musl are supported | | macOS | macOS >= 11 | Currently supported macOS releases | -| Windows | >= Windows 7* | VS >= 2022 and Clang are supported | +| Windows | >= Windows 7* | VS >= 2022 and Clang are supported; requires `` | | FreeBSD | * | Limited testing | | OpenBSD | * | Limited testing | | NetBSD | * | Limited testing | diff --git a/quickjs-libc.c b/quickjs-libc.c index f9af760e3..c87c04fbd 100644 --- a/quickjs-libc.c +++ b/quickjs-libc.c @@ -80,20 +80,15 @@ extern char **environ; #endif /* _WIN32 */ -#if !defined(_WIN32) && !defined(__wasi__) -/* enable the os.Worker API. IT relies on POSIX threads */ -#define USE_WORKER -#endif - -#ifdef USE_WORKER -#include -#include "quickjs-c-atomics.h" -#endif - #include "cutils.h" #include "list.h" #include "quickjs-libc.h" +#if JS_HAVE_THREADS +#include "quickjs-c-atomics.h" +#define USE_WORKER // enable os.Worker +#endif + #ifndef MAX_SAFE_INTEGER // already defined in amalgamation builds #define MAX_SAFE_INTEGER (((int64_t) 1 << 53) - 1) #endif @@ -131,6 +126,8 @@ typedef struct { JSValue func; } JSOSTimer; +#ifdef USE_WORKER + typedef struct { struct list_head link; uint8_t *data; @@ -140,14 +137,20 @@ typedef struct { size_t sab_tab_len; } JSWorkerMessage; +typedef struct JSWaker { +#ifdef _WIN32 + HANDLE handle; +#else + int read_fd; + int write_fd; +#endif +} JSWaker; + typedef struct { int ref_count; -#ifdef USE_WORKER - pthread_mutex_t mutex; -#endif + js_mutex_t mutex; struct list_head msg_queue; /* list of JSWorkerMessage.link */ - int read_fd; - int write_fd; + JSWaker waker; } JSWorkerMessagePipe; typedef struct { @@ -156,6 +159,8 @@ typedef struct { JSValue on_message_func; } JSWorkerMessageHandler; +#endif // USE_WORKER + typedef struct JSThreadState { struct list_head os_rw_handlers; /* list of JSOSRWHandler.link */ struct list_head os_signal_handlers; /* list JSOSSignalHandler.link */ @@ -165,7 +170,11 @@ typedef struct JSThreadState { int64_t next_timer_id; /* for setTimeout / setInterval */ bool can_js_os_poll; /* not used in the main thread */ +#ifdef USE_WORKER JSWorkerMessagePipe *recv_pipe, *send_pipe; +#else + void *recv_pipe; +#endif // USE_WORKER JSClassID std_file_class_id; JSClassID worker_class_id; } JSThreadState; @@ -2393,61 +2402,81 @@ static int js_os_run_timers(JSRuntime *rt, JSContext *ctx, JSThreadState *ts, in return 0; } -#if defined(_WIN32) +#ifdef USE_WORKER -static int js_os_poll(JSContext *ctx) +#ifdef _WIN32 + +static int js_waker_init(JSWaker *w) { - JSRuntime *rt = JS_GetRuntime(ctx); - JSThreadState *ts = js_get_thread_state(rt); - int min_delay, console_fd; - JSOSRWHandler *rh; - struct list_head *el; + w->handle = CreateEvent(NULL, TRUE, FALSE, NULL); + return w->handle ? 0 : -1; +} - /* XXX: handle signals if useful */ +static void js_waker_signal(JSWaker *w) +{ + SetEvent(w->handle); +} - if (js_os_run_timers(rt, ctx, ts, &min_delay)) +static void js_waker_clear(JSWaker *w) +{ + ResetEvent(w->handle); +} + +static void js_waker_close(JSWaker *w) +{ + CloseHandle(w->handle); + w->handle = INVALID_HANDLE_VALUE; +} + +#else // !_WIN32 + +static int js_waker_init(JSWaker *w) +{ + int fds[2]; + + if (pipe(fds) < 0) return -1; - if (min_delay == 0) - return 0; // expired timer - if (min_delay < 0) - if (list_empty(&ts->os_rw_handlers)) - return -1; /* no more events */ + w->read_fd = fds[0]; + w->write_fd = fds[1]; + return 0; +} - console_fd = -1; - list_for_each(el, &ts->os_rw_handlers) { - rh = list_entry(el, JSOSRWHandler, link); - if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) { - console_fd = rh->fd; +static void js_waker_signal(JSWaker *w) +{ + int ret; + + for(;;) { + ret = write(w->write_fd, "", 1); + if (ret == 1) + break; + if (ret < 0 && (errno != EAGAIN || errno != EINTR)) break; - } } +} - if (console_fd >= 0) { - DWORD ti, ret; - HANDLE handle; - if (min_delay == -1) - ti = INFINITE; - else - ti = min_delay; - handle = (HANDLE)_get_osfhandle(console_fd); - ret = WaitForSingleObject(handle, ti); - if (ret == WAIT_OBJECT_0) { - list_for_each(el, &ts->os_rw_handlers) { - rh = list_entry(el, JSOSRWHandler, link); - if (rh->fd == console_fd && !JS_IsNull(rh->rw_func[0])) { - return call_handler(ctx, rh->rw_func[0]); - /* must stop because the list may have been modified */ - } - } - } - } else { - Sleep(min_delay); +static void js_waker_clear(JSWaker *w) +{ + uint8_t buf[16]; + int ret; + + for(;;) { + ret = read(w->read_fd, buf, sizeof(buf)); + if (ret >= 0) + break; + if (errno != EAGAIN && errno != EINTR) + break; } - return 0; } -#else -#ifdef USE_WORKER +static void js_waker_close(JSWaker *w) +{ + close(w->read_fd); + close(w->write_fd); + w->read_fd = -1; + w->write_fd = -1; +} + +#endif // _WIN32 static void js_free_message(JSWorkerMessage *msg); @@ -2461,7 +2490,7 @@ static int handle_posted_message(JSRuntime *rt, JSContext *ctx, JSWorkerMessage *msg; JSValue obj, data_obj, func, retval; - pthread_mutex_lock(&ps->mutex); + js_mutex_lock(&ps->mutex); if (!list_empty(&ps->msg_queue)) { el = ps->msg_queue.next; msg = list_entry(el, JSWorkerMessage, link); @@ -2469,19 +2498,11 @@ static int handle_posted_message(JSRuntime *rt, JSContext *ctx, /* remove the message from the queue */ list_del(&msg->link); - if (list_empty(&ps->msg_queue)) { - uint8_t buf[16]; - int ret; - for(;;) { - ret = read(ps->read_fd, buf, sizeof(buf)); - if (ret >= 0) - break; - if (errno != EAGAIN && errno != EINTR) - break; - } - } + // drain read end of pipe + if (list_empty(&ps->msg_queue)) + js_waker_clear(&ps->waker); - pthread_mutex_unlock(&ps->mutex); + js_mutex_unlock(&ps->mutex); data_obj = JS_ReadObject(ctx, msg->data, msg->data_len, JS_READ_OBJ_SAB | JS_READ_OBJ_REFERENCE); @@ -2511,19 +2532,84 @@ static int handle_posted_message(JSRuntime *rt, JSContext *ctx, } ret = 1; } else { - pthread_mutex_unlock(&ps->mutex); + js_mutex_unlock(&ps->mutex); ret = 0; } return ret; } -#else -static int handle_posted_message(JSRuntime *rt, JSContext *ctx, - JSWorkerMessageHandler *port) + +#endif // USE_WORKER + +#if defined(_WIN32) +static int js_os_poll(JSContext *ctx) { + JSRuntime *rt = JS_GetRuntime(ctx); + JSThreadState *ts = js_get_thread_state(rt); + int min_delay, count; + JSOSRWHandler *rh; + struct list_head *el; + HANDLE handles[MAXIMUM_WAIT_OBJECTS]; // 64 + + /* XXX: handle signals if useful */ + + if (js_os_run_timers(rt, ctx, ts, &min_delay)) + return -1; + if (min_delay == 0) + return 0; // expired timer + if (min_delay < 0) + if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->port_list)) + return -1; /* no more events */ + + count = 0; + list_for_each(el, &ts->os_rw_handlers) { + rh = list_entry(el, JSOSRWHandler, link); + if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) + handles[count++] = (HANDLE)_get_osfhandle(rh->fd); // stdin + if (count == (int)countof(handles)) + break; + } + + list_for_each(el, &ts->port_list) { + JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link); + if (JS_IsNull(port->on_message_func)) + continue; + handles[count++] = port->recv_pipe->waker.handle; + if (count == (int)countof(handles)) + break; + } + + if (count > 0) { + DWORD ret, timeout = INFINITE; + if (min_delay != -1) + timeout = min_delay; + ret = WaitForMultipleObjects(count, handles, FALSE, timeout); + if (ret < count) { + list_for_each(el, &ts->os_rw_handlers) { + rh = list_entry(el, JSOSRWHandler, link); + if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) { + return call_handler(ctx, rh->rw_func[0]); + /* must stop because the list may have been modified */ + } + } + + list_for_each(el, &ts->port_list) { + JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link); + if (!JS_IsNull(port->on_message_func)) { + JSWorkerMessagePipe *ps = port->recv_pipe; + if (ps->waker.handle == handles[ret]) { + if (handle_posted_message(rt, ctx, port)) + goto done; + } + } + } + } + } else { + Sleep(min_delay); + } +done: return 0; } -#endif - +#else // !defined(_WIN32) static int js_os_poll(JSContext *ctx) { JSRuntime *rt = JS_GetRuntime(ctx); @@ -2577,14 +2663,16 @@ static int js_os_poll(JSContext *ctx) FD_SET(rh->fd, &wfds); } +#ifdef USE_WORKER list_for_each(el, &ts->port_list) { JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link); if (!JS_IsNull(port->on_message_func)) { JSWorkerMessagePipe *ps = port->recv_pipe; - fd_max = max_int(fd_max, ps->read_fd); - FD_SET(ps->read_fd, &rfds); + fd_max = max_int(fd_max, ps->waker.read_fd); + FD_SET(ps->waker.read_fd, &rfds); } } +#endif // USE_WORKER ret = select(fd_max + 1, &rfds, &wfds, NULL, tvp); if (ret > 0) { @@ -2601,22 +2689,25 @@ static int js_os_poll(JSContext *ctx) /* must stop because the list may have been modified */ } } - +#ifdef USE_WORKER list_for_each(el, &ts->port_list) { JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link); if (!JS_IsNull(port->on_message_func)) { JSWorkerMessagePipe *ps = port->recv_pipe; - if (FD_ISSET(ps->read_fd, &rfds)) { + if (FD_ISSET(ps->waker.read_fd, &rfds)) { if (handle_posted_message(rt, ctx, port)) goto done; } } } +#endif // USE_WORKER } - done: + goto done; // silence unused label warning +done: return 0; } -#endif /* !_WIN32 */ +#endif // defined(_WIN32) + static JSValue make_obj_error(JSContext *ctx, JSValue obj, @@ -3486,22 +3577,17 @@ static void js_sab_dup(void *opaque, void *ptr) static JSWorkerMessagePipe *js_new_message_pipe(void) { JSWorkerMessagePipe *ps; - int pipe_fds[2]; - - if (pipe(pipe_fds) < 0) - return NULL; ps = malloc(sizeof(*ps)); - if (!ps) { - close(pipe_fds[0]); - close(pipe_fds[1]); + if (!ps) + return NULL; + if (js_waker_init(&ps->waker)) { + free(ps); return NULL; } ps->ref_count = 1; init_list_head(&ps->msg_queue); - pthread_mutex_init(&ps->mutex, NULL); - ps->read_fd = pipe_fds[0]; - ps->write_fd = pipe_fds[1]; + js_mutex_init(&ps->mutex); return ps; } @@ -3539,9 +3625,8 @@ static void js_free_message_pipe(JSWorkerMessagePipe *ps) msg = list_entry(el, JSWorkerMessage, link); js_free_message(msg); } - pthread_mutex_destroy(&ps->mutex); - close(ps->read_fd); - close(ps->write_fd); + js_mutex_destroy(&ps->mutex); + js_waker_close(&ps->waker); free(ps); } } @@ -3573,7 +3658,7 @@ static JSClassDef js_worker_class = { .finalizer = js_worker_finalizer, }; -static void *worker_func(void *opaque) +static void worker_func(void *opaque) { WorkerFuncArgs *args = opaque; JSRuntime *rt; @@ -3620,7 +3705,6 @@ static void *worker_func(void *opaque) js_std_free_handlers(rt); JS_FreeContext(ctx); JS_FreeRuntime(rt); - return NULL; } static JSValue js_worker_ctor_internal(JSContext *ctx, JSValueConst new_target, @@ -3662,8 +3746,7 @@ static JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target, { JSRuntime *rt = JS_GetRuntime(ctx); WorkerFuncArgs *args = NULL; - pthread_t tid; - pthread_attr_t attr; + js_thread_t thr; JSValue obj = JS_UNDEFINED; int ret; const char *filename = NULL, *basename; @@ -3710,14 +3793,7 @@ static JSValue js_worker_ctor(JSContext *ctx, JSValueConst new_target, if (JS_IsException(obj)) goto fail; - pthread_attr_init(&attr); - /* no join at the end */ - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - // musl libc gives threads 80 kb stacks, much smaller than - // JS_DEFAULT_STACK_SIZE (1 MB) - pthread_attr_setstacksize(&attr, 2 << 20); // 2 MB, glibc default - ret = pthread_create(&tid, &attr, worker_func, args); - pthread_attr_destroy(&attr); + ret = js_thread_create(&thr, worker_func, args, JS_THREAD_CREATE_DETACHED); if (ret != 0) { JS_ThrowTypeError(ctx, "could not create worker"); goto fail; @@ -3792,21 +3868,12 @@ static JSValue js_worker_postMessage(JSContext *ctx, JSValueConst this_val, } ps = worker->send_pipe; - pthread_mutex_lock(&ps->mutex); + js_mutex_lock(&ps->mutex); /* indicate that data is present */ - if (list_empty(&ps->msg_queue)) { - uint8_t ch = '\0'; - int ret; - for(;;) { - ret = write(ps->write_fd, &ch, 1); - if (ret == 1) - break; - if (ret < 0 && (errno != EAGAIN || errno != EINTR)) - break; - } - } + if (list_empty(&ps->msg_queue)) + js_waker_signal(&ps->waker); list_add_tail(&msg->link, &ps->msg_queue); - pthread_mutex_unlock(&ps->mutex); + js_mutex_unlock(&ps->mutex); return JS_UNDEFINED; fail: if (msg) { diff --git a/run-test262.c b/run-test262.c index c1717fb51..03afe82df 100644 --- a/run-test262.c +++ b/run-test262.c @@ -35,12 +35,9 @@ #ifdef _WIN32 #include #include -typedef HANDLE js_thread_t; #else #include -#include #include -typedef pthread_t js_thread_t; #endif #include "cutils.h" @@ -530,49 +527,6 @@ static JSValue js_evalScript_262(JSContext *ctx, JSValueConst this_val, return ret; } -static void start_thread(js_thread_t *thrd, void *(*start)(void *), void *arg) -{ - // musl libc gives threads 80 kb stacks, much smaller than - // JS_DEFAULT_STACK_SIZE (1 MB) - static const unsigned stacksize = 2 << 20; // 2 MB, glibc default -#ifdef _WIN32 - HANDLE h, cp; - - cp = GetCurrentProcess(); - h = (HANDLE)_beginthread((void (*)(void *))(void *)start, stacksize, arg); - if (!h) - fatal(1, "_beginthread error"); - // _endthread() automatically closes the handle but we want to wait on - // it so make a copy. Race-y for very short-lived threads. Can be solved - // by switching to _beginthreadex(CREATE_SUSPENDED) but means changing - // |start| from __cdecl to __stdcall. - if (!DuplicateHandle(cp, h, cp, thrd, 0, false, DUPLICATE_SAME_ACCESS)) - fatal(1, "DuplicateHandle error"); -#else - pthread_attr_t attr; - - if (pthread_attr_init(&attr)) - fatal(1, "pthread_attr_init"); - if (pthread_attr_setstacksize(&attr, stacksize)) - fatal(1, "pthread_attr_setstacksize"); - if (pthread_create(thrd, &attr, start, arg)) - fatal(1, "pthread_create error"); - pthread_attr_destroy(&attr); -#endif -} - -static void join_thread(js_thread_t thrd) -{ -#ifdef _WIN32 - if (WaitForSingleObject(thrd, INFINITE)) - fatal(1, "WaitForSingleObject error"); - CloseHandle(thrd); -#else - if (pthread_join(thrd, NULL)) - fatal(1, "pthread_join error"); -#endif -} - static long cpu_count(void) { #ifdef _WIN32 @@ -621,7 +575,7 @@ typedef struct { static JSValue add_helpers1(JSContext *ctx); static void add_helpers(JSContext *ctx); -static void *agent_start(void *arg) +static void agent_start(void *arg) { ThreadLocalStorage *tls; Test262Agent *agent; @@ -697,7 +651,6 @@ static void *agent_start(void *arg) JS_FreeContext(ctx); JS_FreeRuntime(rt); - return NULL; } static JSValue js_agent_start(JSContext *ctx, JSValueConst this_val, @@ -721,7 +674,7 @@ static JSValue js_agent_start(JSContext *ctx, JSValueConst this_val, agent->tls = tls; JS_FreeCString(ctx, script); list_add_tail(&agent->link, &tls->agent_list); - start_thread(&agent->tid, agent_start, agent); + js_thread_create(&agent->tid, agent_start, agent, /*flags*/0); return JS_UNDEFINED; } @@ -733,7 +686,7 @@ static void js_agent_free(JSContext *ctx) list_for_each_safe(el, el1, &tls->agent_list) { agent = list_entry(el, Test262Agent, link); - join_thread(agent->tid); + js_thread_join(agent->tid); JS_FreeValue(ctx, agent->broadcast_sab); list_del(&agent->link); free(agent); @@ -1773,6 +1726,7 @@ int run_test_buf(ThreadLocalStorage *tls, const char *filename, char *harness, if (rt == NULL) { fatal(1, "JS_NewRuntime failure"); } + JS_SetDumpFlags(rt, JS_DUMP_LEAKS); JS_SetRuntimeOpaque(rt, tls); js_std_init_handlers(rt); ctx = JS_NewCustomContext(rt); @@ -2018,6 +1972,7 @@ int run_test262_harness_test(ThreadLocalStorage *tls, const char *filename, if (rt == NULL) { fatal(1, "JS_NewRuntime failure"); } + JS_SetDumpFlags(rt, JS_DUMP_LEAKS); JS_SetRuntimeOpaque(rt, tls); ctx = JS_NewContext(rt); if (ctx == NULL) { @@ -2083,7 +2038,7 @@ int run_test262_harness_test(ThreadLocalStorage *tls, const char *filename, clock_t last_clock; -void *show_progress(void *unused) { +void show_progress(void *unused) { int interval = 1000*1000*1000 / 4; // 250 ms js_mutex_lock(&progress_mutex); @@ -2096,7 +2051,6 @@ void *show_progress(void *unused) { fflush(stderr); } js_mutex_unlock(&progress_mutex); - return NULL; } enum { INCLUDE, EXCLUDE, SKIP }; @@ -2112,7 +2066,7 @@ int include_exclude_or_skip(int i) // naming is hard... return INCLUDE; } -void *run_test_dir_list(void *arg) +void run_test_dir_list(void *arg) { ThreadLocalStorage tls_s, *tls = &tls_s; const char *p; @@ -2129,7 +2083,6 @@ void *run_test_dir_list(void *arg) if (verbose > 1 || (slow_test_threshold && msec >= slow_test_threshold)) fprintf(stderr, "%s (%d ms)\n", p, msec); } - return NULL; } void help(void) @@ -2304,15 +2257,17 @@ int main(int argc, char **argv) } js_cond_init(&progress_cond); js_mutex_init(&progress_mutex); - start_thread(&progress_thread, show_progress, NULL); - for (i = 0; i < nthreads; i++) - start_thread(&threads[i], run_test_dir_list, (void *)(uintptr_t)i); + js_thread_create(&progress_thread, show_progress, NULL, /*flags*/0); + for (i = 0; i < nthreads; i++) { + js_thread_create(&threads[i], run_test_dir_list, + (void *)(uintptr_t)i, /*flags*/0); + } for (i = 0; i < nthreads; i++) - join_thread(threads[i]); + js_thread_join(threads[i]); js_mutex_lock(&progress_mutex); js_cond_signal(&progress_cond); js_mutex_unlock(&progress_mutex); - join_thread(progress_thread); + js_thread_join(progress_thread); js_mutex_destroy(&progress_mutex); js_cond_destroy(&progress_cond); } else { diff --git a/tests/test_worker.js b/tests/test_worker.js index 8309c1891..d1660ce54 100644 --- a/tests/test_worker.js +++ b/tests/test_worker.js @@ -40,6 +40,4 @@ function test_worker() }; } -if (os.platform !== 'win32') { - test_worker(); -} +test_worker();