Skip to content

Commit 8bb41b2

Browse files
author
Fabrice Bellard
committed
enabled os.Worker on Windows (bnoordhuis)
1 parent bff5525 commit 8bb41b2

File tree

1 file changed

+185
-107
lines changed

1 file changed

+185
-107
lines changed

quickjs-libc.c

Lines changed: 185 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,8 @@ typedef sig_t sighandler_t;
6464

6565
#endif
6666

67-
#if !defined(_WIN32)
68-
/* enable the os.Worker API. IT relies on POSIX threads */
67+
/* enable the os.Worker API. It relies on POSIX threads */
6968
#define USE_WORKER
70-
#endif
7169

7270
#ifdef USE_WORKER
7371
#include <pthread.h>
@@ -114,14 +112,22 @@ typedef struct {
114112
size_t sab_tab_len;
115113
} JSWorkerMessage;
116114

115+
typedef struct JSWaker {
116+
#ifdef _WIN32
117+
HANDLE handle;
118+
#else
119+
int read_fd;
120+
int write_fd;
121+
#endif
122+
} JSWaker;
123+
117124
typedef struct {
118125
int ref_count;
119126
#ifdef USE_WORKER
120127
pthread_mutex_t mutex;
121128
#endif
122129
struct list_head msg_queue; /* list of JSWorkerMessage.link */
123-
int read_fd;
124-
int write_fd;
130+
JSWaker waker;
125131
} JSWorkerMessagePipe;
126132

127133
typedef struct {
@@ -2138,82 +2144,81 @@ static void call_handler(JSContext *ctx, JSValueConst func)
21382144
JS_FreeValue(ctx, ret);
21392145
}
21402146

2141-
#if defined(_WIN32)
2147+
#ifdef USE_WORKER
21422148

2143-
static int js_os_poll(JSContext *ctx)
2149+
#ifdef _WIN32
2150+
2151+
static int js_waker_init(JSWaker *w)
21442152
{
2145-
JSRuntime *rt = JS_GetRuntime(ctx);
2146-
JSThreadState *ts = JS_GetRuntimeOpaque(rt);
2147-
int min_delay, console_fd;
2148-
int64_t cur_time, delay;
2149-
JSOSRWHandler *rh;
2150-
struct list_head *el;
2153+
w->handle = CreateEvent(NULL, TRUE, FALSE, NULL);
2154+
return w->handle ? 0 : -1;
2155+
}
21512156

2152-
/* XXX: handle signals if useful */
2157+
static void js_waker_signal(JSWaker *w)
2158+
{
2159+
SetEvent(w->handle);
2160+
}
21532161

2154-
if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers))
2155-
return -1; /* no more events */
2162+
static void js_waker_clear(JSWaker *w)
2163+
{
2164+
ResetEvent(w->handle);
2165+
}
21562166

2157-
/* XXX: only timers and basic console input are supported */
2158-
if (!list_empty(&ts->os_timers)) {
2159-
cur_time = get_time_ms();
2160-
min_delay = 10000;
2161-
list_for_each(el, &ts->os_timers) {
2162-
JSOSTimer *th = list_entry(el, JSOSTimer, link);
2163-
delay = th->timeout - cur_time;
2164-
if (delay <= 0) {
2165-
JSValue func;
2166-
/* the timer expired */
2167-
func = th->func;
2168-
th->func = JS_UNDEFINED;
2169-
free_timer(rt, th);
2170-
call_handler(ctx, func);
2171-
JS_FreeValue(ctx, func);
2172-
return 0;
2173-
} else if (delay < min_delay) {
2174-
min_delay = delay;
2175-
}
2176-
}
2177-
} else {
2178-
min_delay = -1;
2179-
}
2167+
static void js_waker_close(JSWaker *w)
2168+
{
2169+
CloseHandle(w->handle);
2170+
w->handle = INVALID_HANDLE_VALUE;
2171+
}
21802172

2181-
console_fd = -1;
2182-
list_for_each(el, &ts->os_rw_handlers) {
2183-
rh = list_entry(el, JSOSRWHandler, link);
2184-
if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) {
2185-
console_fd = rh->fd;
2173+
#else // !_WIN32
2174+
2175+
static int js_waker_init(JSWaker *w)
2176+
{
2177+
int fds[2];
2178+
2179+
if (pipe(fds) < 0)
2180+
return -1;
2181+
w->read_fd = fds[0];
2182+
w->write_fd = fds[1];
2183+
return 0;
2184+
}
2185+
2186+
static void js_waker_signal(JSWaker *w)
2187+
{
2188+
int ret;
2189+
2190+
for(;;) {
2191+
ret = write(w->write_fd, "", 1);
2192+
if (ret == 1)
2193+
break;
2194+
if (ret < 0 && (errno != EAGAIN || errno != EINTR))
21862195
break;
2187-
}
21882196
}
2197+
}
21892198

