fixed and simplified setTimeout() by using an integer timer handle (github issue #218)
This commit is contained in:
parent
84058766e9
commit
9e561d5c2e
1 changed files with 39 additions and 64 deletions
|
@ -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,8 +2145,6 @@ 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);
|
||||
call_handler(ctx, func);
|
||||
JS_FreeValue(ctx, func);
|
||||
|
@ -2330,8 +2312,6 @@ 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);
|
||||
call_handler(ctx, func);
|
||||
JS_FreeValue(ctx, func);
|
||||
|
@ -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,6 +3826,7 @@ 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);
|
||||
|
||||
|
@ -3883,8 +3860,6 @@ 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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue