Skip to content

Commit 5dca24c

Browse files
committed
select: enable to handle timeout
This commit enables the select syscall to handle timeout with multiple event sources when PROXY_TO_PTHREAD is enabled. When a thread worker calls __syscall_newselect, it blocks using emscripten_proxy_sync_with_ctx. When __syscall_newselect is called with zero timeout, it is unblocked immediately by calling emscripten_proxy_finish before returning. When it is called with non-zero timeout, emscripten_proxy_finish is invoked either by the underlying stream implementation (where an event occurs) or by a setTimeout callback when the tiemout expires. In proxying.c, several wrapper functions for proxying-related APIs are added to allow the JS implementation of newselect to use them. Signed-off-by: Kohei Tokunaga <ktokunaga.mail@gmail.com>
1 parent 96dd87d commit 5dca24c

File tree

3 files changed

+91
-3
lines changed

3 files changed

+91
-3
lines changed

src/lib/libsyscall.js

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -607,12 +607,30 @@ var SyscallsLibrary = {
607607
FS.chdir(stream.path);
608608
return 0;
609609
},
610+
#if PROXY_TO_PTHREAD
611+
__syscall__newselect__proxy: 'none',
612+
__syscall__newselect__deps: ['_emscripten_proxy_newselect'],
610613
__syscall__newselect: (nfds, readfds, writefds, exceptfds, timeout) => {
614+
return __emscripten_proxy_newselect(nfds, readfds, writefds, exceptfds, timeout);
615+
},
616+
#else
617+
__syscall__newselect__deps: ['__syscall__newselect_inner'],
618+
__syscall__newselect: (nfds, readfds, writefds, exceptfds, timeout) => {
619+
return ___syscall__newselect_inner(null, null, nfds, readfds, writefds, exceptfds, timeout);
620+
},
621+
#endif
622+
#if PROXY_TO_PTHREAD
623+
__syscall__newselect_inner__deps: ['_emscripten_proxy_newselect_finish'],
624+
#endif
625+
__syscall__newselect_inner__proxy: 'none',
626+
__syscall__newselect_inner__sig: 'ippipppp',
627+
__syscall__newselect_inner: (ctx, arg, nfds, readfds, writefds, exceptfds, timeout) => {
611628
// readfds are supported,
612629
// writefds checks socket open status
613630
// exceptfds are supported, although on web, such exceptional conditions never arise in web sockets
614631
// and so the exceptfds list will always return empty.
615-
// timeout is supported, although on SOCKFS and PIPEFS these are ignored and always treated as 0 - fully async
632+
// timeout is supported, although on SOCKFS these are ignored and always treated as 0 - fully async
633+
// and PIPEFS supports timeout only when PROXY_TO_PTHREAD is enabled.
616634
#if ASSERTIONS
617635
assert(nfds <= 64, 'nfds must be less than or equal to 64'); // fd sets have 64 bits // TODO: this could be 1024 based on current musl headers
618636
#endif
@@ -633,6 +651,32 @@ var SyscallsLibrary = {
633651
timeoutInMillis = SYSCALLS.getTimeoutInMillis(timeout);
634652
}
635653

654+
#if PROXY_TO_PTHREAD
655+
var cleanupFuncs = [];
656+
var notifyDone = false;
657+
var makeNotifyCallback = (fd) => {
658+
var cb = (flags) => {
659+
if (notifyDone) {
660+
return;
661+
}
662+
if (fd >= 0) {
663+
fdSet.setFlags(fd, flags);
664+
}
665+
notifyDone = true;
666+
cleanupFuncs.forEach(cb => cb());
667+
fdSet.commit();
668+
__emscripten_proxy_newselect_finish({{{ to64('ctx') }}}, {{{ to64('arg') }}}, fdSet.getTotal());
669+
}
670+
cb.registerCleanupFunc = (f) => {
671+
if (f != null) cleanupFuncs.push(f);
672+
}
673+
return cb;
674+
}
675+
if (timeoutInMillis > 0) {
676+
setTimeout(() => makeNotifyCallback(-1)(0), timeoutInMillis);
677+
}
678+
#endif
679+
636680
for (var fd = 0; fd < nfds; fd++) {
637681
var mask = 1 << (fd % 32);
638682
if (!(check(fd, allLow, allHigh, mask))) {
@@ -644,14 +688,23 @@ var SyscallsLibrary = {
644688
var flags = SYSCALLS.DEFAULT_POLLMASK;
645689

646690
if (stream.stream_ops.poll) {
691+
#if PROXY_TO_PTHREAD
692+
flags = stream.stream_ops.poll(stream, timeoutInMillis, timeoutInMillis != 0 ? makeNotifyCallback(fd) : null);
693+
#else
647694
flags = stream.stream_ops.poll(stream, ((timeoutInMillis < 0) || readfds) ? timeoutInMillis : 0);
695+
#endif
648696
}
649697

650698
fdSet.setFlags(fd, flags);
651699
}
652700

653-
654-
fdSet.commit(fd, flags);
701+
#if PROXY_TO_PTHREAD
702+
if ((fdSet.getTotal() > 0) || (timeoutInMillis == 0) ) {
703+
makeNotifyCallback(-1)(0);
704+
}
705+
#else
706+
fdSet.commit();
707+
#endif
655708

656709
return fdSet.getTotal();
657710
},

system/lib/pthread/proxying.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,3 +658,36 @@ double _emscripten_run_js_on_main_thread(int func_index,
658658
}
659659
return 0;
660660
}
661+
662+
typedef struct proxied_select_t {
663+
int n;
664+
void *rfds;
665+
void *wfds;
666+
void *efds;
667+
void *tv;
668+
int result;
669+
} proxied_select_t;
670+
671+
int __syscall__newselect_inner(em_proxying_ctx* ctx, void* arg, int n, void *rfds, void *wfds, void *efds, void *tv);
672+
673+
static void call_newselect(em_proxying_ctx* ctx, void* arg) {
674+
proxied_select_t* t = arg;
675+
__syscall__newselect_inner(ctx, arg, t->n, t->rfds, t->wfds, t->efds, t->tv);
676+
}
677+
678+
void _emscripten_proxy_newselect_finish(em_proxying_ctx* ctx, void* arg, int ret) {
679+
proxied_select_t* t = arg;
680+
t->result = ret;
681+
emscripten_proxy_finish(ctx);
682+
}
683+
684+
int _emscripten_proxy_newselect(int n, void *rfds, void *wfds, void *efds, void *tv) {
685+
em_proxying_queue* q = emscripten_proxy_get_system_queue();
686+
pthread_t target = emscripten_main_runtime_thread_id();
687+
proxied_select_t t = {.n = n, .rfds = rfds, .wfds = wfds, .efds = efds, .tv = tv};
688+
if (!emscripten_proxy_sync_with_ctx(q, target, call_newselect, &t)) {
689+
assert(false && "emscripten_proxy_sync failed");
690+
return -1;
691+
}
692+
return t.result;
693+
}

tools/emscripten.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,8 @@ def create_pointer_conversion_wrappers(metadata):
11061106
'_emscripten_dlsync_self_async': '_p',
11071107
'_emscripten_proxy_dlsync_async': '_pp',
11081108
'_emscripten_wasm_worker_initialize': '_p_',
1109+
'_emscripten_proxy_newselect': '__pppp',
1110+
'_emscripten_proxy_newselect_finish': '_pp_',
11091111
'_wasmfs_rename': '_pp',
11101112
'_wasmfs_readlink': '_pp',
11111113
'_wasmfs_truncate': '_p_',

0 commit comments

Comments
 (0)