@@ -94,6 +94,8 @@ extern char **environ;
94
94
#include "list.h"
95
95
#include "quickjs-libc.h"
96
96
97
+ #define MAX_SAFE_INTEGER (((int64_t) 1 << 53) - 1)
98
+
97
99
/* TODO:
98
100
- add socket calls
99
101
*/
@@ -112,7 +114,7 @@ typedef struct {
112
114
113
115
typedef struct {
114
116
struct list_head link ;
115
- uint8_t has_object : 1 ;
117
+ int64_t timer_id ;
116
118
uint8_t repeats :1 ;
117
119
int64_t timeout ;
118
120
int64_t delay ;
@@ -150,6 +152,7 @@ typedef struct JSThreadState {
150
152
struct list_head os_timers ; /* list of JSOSTimer.link */
151
153
struct list_head port_list ; /* list of JSWorkerMessageHandler.link */
152
154
int eval_script_recurse ; /* only used in the main thread */
155
+ int64_t next_timer_id ; /* for setTimeout / setInterval */
153
156
/* not used in the main thread */
154
157
JSWorkerMessagePipe * recv_pipe , * send_pipe ;
155
158
} JSThreadState ;
@@ -2029,41 +2032,13 @@ static uint64_t js__hrtime_ms(void)
2029
2032
return js__hrtime_ns () / (1000 * 1000 );
2030
2033
}
2031
2034
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
-
2040
2035
static void free_timer (JSRuntime * rt , JSOSTimer * th )
2041
2036
{
2037
+ list_del (& th -> link );
2042
2038
JS_FreeValueRT (rt , th -> func );
2043
2039
js_free_rt (rt , th );
2044
2040
}
2045
2041
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
-
2067
2042
// TODO(bnoordhuis) accept string as first arg and eval at timer expiry
2068
2043
// TODO(bnoordhuis) retain argv[2..] as args for callback if argc > 2
2069
2044
static JSValue js_os_setTimeout (JSContext * ctx , JSValue this_val ,
@@ -2074,7 +2049,6 @@ static JSValue js_os_setTimeout(JSContext *ctx, JSValue this_val,
2074
2049
int64_t delay ;
2075
2050
JSValue func ;
2076
2051
JSOSTimer * th ;
2077
- JSValue obj ;
2078
2052
2079
2053
func = argv [0 ];
2080
2054
if (!JS_IsFunction (ctx , func ))
@@ -2083,42 +2057,50 @@ static JSValue js_os_setTimeout(JSContext *ctx, JSValue this_val,
2083
2057
return JS_EXCEPTION ;
2084
2058
if (delay < 1 )
2085
2059
delay = 1 ;
2086
- obj = JS_NewObjectClass (ctx , js_os_timer_class_id );
2087
- if (JS_IsException (obj ))
2088
- return obj ;
2089
2060
th = js_mallocz (ctx , sizeof (* th ));
2090
- if (!th ) {
2091
- JS_FreeValue (ctx , obj );
2061
+ if (!th )
2092
2062
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 ;
2095
2066
th -> repeats = (magic > 0 );
2096
2067
th -> timeout = js__hrtime_ms () + delay ;
2097
2068
th -> delay = delay ;
2098
2069
th -> func = JS_DupValue (ctx , func );
2099
2070
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 ;
2102
2085
}
2103
2086
2104
2087
static JSValue js_os_clearTimeout (JSContext * ctx , JSValue this_val ,
2105
2088
int argc , JSValue * argv )
2106
2089
{
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 ]))
2109
2096
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 );
2113
2101
return JS_UNDEFINED ;
2114
2102
}
2115
2103
2116
- static JSClassDef js_os_timer_class = {
2117
- "OSTimer" ,
2118
- .finalizer = js_os_timer_finalizer ,
2119
- .gc_mark = js_os_timer_mark ,
2120
- };
2121
-
2122
2104
/* return a promise */
2123
2105
static JSValue js_os_sleepAsync (JSContext * ctx , JSValueConst this_val ,
2124
2106
int argc , JSValueConst * argv )
@@ -2142,7 +2124,7 @@ static JSValue js_os_sleepAsync(JSContext *ctx, JSValueConst this_val,
2142
2124
JS_FreeValue (ctx , resolving_funcs [1 ]);
2143
2125
return JS_EXCEPTION ;
2144
2126
}
2145
- th -> has_object = FALSE ;
2127
+ th -> timer_id = -1 ;
2146
2128
th -> timeout = js__hrtime_ms () + delay ;
2147
2129
th -> func = JS_DupValue (ctx , resolving_funcs [0 ]);
2148
2130
list_add_tail (& th -> link , & ts -> os_timers );
@@ -2185,13 +2167,10 @@ static int js_os_run_timers(JSRuntime *rt, JSContext *ctx, JSThreadState *ts)
2185
2167
min_delay = min_int (min_delay , delay );
2186
2168
} else {
2187
2169
func = JS_DupValueRT (rt , th -> func );
2188
- unlink_timer (rt , th );
2189
- if (th -> repeats ) {
2170
+ if (th -> repeats )
2190
2171
th -> timeout = cur_time + th -> delay ;
2191
- list_add_tail (& th -> link , & ts -> os_timers );
2192
- } else if (!th -> has_object ) {
2172
+ else
2193
2173
free_timer (rt , th );
2194
- }
2195
2174
call_handler (ctx , func );
2196
2175
JS_FreeValueRT (rt , func );
2197
2176
return 0 ;
@@ -3785,15 +3764,11 @@ static const JSCFunctionListEntry js_os_funcs[] = {
3785
3764
3786
3765
static int js_os_init (JSContext * ctx , JSModuleDef * m )
3787
3766
{
3788
- JSRuntime * rt = JS_GetRuntime (ctx );
3789
3767
os_poll_func = js_os_poll ;
3790
3768
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
-
3795
3769
#ifdef USE_WORKER
3796
3770
{
3771
+ JSRuntime * rt = JS_GetRuntime (ctx );
3797
3772
JSThreadState * ts = JS_GetRuntimeOpaque (rt );
3798
3773
JSValue proto , obj ;
3799
3774
/* Worker class */
@@ -3819,8 +3794,7 @@ static int js_os_init(JSContext *ctx, JSModuleDef *m)
3819
3794
}
3820
3795
#endif /* USE_WORKER */
3821
3796
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 ));
3824
3798
}
3825
3799
3826
3800
JSModuleDef * js_init_module_os (JSContext * ctx , const char * module_name )
@@ -3904,6 +3878,8 @@ void js_std_init_handlers(JSRuntime *rt)
3904
3878
init_list_head (& ts -> os_timers );
3905
3879
init_list_head (& ts -> port_list );
3906
3880
3881
+ ts -> next_timer_id = 1 ;
3882
+
3907
3883
JS_SetRuntimeOpaque (rt , ts );
3908
3884
3909
3885
#ifdef USE_WORKER
@@ -3936,9 +3912,7 @@ void js_std_free_handlers(JSRuntime *rt)
3936
3912
3937
3913
list_for_each_safe (el , el1 , & ts -> os_timers ) {
3938
3914
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 );
3942
3916
}
3943
3917
3944
3918
#ifdef USE_WORKER
0 commit comments