Skip to content

Commit 71a0e98

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 71a0e98

File tree

5 files changed

+93
-3
lines changed

5 files changed

+93
-3
lines changed

src/lib/libsigs.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@ sigs = {
381381
_mmap_js__sig: 'ipiiijpp',
382382
_msync_js__sig: 'ippiiij',
383383
_munmap_js__sig: 'ippiiij',
384+
_newselect_js__sig: 'ippipppp',
384385
_setitimer_js__sig: 'iid',
385386
_timegm_js__sig: 'jp',
386387
_tzset_js__sig: 'vpppp',

src/lib/libsyscall.js

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -607,12 +607,29 @@ 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: ['_newselect_js'],
618+
__syscall__newselect: (nfds, readfds, writefds, exceptfds, timeout) => {
619+
return __newselect_js(null, null, nfds, readfds, writefds, exceptfds, timeout);
620+
},
621+
#endif
622+
#if PROXY_TO_PTHREAD
623+
_newselect_js__deps: ['_emscripten_proxy_newselect_finish'],
624+
#endif
625+
_newselect_js__proxy: 'none',
626+
_newselect_js: (ctx, arg, nfds, readfds, writefds, exceptfds, timeout) => {
611627
// readfds are supported,
612628
// writefds checks socket open status
613629
// exceptfds are supported, although on web, such exceptional conditions never arise in web sockets
614630
// 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
631+
// timeout is supported, although on SOCKFS these are ignored and always treated as 0 - fully async
632+
// and PIPEFS supports timeout only when PROXY_TO_PTHREAD is enabled.
616633
#if ASSERTIONS
617634
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
618635
#endif
@@ -633,6 +650,32 @@ var SyscallsLibrary = {
633650
timeoutInMillis = SYSCALLS.getTimeoutInMillis(timeout);
634651
}
635652

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

646689
if (stream.stream_ops.poll) {
690+
#if PROXY_TO_PTHREAD
691+
flags = stream.stream_ops.poll(stream, timeoutInMillis, timeoutInMillis != 0 ? makeNotifyCallback(fd) : null);
692+
#else
647693
flags = stream.stream_ops.poll(stream, ((timeoutInMillis < 0) || readfds) ? timeoutInMillis : 0);
694+
#endif
648695
}
649696

650697
fdSet.setFlags(fd, flags);
651698
}
652699

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

656708
return fdSet.getTotal();
657709
},

system/lib/libc/emscripten_internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ EmscriptenDeviceOrientationEvent* _emscripten_get_last_deviceorientation_event()
151151
EmscriptenDeviceMotionEvent* _emscripten_get_last_devicemotion_event();
152152
EmscriptenMouseEvent* _emscripten_get_last_mouse_event();
153153

154+
int _newselect_js(void* ctx, void* arg, int n, void *rfds, void *wfds, void *efds, void *tv);
155+
154156
#ifdef __cplusplus
155157
}
156158
#endif

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 _newselect_js(void* 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+
_newselect_js(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)