Skip to content

Commit b2f724c

Browse files
committed
Remove custom alarm impl in favor of lower level itimer syscalls
These alarms/signals will now fire if when waiting on a lock (i.e. they don't depend on the event loops running). Fixes: #12415
1 parent 0d7014e commit b2f724c

File tree

18 files changed

+268
-27
lines changed

18 files changed

+268
-27
lines changed

src/library.js

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2264,14 +2264,38 @@ mergeInto(LibraryManager.library, {
22642264
return 0;
22652265
},
22662266

2267-
// http://pubs.opengroup.org/onlinepubs/000095399/functions/alarm.html
2268-
alarm__deps: ['raise', '$callUserCallback'],
2269-
alarm: function(seconds) {
2270-
setTimeout(function() {
2271-
callUserCallback(function() {
2272-
_raise({{{ cDefine('SIGALRM') }}});
2273-
});
2274-
}, seconds*1000);
2267+
$timers: {},
2268+
2269+
// Helper function for setitimer that registers timers with the eventloop.
2270+
// Timers always fire on the main thread, either directly from JS (here) or
2271+
// or when the main thread is busy waiting calling _emscripten_yield.
2272+
_setitimer_js__sig: 'iid',
2273+
_setitimer_js__proxy: 'sync',
2274+
_setitimer_js__deps: ['$timers', '$callUserCallback',
2275+
'_emscripten_timeout', 'emscripten_get_now'],
2276+
_setitimer_js: function(which, timeout_ms) {
2277+
#if RUNTIME_DEBUG
2278+
dbg('setitimer_js ' + which + ' timeout=' + timeout_ms);
2279+
#endif
2280+
if (timers[which]) {
2281+
clearTimeout(timers[which].id);
2282+
delete timers[which];
2283+
}
2284+
2285+
if (timeout_ms) {
2286+
var id = setTimeout(() => {
2287+
#if ASSERTIONS
2288+
assert(which in timers);
2289+
#endif
2290+
delete timers[which];
2291+
#if RUNTIME_DEBUG
2292+
dbg('itimer fired: ' + which);
2293+
#endif
2294+
callUserCallback(() => __emscripten_timeout(which, _emscripten_get_now()));
2295+
}, timeout_ms);
2296+
timers[which] = { id: id, timeout_ms: timeout_ms };
2297+
}
2298+
return 0;
22752299
},
22762300

22772301
// Helper for raise() to avoid signature mismatch failures:

src/shell.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,10 @@ if (ENVIRONMENT_IS_SHELL) {
318318
setTimeout(() => onload(readBinary(f)), 0);
319319
};
320320

321+
if (typeof clearTimeout == 'undefined') {
322+
globalThis.clearTimeout = (id) => {};
323+
}
324+
321325
if (typeof scriptArgs != 'undefined') {
322326
arguments_ = scriptArgs;
323327
} else if (typeof arguments != 'undefined') {

system/include/emscripten/threading.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,8 +289,6 @@ void emscripten_check_blocking_allowed(void);
289289
// Experimental API for syncing loaded code between pthreads.
290290
void _emscripten_thread_sync_code();
291291

292-
void _emscripten_yield();
293-
294292
#ifdef __cplusplus
295293
}
296294
#endif

system/lib/libc/emscripten_syscall_stubs.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,6 @@ UNIMPLEMENTED(pipe2, (intptr_t fds, int flags))
254254
UNIMPLEMENTED(pselect6, (int nfds, intptr_t readfds, intptr_t writefds, intptr_t exceptfds, intptr_t timeout, intptr_t sigmaks))
255255
UNIMPLEMENTED(recvmmsg, (int sockfd, intptr_t msgvec, size_t vlen, int flags, ...))
256256
UNIMPLEMENTED(sendmmsg, (int sockfd, intptr_t msgvec, size_t vlen, int flags, ...))
257-
UNIMPLEMENTED(setitimer, (int which, intptr_t new_value, intptr_t old_value))
258-
UNIMPLEMENTED(getitimer, (int which, intptr_t old_value))
259257
UNIMPLEMENTED(shutdown, (int sockfd, int how, int dummy, int dummy2, int dummy3, int dummy4))
260258
UNIMPLEMENTED(socketpair, (int domain, int type, int protocol, intptr_t fds, int dummy, int dummy2))
261259
UNIMPLEMENTED(wait4,(int pid, intptr_t wstatus, int options, int rusage))

system/lib/libc/musl/arch/emscripten/bits/syscall.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@
2020
#define SYS_fchmod __syscall_fchmod
2121
#define SYS_getpriority __syscall_getpriority
2222
#define SYS_setpriority __syscall_setpriority
23-
#define SYS_setitimer __syscall_setitimer
24-
#define SYS_getitimer __syscall_getitimer
2523
#define SYS_wait4 __syscall_wait4
2624
#define SYS_setdomainname __syscall_setdomainname
2725
#define SYS_uname __syscall_uname

system/lib/libc/musl/arch/emscripten/syscall_arch.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ int __syscall_fchmod(int fd, int mode);
3838
int __syscall_getpriority(int which, int who);
3939
int __syscall_setpriority(int which, int who, int prio);
4040
int __syscall_socketcall(int call, intptr_t args);
41-
int __syscall_setitimer(int which, intptr_t new_value, intptr_t old_value);
42-
int __syscall_getitimer(int which, intptr_t old_value);
4341
int __syscall_wait4(int pid, intptr_t wstatus, int options, int rusage);
4442
int __syscall_setdomainname(intptr_t name, size_t size);
4543
int __syscall_uname(intptr_t buf);

system/lib/libc/musl/src/sched/sched_yield.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
#include "syscall.h"
33

44
#if __EMSCRIPTEN__
5+
#include <emscripten/emscripten.h>
56
#include <emscripten/threading.h>
7+
#include "threading_internal.h"
68
#endif
79

810
int sched_yield()
@@ -11,7 +13,7 @@ int sched_yield()
1113
// SharedArrayBuffer and wasm threads do not support explicit yielding.
1214
// For now we at least call `emscripten_yield` which processes the event queue
1315
// (along with other essential tasks).
14-
_emscripten_yield();
16+
_emscripten_yield(emscripten_get_now());
1517
return 0;
1618
#else
1719
return syscall(SYS_sched_yield);

system/lib/libc/musl/src/signal/getitimer.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
11
#include <sys/time.h>
22
#include "syscall.h"
33

4+
#ifdef __EMSCRIPTEN__
5+
#include <emscripten/emscripten.h>
6+
void __getitimer(int which, struct itimerval *old, double now);
7+
#endif
8+
49
int getitimer(int which, struct itimerval *old)
510
{
11+
#ifdef __EMSCRIPTEN__
12+
if (which > ITIMER_PROF) return EINVAL;
13+
__getitimer(which, old, emscripten_get_now());
14+
return 0;
15+
#else
616
if (sizeof(time_t) > sizeof(long)) {
717
long old32[4];
818
int r = __syscall(SYS_getitimer, which, old32);
@@ -15,4 +25,5 @@ int getitimer(int which, struct itimerval *old)
1525
return __syscall_ret(r);
1626
}
1727
return syscall(SYS_getitimer, which, old);
28+
#endif
1829
}

system/lib/libc/musl/src/signal/setitimer.c

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,72 @@
44

55
#define IS32BIT(x) !((x)+0x80000000ULL>>32)
66

7+
#ifdef __EMSCRIPTEN__
8+
#include <signal.h>
9+
#include <stdio.h>
10+
#include <emscripten/emscripten.h>
11+
static double _emscripten_timers[3];
12+
static double _emscripten_intervals[3];
13+
14+
#define MAX(a,b) ((a)>(b)?(a):(b))
15+
16+
int _setitimer_js(int which, double timeout);
17+
18+
void __getitimer(int which, struct itimerval *old, double now)
19+
{
20+
double remaining_ms = MAX(_emscripten_timers[which] - now, 0);
21+
old->it_value.tv_sec = remaining_ms / 1000;
22+
old->it_value.tv_usec = remaining_ms * 1000;
23+
old->it_interval.tv_sec = _emscripten_intervals[which] / 1000;
24+
old->it_interval.tv_usec = _emscripten_intervals[which] * 1000;
25+
}
26+
27+
void _emscripten_timeout(int which, double now)
28+
{
29+
int signum = SIGALRM;
30+
if (which == ITIMER_PROF) {
31+
signum = SIGPROF;
32+
} else if (which == ITIMER_VIRTUAL) {
33+
signum = SIGVTALRM;
34+
}
35+
int next_timeout = _emscripten_intervals[which];
36+
if (next_timeout) {
37+
_emscripten_timers[which] = now + next_timeout;
38+
} else {
39+
_emscripten_timers[which] = 0;
40+
}
41+
_setitimer_js(which, next_timeout);
42+
raise(signum);
43+
}
44+
45+
void _emscripten_check_timers(double now)
46+
{
47+
if (!now) now = emscripten_get_now();
48+
for (int which = 0; which < 3; which++) {
49+
if (_emscripten_timers[which] && now >= _emscripten_timers[which]) {
50+
_emscripten_timeout(which, now);
51+
}
52+
}
53+
}
54+
#endif
55+
756
int setitimer(int which, const struct itimerval *restrict new, struct itimerval *restrict old)
857
{
58+
#ifdef __EMSCRIPTEN__
59+
if (which > ITIMER_PROF) return EINVAL;
60+
double now = emscripten_get_now();
61+
if (old) {
62+
__getitimer(which, old, now);
63+
}
64+
if (new->it_value.tv_sec || new->it_value.tv_usec) {
65+
_emscripten_timers[which] = now + new->it_value.tv_sec * 1000 + new->it_value.tv_usec / 1000;
66+
_emscripten_intervals[which] = new->it_interval.tv_sec * 1000 + new->it_interval.tv_usec / 1000;
67+
} else {
68+
_emscripten_timers[which] = 0;
69+
_emscripten_intervals[which] = 0;
70+
}
71+
return _setitimer_js(which, new->it_value.tv_sec * 1000 + new->it_value.tv_usec / 1000);
72+
#else
973
if (sizeof(time_t) > sizeof(long)) {
1074
time_t is = new->it_interval.tv_sec, vs = new->it_value.tv_sec;
1175
long ius = new->it_interval.tv_usec, vus = new->it_value.tv_usec;
@@ -23,4 +87,5 @@ int setitimer(int which, const struct itimerval *restrict new, struct itimerval
2387
return __syscall_ret(r);
2488
}
2589
return syscall(SYS_setitimer, which, new, old);
90+
#endif
2691
}

system/lib/pthread/emscripten_futex_wait.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ static int futex_wait_main_browser_thread(volatile void* addr,
6464
// We were told to stop waiting, so stop.
6565
break;
6666
}
67-
_emscripten_yield();
67+
_emscripten_yield(now);
6868

6969
// Check the value, as if we were starting the futex all over again.
7070
// This handles the following case:
@@ -116,7 +116,7 @@ int emscripten_futex_wait(volatile void *addr, uint32_t val, double max_wait_ms)
116116
return -EINVAL;
117117
}
118118

119-
_emscripten_yield();
119+
_emscripten_yield(0);
120120

121121
int ret;
122122
emscripten_conditional_set_current_thread_status(EM_THREAD_STATUS_RUNNING, EM_THREAD_STATUS_WAITFUTEX);

0 commit comments

Comments
 (0)