Skip to content

Support os.Worker on Windows #1003

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Mar 31, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you mention the requirement of atomics in https://quickjs-ng.github.io/quickjs/supported_platforms ?

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:
Expand Down
11 changes: 11 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, do you know what versions those are?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I didn't mess up my notes: 3.22.1-1ubuntu1 (old), 3.31.6 (new)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good to 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")
Expand Down
76 changes: 72 additions & 4 deletions cutils.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@
#if !defined(_MSC_VER)
#include <sys/time.h>
#endif
#if defined(_WIN32)
#include <windows.h>
#include <process.h> // _beginthread
#endif

#include "cutils.h"

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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
Expand Down
19 changes: 18 additions & 1 deletion cutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/supported_platforms.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 `<stdatomic.h>` |
| FreeBSD | * | Limited testing |
| OpenBSD | * | Limited testing |
| NetBSD | * | Limited testing |
Expand Down
Loading