summaryrefslogtreecommitdiff
path: root/quickjs-libc.c
diff options
context:
space:
mode:
authorFabrice Bellard <fabrice@bellard.org>2024-01-19 10:20:34 +0100
committerFabrice Bellard <fabrice@bellard.org>2024-01-19 10:20:34 +0100
commit9e561d5c2e986e535484c26385d6e1b8d08a238f (patch)
treef357da1c62c1d0f058fca55d93b13f03dc42512a /quickjs-libc.c
parent84058766e9f247cac7b00543feeb10f3bba8120a (diff)
downloadquickjs-9e561d5c2e986e535484c26385d6e1b8d08a238f.tar.gz
quickjs-9e561d5c2e986e535484c26385d6e1b8d08a238f.zip
fixed and simplified setTimeout() by using an integer timer handle (github issue #218)
Diffstat (limited to 'quickjs-libc.c')
-rw-r--r--quickjs-libc.c103
1 files changed, 39 insertions, 64 deletions
diff --git a/quickjs-libc.c b/quickjs-libc.c
index aa9e861..67fe2f6 100644
--- a/quickjs-libc.c
+++ b/quickjs-libc.c
@@ -89,7 +89,7 @@ typedef struct {
typedef struct {
struct list_head link;
- BOOL has_object;
+ int timer_id;
int64_t timeout;
JSValue func;
} JSOSTimer;
@@ -125,6 +125,7 @@ typedef struct JSThreadState {
struct list_head os_timers; /* list of JSOSTimer.link */
struct list_head port_list; /* list of JSWorkerMessageHandler.link */
int eval_script_recurse; /* only used in the main thread */
+ int next_timer_id; /* for setTimeout() */
/* not used in the main thread */
JSWorkerMessagePipe *recv_pipe, *send_pipe;
} JSThreadState;
@@ -2006,41 +2007,13 @@ static JSValue js_os_now(JSContext *ctx, JSValue this_val,
return JS_NewFloat64(ctx, (double)get_time_ns() / 1e6);
}
-static void unlink_timer(JSRuntime *rt, JSOSTimer *th)
-{
- if (th->link.prev) {
- list_del(&th->link);
- th->link.prev = th->link.next = NULL;
- }
-}
-
static void free_timer(JSRuntime *rt, JSOSTimer *th)
{
+ list_del(&th->link);
JS_FreeValueRT(rt, th->func);
js_free_rt(rt, th);
}
-static JSClassID js_os_timer_class_id;
-
-static void js_os_timer_finalizer(JSRuntime *rt, JSValue val)
-{
- JSOSTimer *th = JS_GetOpaque(val, js_os_timer_class_id);
- if (th) {
- th->has_object = FALSE;
- if (!th->link.prev)
- free_timer(rt, th);
- }
-}
-
-static void js_os_timer_mark(JSRuntime *rt, JSValueConst val,
- JS_MarkFunc *mark_func)
-{
- JSOSTimer *th = JS_GetOpaque(val, js_os_timer_class_id);
- if (th) {
- JS_MarkValue(rt, th->func, mark_func);
- }
-}
-
static JSValue js_os_setTimeout(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
@@ -2049,45 +2022,56 @@ static JSValue js_os_setTimeout(JSContext *ctx, JSValueConst this_val,
int64_t delay;
JSValueConst func;
JSOSTimer *th;
- JSValue obj;
func = argv[0];
if (!JS_IsFunction(ctx, func))
return JS_ThrowTypeError(ctx, "not a function");
if (JS_ToInt64(ctx, &delay, argv[1]))
return JS_EXCEPTION;
- obj = JS_NewObjectClass(ctx, js_os_timer_class_id);
- if (JS_IsException(obj))
- return obj;
th = js_mallocz(ctx, sizeof(*th));
- if (!th) {
- JS_FreeValue(ctx, obj);
+ if (!th)
return JS_EXCEPTION;
- }
- th->has_object = TRUE;
+ th->timer_id = ts->next_timer_id;
+ if (ts->next_timer_id == INT32_MAX)
+ ts->next_timer_id = 1;
+ else
+ ts->next_timer_id++;
th->timeout = get_time_ms() + delay;
th->func = JS_DupValue(ctx, func);
list_add_tail(&th->link, &ts->os_timers);
- JS_SetOpaque(obj, th);
- return obj;
+ return JS_NewInt32(ctx, th->timer_id);
+}
+
+static JSOSTimer *find_timer_by_id(JSThreadState *ts, int timer_id)
+{
+ struct list_head *el;
+ if (timer_id <= 0)
+ return NULL;
+ list_for_each(el, &ts->os_timers) {
+ JSOSTimer *th = list_entry(el, JSOSTimer, link);
+ if (th->timer_id == timer_id)
+ return th;
+ }
+ return NULL;
}
static JSValue js_os_clearTimeout(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
- JSOSTimer *th = JS_GetOpaque2(ctx, argv[0], js_os_timer_class_id);
- if (!th)
+ JSRuntime *rt = JS_GetRuntime(ctx);
+ JSThreadState *ts = JS_GetRuntimeOpaque(rt);
+ JSOSTimer *th;
+ int timer_id;
+
+ if (JS_ToInt32(ctx, &timer_id, argv[0]))
return JS_EXCEPTION;
- unlink_timer(JS_GetRuntime(ctx), th);
+ th = find_timer_by_id(ts, timer_id);
+ if (!th)
+ return JS_UNDEFINED;
+ free_timer(rt, th);
return JS_UNDEFINED;
}
-static JSClassDef js_os_timer_class = {
- "OSTimer",
- .finalizer = js_os_timer_finalizer,
- .gc_mark = js_os_timer_mark,
-};
-
/* return a promise */
static JSValue js_os_sleepAsync(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
@@ -2111,7 +2095,7 @@ static JSValue js_os_sleepAsync(JSContext *ctx, JSValueConst this_val,
JS_FreeValue(ctx, resolving_funcs[1]);
return JS_EXCEPTION;
}
- th->has_object = FALSE;
+ th->timer_id = -1;
th->timeout = get_time_ms() + delay;
th->func = JS_DupValue(ctx, resolving_funcs[0]);
list_add_tail(&th->link, &ts->os_timers);
@@ -2161,9 +2145,7 @@ static int js_os_poll(JSContext *ctx)
/* the timer expired */
func = th->func;
th->func = JS_UNDEFINED;
- unlink_timer(rt, th);
- if (!th->has_object)
- free_timer(rt, th);
+ free_timer(rt, th);
call_handler(ctx, func);
JS_FreeValue(ctx, func);
return 0;
@@ -2330,9 +2312,7 @@ static int js_os_poll(JSContext *ctx)
/* the timer expired */
func = th->func;
th->func = JS_UNDEFINED;
- unlink_timer(rt, th);
- if (!th->has_object)
- free_timer(rt, th);
+ free_timer(rt, th);
call_handler(ctx, func);
JS_FreeValue(ctx, func);
return 0;
@@ -3735,10 +3715,6 @@ static int js_os_init(JSContext *ctx, JSModuleDef *m)
{
os_poll_func = js_os_poll;
- /* OSTimer class */
- JS_NewClassID(&js_os_timer_class_id);
- JS_NewClass(JS_GetRuntime(ctx), js_os_timer_class_id, &js_os_timer_class);
-
#ifdef USE_WORKER
{
JSRuntime *rt = JS_GetRuntime(ctx);
@@ -3850,7 +3826,8 @@ void js_std_init_handlers(JSRuntime *rt)
init_list_head(&ts->os_signal_handlers);
init_list_head(&ts->os_timers);
init_list_head(&ts->port_list);
-
+ ts->next_timer_id = 1;
+
JS_SetRuntimeOpaque(rt, ts);
#ifdef USE_WORKER
@@ -3883,9 +3860,7 @@ void js_std_free_handlers(JSRuntime *rt)
list_for_each_safe(el, el1, &ts->os_timers) {
JSOSTimer *th = list_entry(el, JSOSTimer, link);
- unlink_timer(rt, th);
- if (!th->has_object)
- free_timer(rt, th);
+ free_timer(rt, th);
}
#ifdef USE_WORKER