2190-
if (console_fd >= 0) {
2191-
DWORD ti, ret;
2192-
HANDLE handle;
2193-
if (min_delay == -1)
2194-
ti = INFINITE;
2195-
else
2196-
ti = min_delay;
2197-
handle = (HANDLE)_get_osfhandle(console_fd);
2198-
ret = WaitForSingleObject(handle, ti);
2199-
if (ret == WAIT_OBJECT_0) {
2200-
list_for_each(el, &ts->os_rw_handlers) {
2201-
rh = list_entry(el, JSOSRWHandler, link);
2202-
if (rh->fd == console_fd && !JS_IsNull(rh->rw_func[0])) {
2203-
call_handler(ctx, rh->rw_func[0]);
2204-
/* must stop because the list may have been modified */
2205-
break;
2206-
}
2207-
}
2208-
}
2209-
} else {
2210-
Sleep(min_delay);
2199+
static void js_waker_clear(JSWaker *w)
2200+
{
2201+
uint8_t buf[16];
2202+
int ret;
2203+
2204+
for(;;) {
2205+
ret = read(w->read_fd, buf, sizeof(buf));
2206+
if (ret >= 0)
2207+
break;
2208+
if (errno != EAGAIN && errno != EINTR)
2209+
break;
22112210
}
2212-
return 0;
22132211
}
2214-
#else
22152212

2216-
#ifdef USE_WORKER
2213+
static void js_waker_close(JSWaker *w)
2214+
{
2215+
close(w->read_fd);
2216+
close(w->write_fd);
2217+
w->read_fd = -1;
2218+
w->write_fd = -1;
2219+
}
2220+
2221+
#endif // _WIN32
22172222

22182223
static void js_free_message(JSWorkerMessage *msg);
22192224

@@ -2235,17 +2240,8 @@ static int handle_posted_message(JSRuntime *rt, JSContext *ctx,
22352240
/* remove the message from the queue */
22362241
list_del(&msg->link);
22372242

2238-
if (list_empty(&ps->msg_queue)) {
2239-
uint8_t buf[16];
2240-
int ret;
2241-
for(;;) {
2242-
ret = read(ps->read_fd, buf, sizeof(buf));
2243-
if (ret >= 0)
2244-
break;
2245-
if (errno != EAGAIN && errno != EINTR)
2246-
break;
2247-
}
2248-
}
2243+
if (list_empty(&ps->msg_queue))
2244+
js_waker_clear(&ps->waker);
22492245

22502246
pthread_mutex_unlock(&ps->mutex);
22512247

@@ -2288,7 +2284,104 @@ static int handle_posted_message(JSRuntime *rt, JSContext *ctx,
22882284
{
22892285
return 0;
22902286
}
2291-
#endif
2287+
#endif /* !USE_WORKER */
2288+
2289+
#if defined(_WIN32)
2290+
2291+
static int js_os_poll(JSContext *ctx)
2292+
{
2293+
JSRuntime *rt = JS_GetRuntime(ctx);
2294+
JSThreadState *ts = JS_GetRuntimeOpaque(rt);
2295+
int min_delay, count;
2296+
int64_t cur_time, delay;
2297+
JSOSRWHandler *rh;
2298+
struct list_head *el;
2299+
HANDLE handles[MAXIMUM_WAIT_OBJECTS]; // 64
2300+
2301+
/* XXX: handle signals if useful */
2302+
2303+
if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers) &&
2304+
list_empty(&ts->port_list)) {
2305+
return -1; /* no more events */
2306+
}
2307+
2308+
if (!list_empty(&ts->os_timers)) {
2309+
cur_time = get_time_ms();
2310+
min_delay = 10000;
2311+
list_for_each(el, &ts->os_timers) {
2312+
JSOSTimer *th = list_entry(el, JSOSTimer, link);
2313+
delay = th->timeout - cur_time;
2314+
if (delay <= 0) {
2315+
JSValue func;
2316+
/* the timer expired */
2317+
func = th->func;
2318+
th->func = JS_UNDEFINED;
2319+
free_timer(rt, th);
2320+
call_handler(ctx, func);
2321+
JS_FreeValue(ctx, func);
2322+
return 0;
2323+
} else if (delay < min_delay) {
2324+
min_delay = delay;
2325+
}
2326+
}
2327+
} else {
2328+
min_delay = -1;
2329+
}
2330+
2331+
count = 0;
2332+
list_for_each(el, &ts->os_rw_handlers) {
2333+
rh = list_entry(el, JSOSRWHandler, link);
2334+
if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) {
2335+
handles[count++] = (HANDLE)_get_osfhandle(rh->fd); // stdin
2336+
if (count == (int)countof(handles))
2337+
break;
2338+
}
2339+
}
2340+
2341+
list_for_each(el, &ts->port_list) {
2342+
JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
2343+
if (JS_IsNull(port->on_message_func))
2344+
continue;
2345+
handles[count++] = port->recv_pipe->waker.handle;
2346+
if (count == (int)countof(handles))
2347+
break;
2348+
}
2349+
2350+
if (count > 0) {
2351+
DWORD ret, timeout = INFINITE;
2352+
if (min_delay != -1)
2353+
timeout = min_delay;
2354+
ret = WaitForMultipleObjects(count, handles, FALSE, timeout);
2355+
2356+
if (ret < count) {
2357+
list_for_each(el, &ts->os_rw_handlers) {
2358+
rh = list_entry(el, JSOSRWHandler, link);
2359+
if (rh->fd == 0 && !JS_IsNull(rh->rw_func[0])) {
2360+
call_handler(ctx, rh->rw_func[0]);
2361+
/* must stop because the list may have been modified */
2362+
goto done;
2363+
}
2364+
}
2365+
2366+
list_for_each(el, &ts->port_list) {
2367+
JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
2368+
if (!JS_IsNull(port->on_message_func)) {
2369+
JSWorkerMessagePipe *ps = port->recv_pipe;
2370+
if (ps->waker.handle == handles[ret]) {
2371+
if (handle_posted_message(rt, ctx, port))
2372+
goto done;
2373+
}
2374+
}
2375+
}
2376+
}
2377+
} else {
2378+
Sleep(min_delay);
2379+
}
2380+
done:
2381+
return 0;
2382+
}
2383+
2384+
#else
22922385

