mirror of
https://github.com/bellard/quickjs.git
synced 2025-05-12 19:14:39 +08:00
enabled os.Worker on Windows (bnoordhuis)
This commit is contained in:
parent
bff55250c4
commit
8bb41b20dd
296
quickjs-libc.c
296
quickjs-libc.c
@ -64,10 +64,8 @@ typedef sig_t sighandler_t;
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(_WIN32)
|
/* enable the os.Worker API. It relies on POSIX threads */
|
||||||
/* enable the os.Worker API. IT relies on POSIX threads */
|
|
||||||
#define USE_WORKER
|
#define USE_WORKER
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_WORKER
|
#ifdef USE_WORKER
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
@ -114,14 +112,22 @@ typedef struct {
|
|||||||
size_t sab_tab_len;
|
size_t sab_tab_len;
|
||||||
} JSWorkerMessage;
|
} JSWorkerMessage;
|
||||||
|
|
||||||
|
typedef struct JSWaker {
|
||||||
|
#ifdef _WIN32
|
||||||
|
HANDLE handle;
|
||||||
|
#else
|
||||||
|
int read_fd;
|
||||||
|
int write_fd;
|
||||||
|
#endif
|
||||||
|
} JSWaker;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int ref_count;
|
int ref_count;
|
||||||
#ifdef USE_WORKER
|
#ifdef USE_WORKER
|
||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
#endif
|
#endif
|
||||||
struct list_head msg_queue; /* list of JSWorkerMessage.link */
|
struct list_head msg_queue; /* list of JSWorkerMessage.link */
|
||||||
int read_fd;
|
JSWaker waker;
|
||||||
int write_fd;
|
|
||||||
} JSWorkerMessagePipe;
|
} JSWorkerMessagePipe;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -2138,82 +2144,81 @@ static void call_handler(JSContext *ctx, JSValueConst func)
|
|||||||
JS_FreeValue(ctx, ret);
|
JS_FreeValue(ctx, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
#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);
|
w->handle = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
JSThreadState *ts = JS_GetRuntimeOpaque(rt);
|
return w->handle ? 0 : -1;
|
||||||
int min_delay, console_fd;
|
}
|
||||||
int64_t cur_time, delay;
|
|
||||||
JSOSRWHandler *rh;
|
|
||||||
struct list_head *el;
|
|
||||||
|
|
||||||
/* XXX: handle signals if useful */
|
static void js_waker_signal(JSWaker *w)
|
||||||
|
{
|
||||||
|
SetEvent(w->handle);
|
||||||
|
}
|
||||||
|
|
||||||
if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers))
|
static void js_waker_clear(JSWaker *w)
|
||||||
return -1; /* no more events */
|
{
|
||||||
|
ResetEvent(w->handle);
|
||||||
|
}
|
||||||
|
|
||||||
/* XXX: only timers and basic console input are supported */
|
static void js_waker_close(JSWaker *w)
|
||||||
if (!list_empty(&ts->os_timers)) {
|
{
|
||||||
cur_time = get_time_ms();
|
CloseHandle(w->handle);
|
||||||
min_delay = 10000;
|
w->handle = INVALID_HANDLE_VALUE;
|
||||||
list_for_each(el, &ts->os_timers) {
|
}
|
||||||
JSOSTimer *th = list_entry(el, JSOSTimer, link);
|
|
||||||
delay = th->timeout - cur_time;
|
|
||||||
if (delay <= 0) {
|
|
||||||
JSValue func;
|
|
||||||
/* the timer expired */
|
|
||||||
func = th->func;
|
|
||||||
th->func = JS_UNDEFINED;
|
|
||||||
free_timer(rt, th);
|
|
||||||
call_handler(ctx, func);
|
|
||||||
JS_FreeValue(ctx, func);
|
|
||||||
return 0;
|
|
||||||
} else if (delay < min_delay) {
|
|
||||||
min_delay = delay;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
min_delay = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
console_fd = -1;
|
#else // !_WIN32
|
||||||
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;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (console_fd >= 0) {
|
static int js_waker_init(JSWaker *w)
|
||||||
DWORD ti, ret;
|
{
|
||||||
HANDLE handle;
|
int fds[2];
|
||||||
if (min_delay == -1)
|
|
||||||
ti = INFINITE;
|
if (pipe(fds) < 0)
|
||||||
else
|
return -1;
|
||||||
ti = min_delay;
|
w->read_fd = fds[0];
|
||||||
handle = (HANDLE)_get_osfhandle(console_fd);
|
w->write_fd = fds[1];
|
||||||
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])) {
|
|
||||||
call_handler(ctx, rh->rw_func[0]);
|
|
||||||
/* must stop because the list may have been modified */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Sleep(min_delay);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
|
|
||||||
#ifdef USE_WORKER
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
static void js_free_message(JSWorkerMessage *msg);
|
||||||
|
|
||||||
@ -2235,17 +2240,8 @@ static int handle_posted_message(JSRuntime *rt, JSContext *ctx,
|
|||||||
/* remove the message from the queue */
|
/* remove the message from the queue */
|
||||||
list_del(&msg->link);
|
list_del(&msg->link);
|
||||||
|
|
||||||
if (list_empty(&ps->msg_queue)) {
|
if (list_empty(&ps->msg_queue))
|
||||||
uint8_t buf[16];
|
js_waker_clear(&ps->waker);
|
||||||
int ret;
|
|
||||||
for(;;) {
|
|
||||||
ret = read(ps->read_fd, buf, sizeof(buf));
|
|
||||||
if (ret >= 0)
|
|
||||||
break;
|
|
||||||
if (errno != EAGAIN && errno != EINTR)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_unlock(&ps->mutex);
|
pthread_mutex_unlock(&ps->mutex);
|
||||||
|
|
||||||
@ -2288,7 +2284,104 @@ static int handle_posted_message(JSRuntime *rt, JSContext *ctx,
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif /* !USE_WORKER */
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
|
||||||
|
static int js_os_poll(JSContext *ctx)
|
||||||
|
{
|
||||||
|
JSRuntime *rt = JS_GetRuntime(ctx);
|
||||||
|
JSThreadState *ts = JS_GetRuntimeOpaque(rt);
|
||||||
|
int min_delay, count;
|
||||||
|
int64_t cur_time, delay;
|
||||||
|
JSOSRWHandler *rh;
|
||||||
|
struct list_head *el;
|
||||||
|
HANDLE handles[MAXIMUM_WAIT_OBJECTS]; // 64
|
||||||
|
|
||||||
|
/* XXX: handle signals if useful */
|
||||||
|
|
||||||
|
if (list_empty(&ts->os_rw_handlers) && list_empty(&ts->os_timers) &&
|
||||||
|
list_empty(&ts->port_list)) {
|
||||||
|
return -1; /* no more events */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!list_empty(&ts->os_timers)) {
|
||||||
|
cur_time = get_time_ms();
|
||||||
|
min_delay = 10000;
|
||||||
|
list_for_each(el, &ts->os_timers) {
|
||||||
|
JSOSTimer *th = list_entry(el, JSOSTimer, link);
|
||||||
|
delay = th->timeout - cur_time;
|
||||||
|
if (delay <= 0) {
|
||||||
|
JSValue func;
|
||||||
|
/* the timer expired */
|
||||||
|
func = th->func;
|
||||||
|
th->func = JS_UNDEFINED;
|
||||||
|
free_timer(rt, th);
|
||||||
|
call_handler(ctx, func);
|
||||||
|
JS_FreeValue(ctx, func);
|
||||||
|
return 0;
|
||||||
|
} else if (delay < min_delay) {
|
||||||
|
min_delay = delay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
min_delay = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
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])) {
|
||||||
|
call_handler(ctx, rh->rw_func[0]);
|
||||||
|
/* must stop because the list may have been modified */
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
static int js_os_poll(JSContext *ctx)
|
static int js_os_poll(JSContext *ctx)
|
||||||
{
|
{
|
||||||
@ -2364,8 +2457,8 @@ static int js_os_poll(JSContext *ctx)
|
|||||||
JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
|
JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
|
||||||
if (!JS_IsNull(port->on_message_func)) {
|
if (!JS_IsNull(port->on_message_func)) {
|
||||||
JSWorkerMessagePipe *ps = port->recv_pipe;
|
JSWorkerMessagePipe *ps = port->recv_pipe;
|
||||||
fd_max = max_int(fd_max, ps->read_fd);
|
fd_max = max_int(fd_max, ps->waker.read_fd);
|
||||||
FD_SET(ps->read_fd, &rfds);
|
FD_SET(ps->waker.read_fd, &rfds);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2391,14 +2484,14 @@ static int js_os_poll(JSContext *ctx)
|
|||||||
JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
|
JSWorkerMessageHandler *port = list_entry(el, JSWorkerMessageHandler, link);
|
||||||
if (!JS_IsNull(port->on_message_func)) {
|
if (!JS_IsNull(port->on_message_func)) {
|
||||||
JSWorkerMessagePipe *ps = port->recv_pipe;
|
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))
|
if (handle_posted_message(rt, ctx, port))
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* !_WIN32 */
|
#endif /* !_WIN32 */
|
||||||
@ -3269,22 +3362,17 @@ static void js_sab_dup(void *opaque, void *ptr)
|
|||||||
static JSWorkerMessagePipe *js_new_message_pipe(void)
|
static JSWorkerMessagePipe *js_new_message_pipe(void)
|
||||||
{
|
{
|
||||||
JSWorkerMessagePipe *ps;
|
JSWorkerMessagePipe *ps;
|
||||||
int pipe_fds[2];
|
|
||||||
|
|
||||||
if (pipe(pipe_fds) < 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
ps = malloc(sizeof(*ps));
|
ps = malloc(sizeof(*ps));
|
||||||
if (!ps) {
|
if (!ps)
|
||||||
close(pipe_fds[0]);
|
return NULL;
|
||||||
close(pipe_fds[1]);
|
if (js_waker_init(&ps->waker)) {
|
||||||
|
free(ps);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ps->ref_count = 1;
|
ps->ref_count = 1;
|
||||||
init_list_head(&ps->msg_queue);
|
init_list_head(&ps->msg_queue);
|
||||||
pthread_mutex_init(&ps->mutex, NULL);
|
pthread_mutex_init(&ps->mutex, NULL);
|
||||||
ps->read_fd = pipe_fds[0];
|
|
||||||
ps->write_fd = pipe_fds[1];
|
|
||||||
return ps;
|
return ps;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3323,8 +3411,7 @@ static void js_free_message_pipe(JSWorkerMessagePipe *ps)
|
|||||||
js_free_message(msg);
|
js_free_message(msg);
|
||||||
}
|
}
|
||||||
pthread_mutex_destroy(&ps->mutex);
|
pthread_mutex_destroy(&ps->mutex);
|
||||||
close(ps->read_fd);
|
js_waker_close(&ps->waker);
|
||||||
close(ps->write_fd);
|
|
||||||
free(ps);
|
free(ps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3572,17 +3659,8 @@ static JSValue js_worker_postMessage(JSContext *ctx, JSValueConst this_val,
|
|||||||
ps = worker->send_pipe;
|
ps = worker->send_pipe;
|
||||||
pthread_mutex_lock(&ps->mutex);
|
pthread_mutex_lock(&ps->mutex);
|
||||||
/* indicate that data is present */
|
/* indicate that data is present */
|
||||||
if (list_empty(&ps->msg_queue)) {
|
if (list_empty(&ps->msg_queue))
|
||||||
uint8_t ch = '\0';
|
js_waker_signal(&ps->waker);
|
||||||
int ret;
|
|
||||||
for(;;) {
|
|
||||||
ret = write(ps->write_fd, &ch, 1);
|
|
||||||
if (ret == 1)
|
|
||||||
break;
|
|
||||||
if (ret < 0 && (errno != EAGAIN || errno != EINTR))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
list_add_tail(&msg->link, &ps->msg_queue);
|
list_add_tail(&msg->link, &ps->msg_queue);
|
||||||
pthread_mutex_unlock(&ps->mutex);
|
pthread_mutex_unlock(&ps->mutex);
|
||||||
return JS_UNDEFINED;
|
return JS_UNDEFINED;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user