Skip to content

Commit 5bf3545

Browse files
committed
Use an integer as the timer handle
Port of bellard/quickjs@9e561d5 but adapted.
1 parent 54afb19 commit 5bf3545

File tree

1 file changed

+41
-67
lines changed

1 file changed

+41
-67
lines changed

quickjs-libc.c

Lines changed: 41 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ extern char **environ;
9494
#include "list.h"
9595
#include "quickjs-libc.h"
9696

97+
#define MAX_SAFE_INTEGER (((int64_t) 1 << 53) - 1)
98+
9799
/* TODO:
98100
- add socket calls
99101
*/
@@ -112,7 +114,7 @@ typedef struct {
112114

113115
typedef struct {
114116
struct list_head link;
115-
uint8_t has_object:1;
117+
int64_t timer_id;
116118
uint8_t repeats:1;
117119
int64_t timeout;
118120
int64_t delay;
@@ -150,6 +152,7 @@ typedef struct JSThreadState {
150152
struct list_head os_timers; /* list of JSOSTimer.link */
151153
struct list_head port_list; /* list of JSWorkerMessageHandler.link */
152154
int eval_script_recurse; /* only used in the main thread */
155+
int64_t next_timer_id; /* for setTimeout / setInterval */
153156
/* not used in the main thread */
154157
JSWorkerMessagePipe *recv_pipe, *send_pipe;
155158
} JSThreadState;
@@ -2029,41 +2032,13 @@ static uint64_t js__hrtime_ms(void)
20292032
return js__hrtime_ns() / (1000 * 1000);
20302033
}
20312034

2032-
static void unlink_timer(JSRuntime *rt, JSOSTimer *th)
2033-
{
2034-
if (th->link.prev) {
2035-
list_del(&th->link);
2036-
th->link.prev = th->link.next = NULL;
2037-
}
2038-
}
2039-
20402035
static void free_timer(JSRuntime *rt, JSOSTimer *th)
20412036
{
2037+
list_del(&th->link);
20422038
JS_FreeValueRT(rt, th->func);
20432039
js_free_rt(rt, th);
20442040
}
20452041

2046-
static JSClassID js_os_timer_class_id;
2047-
2048-
static void js_os_timer_finalizer(JSRuntime *rt, JSValue val)
2049-
{
2050-
JSOSTimer *th = JS_GetOpaque(val, js_os_timer_class_id);
2051-
if (th) {
2052-
th->has_object = FALSE;
2053-
if (!th->link.prev)
2054-
free_timer(rt, th);
2055-
}
2056-
}
2057-
2058-
static void js_os_timer_mark(JSRuntime *rt, JSValue val,
2059-
JS_MarkFunc *mark_func)
2060-
{
2061-
JSOSTimer *th = JS_GetOpaque(val, js_os_timer_class_id);
2062-
if (th) {
2063-
JS_MarkValue(rt, th->func, mark_func);
2064-
}
2065-
}
2066-
20672042
// TODO(bnoordhuis) accept string as first arg and eval at timer expiry
20682043
// TODO(bnoordhuis) retain argv[2..] as args for callback if argc > 2
20692044
static JSValue js_os_setTimeout(JSContext *ctx, JSValue this_val,
@@ -2074,7 +2049,6 @@ static JSValue js_os_setTimeout(JSContext *ctx, JSValue this_val,
20742049
int64_t delay;
20752050
JSValue func;
20762051
JSOSTimer *th;
2077-
JSValue obj;
20782052

20792053
func = argv[0];
20802054
if (!JS_IsFunction(ctx, func))
@@ -2083,42 +2057,50 @@ static JSValue js_os_setTimeout(JSContext *ctx, JSValue this_val,
20832057
return JS_EXCEPTION;
20842058
if (delay < 1)
20852059
delay = 1;
2086-
obj = JS_NewObjectClass(ctx, js_os_timer_class_id);
2087-
if (JS_IsException(obj))
2088-
return obj;
20892060
th = js_mallocz(ctx, sizeof(*th));
2090-
if (!th) {
2091-
JS_FreeValue(ctx, obj);
2061+
if (!th)
20922062
return JS_EXCEPTION;
2093-
}
2094-
th->has_object = TRUE;
2063+
th->timer_id = ts->next_timer_id++;
2064+
if (ts->next_timer_id > MAX_SAFE_INTEGER)
2065+
ts->next_timer_id = 1;
20952066
th->repeats = (magic > 0);
20962067
th->timeout = js__hrtime_ms() + delay;
20972068
th->delay = delay;
20982069
th->func = JS_DupValue(ctx, func);
20992070
list_add_tail(&th->link, &ts->os_timers);
2100-
JS_SetOpaque(obj, th);
2101-
return obj;
2071+
return JS_NewInt64(ctx, th->timer_id);
2072+
}
2073+
2074+
static JSOSTimer *find_timer_by_id(JSThreadState *ts, int timer_id)
2075+
{
2076+
struct list_head *el;
2077+
if (timer_id <= 0)
2078+
return NULL;
2079+
list_for_each(el, &ts->os_timers) {
2080+
JSOSTimer *th = list_entry(el, JSOSTimer, link);
2081+
if (th->timer_id == timer_id)
2082+
return th;
2083+
}
2084+
return NULL;
21022085
}
21032086

21042087
static JSValue js_os_clearTimeout(JSContext *ctx, JSValue this_val,
21052088
int argc, JSValue *argv)
21062089
{
2107-
JSOSTimer *th = JS_GetOpaque2(ctx, argv[0], js_os_timer_class_id);
2108-
if (!th)
2090+
JSRuntime *rt = JS_GetRuntime(ctx);
2091+
JSThreadState *ts = JS_GetRuntimeOpaque(rt);
2092+
JSOSTimer *th;
2093+
int64_t timer_id;
2094+
2095+
if (JS_ToInt64(ctx, &timer_id, argv[0]))
21092096
return JS_EXCEPTION;
2110-
unlink_timer(JS_GetRuntime(ctx), th);
2111-
JS_FreeValue(ctx, th->func);
2112-
th->func = JS_UNDEFINED;
2097+
th = find_timer_by_id(ts, timer_id);
2098+
if (!th)
2099+
return JS_UNDEFINED;
2100+
free_timer(rt, th);
21132101
return JS_UNDEFINED;
21142102
}
21152103

2116-
static JSClassDef js_os_timer_class = {
2117-
"OSTimer",
2118-
.finalizer = js_os_timer_finalizer,
2119-
.gc_mark = js_os_timer_mark,
2120-
};
2121-
21222104
/* return a promise */
21232105
static JSValue js_os_sleepAsync(JSContext *ctx, JSValueConst this_val,
21242106
int argc, JSValueConst *argv)
@@ -2142,7 +2124,7 @@ static JSValue js_os_sleepAsync(JSContext *ctx, JSValueConst this_val,
21422124
JS_FreeValue(ctx, resolving_funcs[1]);
21432125
return JS_EXCEPTION;
21442126
}
2145-
th->has_object = FALSE;
2127+
th->timer_id = -1;
21462128
th->timeout = js__hrtime_ms() + delay;
21472129
th->func = JS_DupValue(ctx, resolving_funcs[0]);
21482130
list_add_tail(&th->link, &ts->os_timers);
@@ -2185,13 +2167,10 @@ static int js_os_run_timers(JSRuntime *rt, JSContext *ctx, JSThreadState *ts)
21852167
min_delay = min_int(min_delay, delay);
21862168
} else {
21872169
func = JS_DupValueRT(rt, th->func);
2188-
unlink_timer(rt, th);
2189-
if (th->repeats) {
2170+
if (th->repeats)
21902171
th->timeout = cur_time + th->delay;
2191-
list_add_tail(&th->link, &ts->os_timers);
2192-
} else if (!th->has_object) {
2172+
else
21932173
free_timer(rt, th);
2194-
}
21952174
call_handler(ctx, func);
21962175
JS_FreeValueRT(rt, func);
21972176
return 0;
@@ -3785,15 +3764,11 @@ static const JSCFunctionListEntry js_os_funcs[] = {
37853764

37863765
static int js_os_init(JSContext *ctx, JSModuleDef *m)
37873766
{
3788-
JSRuntime *rt = JS_GetRuntime(ctx);
37893767
os_poll_func = js_os_poll;
37903768

3791-
/* OSTimer class */
3792-
JS_NewClassID(rt, &js_os_timer_class_id);
3793-
JS_NewClass(rt, js_os_timer_class_id, &js_os_timer_class);
3794-
37953769
#ifdef USE_WORKER
37963770
{
3771+
JSRuntime *rt = JS_GetRuntime(ctx);
37973772
JSThreadState *ts = JS_GetRuntimeOpaque(rt);
37983773
JSValue proto, obj;
37993774
/* Worker class */
@@ -3819,8 +3794,7 @@ static int js_os_init(JSContext *ctx, JSModuleDef *m)
38193794
}
38203795
#endif /* USE_WORKER */
38213796

3822-
return JS_SetModuleExportList(ctx, m, js_os_funcs,
3823-
countof(js_os_funcs));
3797+
return JS_SetModuleExportList(ctx, m, js_os_funcs, countof(js_os_funcs));
38243798
}
38253799

38263800
JSModuleDef *js_init_module_os(JSContext *ctx, const char *module_name)
@@ -3904,6 +3878,8 @@ void js_std_init_handlers(JSRuntime *rt)
39043878
init_list_head(&ts->os_timers);
39053879
init_list_head(&ts->port_list);
39063880

3881+
ts->next_timer_id = 1;
3882+
39073883
JS_SetRuntimeOpaque(rt, ts);
39083884

39093885
#ifdef USE_WORKER
@@ -3936,9 +3912,7 @@ void js_std_free_handlers(JSRuntime *rt)
39363912

39373913
list_for_each_safe(el, el1, &ts->os_timers) {
39383914
JSOSTimer *th = list_entry(el, JSOSTimer, link);
3939-
unlink_timer(rt, th);
3940-
if (!th->has_object)
3941-
free_timer(rt, th);
3915+
free_timer(rt, th);
39423916
}
39433917

39443918
#ifdef USE_WORKER

0 commit comments

Comments
 (0)