22
22
* THE SOFTWARE.
23
23
*/
24
24
25
+ #include "hash.h"
26
+ #include "mem.h"
25
27
#include "private.h"
26
28
#include "utils.h"
27
29
30
+ #define MAX_SAFE_INTEGER (((int64_t)1 << 53) - 1)
28
31
29
- typedef struct {
32
+ struct TJSTimer {
30
33
JSContext * ctx ;
31
- JSRuntime * rt ;
34
+ int64_t id ;
32
35
uv_timer_t handle ;
36
+ UT_hash_handle hh ;
33
37
int interval ;
34
38
JSValue func ;
35
39
int argc ;
36
40
JSValue argv [];
37
- } TJSTimer ;
41
+ };
42
+
43
+ static void uv__timer_close (uv_handle_t * handle ) {
44
+ TJSTimer * th = handle -> data ;
45
+ CHECK_NOT_NULL (th );
46
+ tjs__free (th );
47
+ }
38
48
39
- static void clear_timer (TJSTimer * th ) {
49
+ static void destroy_timer (TJSTimer * th ) {
40
50
JSContext * ctx = th -> ctx ;
51
+ TJSRuntime * qrt = JS_GetContextOpaque (ctx );
52
+ CHECK_NOT_NULL (qrt );
41
53
42
54
JS_FreeValue (ctx , th -> func );
43
55
th -> func = JS_UNDEFINED ;
@@ -47,6 +59,18 @@ static void clear_timer(TJSTimer *th) {
47
59
th -> argv [i ] = JS_UNDEFINED ;
48
60
}
49
61
th -> argc = 0 ;
62
+
63
+ HASH_DEL (qrt -> timers .timers , th );
64
+
65
+ uv_close ((uv_handle_t * ) & th -> handle , uv__timer_close );
66
+ }
67
+
68
+ void tjs__destroy_timers (TJSRuntime * qrt ) {
69
+ TJSTimer * th , * tmp ;
70
+
71
+ HASH_ITER (hh , qrt -> timers .timers , th , tmp ) {
72
+ destroy_timer (th );
73
+ }
50
74
}
51
75
52
76
static void call_timer (TJSTimer * th ) {
@@ -61,12 +85,6 @@ static void call_timer(TJSTimer *th) {
61
85
JS_FreeValue (ctx , ret );
62
86
}
63
87
64
- static void uv__timer_close (uv_handle_t * handle ) {
65
- TJSTimer * th = handle -> data ;
66
- CHECK_NOT_NULL (th );
67
- js_free_rt (th -> rt , th );
68
- }
69
-
70
88
static void uv__timer_cb (uv_timer_t * handle ) {
71
89
TJSTimer * th = handle -> data ;
72
90
CHECK_NOT_NULL (th );
@@ -75,71 +93,43 @@ static void uv__timer_cb(uv_timer_t *handle) {
75
93
tjs__execute_jobs (th -> ctx );
76
94
77
95
call_timer (th );
78
- if (!th -> interval )
79
- clear_timer (th );
80
- }
81
-
82
- static JSClassID tjs_timer_class_id ;
83
96
84
- static void tjs_timer_finalizer (JSRuntime * rt , JSValue val ) {
85
- TJSTimer * th = JS_GetOpaque (val , tjs_timer_class_id );
86
- if (th ) {
87
- clear_timer (th );
88
- /* The handle might have been closed by the loop destruction in TJS_FreeRuntime. */
89
- if (!uv_is_closing ((uv_handle_t * ) & th -> handle ))
90
- uv_close ((uv_handle_t * ) & th -> handle , uv__timer_close );
91
- }
92
- }
93
-
94
- static void tjs_timer_mark (JSRuntime * rt , JSValueConst val , JS_MarkFunc * mark_func ) {
95
- TJSTimer * th = JS_GetOpaque (val , tjs_timer_class_id );
96
- if (th ) {
97
- JS_MarkValue (rt , th -> func , mark_func );
98
- for (int i = 0 ; i < th -> argc ; i ++ )
99
- JS_MarkValue (rt , th -> argv [i ], mark_func );
100
- }
97
+ if (!th -> interval )
98
+ destroy_timer (th );
101
99
}
102
100
103
- static JSClassDef tjs_timer_class = {
104
- "Timer" ,
105
- .finalizer = tjs_timer_finalizer ,
106
- .gc_mark = tjs_timer_mark ,
107
- };
101
+ static JSValue tjs_setTimeout (JSContext * ctx , JSValue this_val , int argc , JSValue * argv , int magic ) {
102
+ TJSRuntime * qrt = JS_GetContextOpaque (ctx );
103
+ CHECK_NOT_NULL (qrt );
108
104
109
- static JSValue tjs_setTimeout (JSContext * ctx , JSValueConst this_val , int argc , JSValueConst * argv , int magic ) {
110
105
int64_t delay ;
111
- JSValueConst func ;
106
+ JSValue func ;
112
107
TJSTimer * th ;
113
- JSValue obj ;
114
108
115
109
func = argv [0 ];
116
110
if (!JS_IsFunction (ctx , func ))
117
111
return JS_ThrowTypeError (ctx , "not a function" );
118
112
119
113
if (argc <= 1 ) {
120
114
delay = 0 ;
121
- } else {
122
- if (JS_ToInt64 (ctx , & delay , argv [1 ]))
123
- return JS_EXCEPTION ;
115
+ } else if (JS_ToInt64 (ctx , & delay , argv [1 ])) {
116
+ return JS_EXCEPTION ;
124
117
}
125
118
126
- obj = JS_NewObjectClass (ctx , tjs_timer_class_id );
127
- if (JS_IsException (obj ))
128
- return obj ;
129
-
130
119
int nargs = argc - 2 ;
131
120
if (nargs < 0 ) {
132
121
nargs = 0 ;
133
122
}
134
123
135
- th = js_mallocz (ctx , sizeof (* th ) + nargs * sizeof (JSValue ));
136
- if (!th ) {
137
- JS_FreeValue (ctx , obj );
138
- return JS_EXCEPTION ;
139
- }
124
+ th = tjs__malloc (sizeof (* th ) + nargs * sizeof (JSValue ));
125
+ if (!th )
126
+ return JS_ThrowOutOfMemory (ctx );
127
+
128
+ th -> id = qrt -> timers .next_timer ++ ;
129
+ if (qrt -> timers .next_timer > MAX_SAFE_INTEGER )
130
+ qrt -> timers .next_timer = 1 ;
140
131
141
132
th -> ctx = ctx ;
142
- th -> rt = JS_GetRuntime (ctx );
143
133
CHECK_EQ (uv_timer_init (tjs_get_loop (ctx ), & th -> handle ), 0 );
144
134
th -> handle .data = th ;
145
135
th -> interval = magic ;
@@ -150,17 +140,26 @@ static JSValue tjs_setTimeout(JSContext *ctx, JSValueConst this_val, int argc, J
150
140
151
141
CHECK_EQ (uv_timer_start (& th -> handle , uv__timer_cb , delay , magic ? delay : 0 /* repeat */ ), 0 );
152
142
153
- JS_SetOpaque (obj , th );
154
- return obj ;
143
+ HASH_ADD_INT64 (qrt -> timers .timers , id , th );
144
+
145
+ return JS_NewInt64 (ctx , th -> id );
155
146
}
156
147
157
- static JSValue tjs_clearTimeout (JSContext * ctx , JSValueConst this_val , int argc , JSValueConst * argv ) {
158
- TJSTimer * th = JS_GetOpaque2 (ctx , argv [0 ], tjs_timer_class_id );
159
- if (!th )
148
+ static JSValue tjs_clearTimeout (JSContext * ctx , JSValue this_val , int argc , JSValue * argv ) {
149
+ TJSRuntime * qrt = JS_GetContextOpaque (ctx );
150
+ CHECK_NOT_NULL (qrt );
151
+ int64_t timer_id ;
152
+ TJSTimer * th = NULL ;
153
+
154
+ if (JS_ToInt64 (ctx , & timer_id , argv [0 ]))
160
155
return JS_EXCEPTION ;
161
156
162
- CHECK_EQ (uv_timer_stop (& th -> handle ), 0 );
163
- clear_timer (th );
157
+ HASH_FIND_INT64 (qrt -> timers .timers , & timer_id , th );
158
+
159
+ if (th != NULL ) {
160
+ CHECK_EQ (uv_timer_stop (& th -> handle ), 0 );
161
+ destroy_timer (th );
162
+ }
164
163
165
164
return JS_UNDEFINED ;
166
165
}
@@ -171,9 +170,5 @@ static const JSCFunctionListEntry tjs_timer_funcs[] = { JS_CFUNC_MAGIC_DEF("setT
171
170
TJS_CFUNC_DEF ("clearInterval" , 1 , tjs_clearTimeout ) };
172
171
173
172
void tjs__mod_timers_init (JSContext * ctx , JSValue ns ) {
174
- JSRuntime * rt = JS_GetRuntime (ctx );
175
-
176
- JS_NewClassID (rt , & tjs_timer_class_id );
177
- JS_NewClass (rt , tjs_timer_class_id , & tjs_timer_class );
178
173
JS_SetPropertyFunctionList (ctx , ns , tjs_timer_funcs , countof (tjs_timer_funcs ));
179
174
}
0 commit comments