22932386
static int js_os_poll(JSContext *ctx)
22942387
{
@@ -2364,8 +2457,8 @@ static int js_os_poll(JSContext *ctx)
23642457
JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
23652458
if (!JS_IsNull(port->on_message_func)) {
23662459
JSWorkerMessagePipe *ps = port->recv_pipe;
2367-
fd_max = max_int(fd_max, ps->read_fd);
2368-
FD_SET(ps->read_fd, &rfds);
2460+
fd_max = max_int(fd_max, ps->waker.read_fd);
2461+
FD_SET(ps->waker.read_fd, &rfds);
23692462
}
23702463
}
23712464

@@ -2391,14 +2484,14 @@ static int js_os_poll(JSContext *ctx)
23912484
JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
23922485
if (!JS_IsNull(port->on_message_func)) {
23932486
JSWorkerMessagePipe *ps = port->recv_pipe;
2394-
if (FD_ISSET(ps->read_fd, &rfds)) {
2487+
if (FD_ISSET(ps->waker.read_fd, &rfds)) {
23952488
if (handle_posted_message(rt, ctx, port))
23962489
goto done;
23972490
}
23982491
}
23992492
}
24002493
}
2401-
done:
2494+
done:
24022495
return 0;
24032496
}
24042497
#endif /* !_WIN32 */
@@ -3269,22 +3362,17 @@ static void js_sab_dup(void *opaque, void *ptr)
32693362
static JSWorkerMessagePipe *js_new_message_pipe(void)
32703363
{
32713364
JSWorkerMessagePipe *ps;
3272-
int pipe_fds[2];
3273-
3274-
if (pipe(pipe_fds) < 0)
3275-
return NULL;
32763365

32773366
ps = malloc(sizeof(*ps));
3278-
if (!ps) {
3279-
close(pipe_fds[0]);
3280-
close(pipe_fds[1]);
3367+
if (!ps)
3368+
return NULL;
3369+
if (js_waker_init(&ps->waker)) {
3370+
free(ps);
32813371
return NULL;
32823372
}
32833373
ps->ref_count = 1;
32843374
init_list_head(&ps->msg_queue);
32853375
pthread_mutex_init(&ps->mutex, NULL);
3286-
ps->read_fd = pipe_fds[0];
3287-
ps->write_fd = pipe_fds[1];
32883376
return ps;
32893377
}
32903378

@@ -3323,8 +3411,7 @@ static void js_free_message_pipe(JSWorkerMessagePipe *ps)
33233411
js_free_message(msg);
33243412
}
33253413
pthread_mutex_destroy(&ps->mutex);
3326-
close(ps->read_fd);
3327-
close(ps->write_fd);
3414+
js_waker_close(&ps->waker);
33283415
free(ps);
33293416
}
33303417
}
@@ -3572,17 +3659,8 @@ static JSValue js_worker_postMessage(JSContext *ctx, JSValueConst this_val,
35723659
ps = worker->send_pipe;
35733660
pthread_mutex_lock(&ps->mutex);
35743661
/* indicate that data is present */
3575-
if (list_empty(&ps->msg_queue)) {
3576-
uint8_t ch = '\0';
3577-
int ret;
3578-
for(;;) {
3579-
ret = write(ps->write_fd, &ch, 1);
3580-
if (ret == 1)
3581-
break;
3582-
if (ret < 0 && (errno != EAGAIN || errno != EINTR))
3583-
break;
3584-
}
3585-
}
3662+
if (list_empty(&ps->msg_queue))
3663+
js_waker_signal(&ps->waker);
35863664
list_add_tail(&msg->link, &ps->msg_queue);
35873665
pthread_mutex_unlock(&ps->mutex);
35883666
return JS_UNDEFINED;

0 commit comments

Comments
 (0)