Skip to content

Commit 7b22e22

Browse files
committed
core: refactor timers
- Don't use JS objects for timer handles - Use a hash table in C rather an a Map in JS - Allocate memory without using the JS allocator (1) 1) This is important because the libuv loop outlives the JS runtime. Since handle closing is not sync and the callback where we need to free the structures will be called later it's not safe to use it. This is a small step in the direction of not using the JS allocator for structures that embed libuv handles.
1 parent 47d2712 commit 7b22e22

File tree

8 files changed

+55578
-54524
lines changed

8 files changed

+55578
-54524
lines changed

src/bundles/c/core/polyfills.c

+54,247-54,358
Large diffs are not rendered by default.

src/hash.h

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* txiki.js
3+
*
4+
* Copyright (c) 2024-present Saúl Ibarra Corretgé <s@saghul.net>
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19+
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
#ifndef TJS_HASH_H
26+
#define TJS_HASH_H
27+
28+
#include "uthash.h"
29+
30+
#include <stdint.h>
31+
32+
#define HASH_FIND_INT64(head,findint,out) \
33+
HASH_FIND(hh,head,findint,sizeof(int64_t),out)
34+
#define HASH_ADD_INT64(head,intfield,add) \
35+
HASH_ADD(hh,head,intfield,sizeof(int64_t),add)
36+
37+
#endif

src/js/polyfills/timers.js

+4-58
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,7 @@
11
const core = globalThis[Symbol.for('tjs.internal.core')];
22

3-
const timers = new Map();
4-
let nextId = 1;
3+
globalThis.setTimeout = core.setTimeout;
4+
globalThis.clearTimeout = core.clearTimeout;
55

6-
function getNextId() {
7-
let id;
8-
9-
// eslint-disable-next-line no-constant-condition
10-
while (true) {
11-
id = nextId++;
12-
13-
if (!timers.has(id)) {
14-
break;
15-
}
16-
17-
if (nextId >= Number.MAX_SAFE_INTEGER) {
18-
nextId = 1;
19-
}
20-
}
21-
22-
return id;
23-
}
24-
25-
globalThis.setTimeout = (fn, ms, ...args) => {
26-
const timer = core.setTimeout(fn, ms, ...args);
27-
const id = getNextId();
28-
29-
timers.set(id, timer);
30-
31-
return id;
32-
};
33-
34-
globalThis.clearTimeout = id => {
35-
const timer = timers.get(id);
36-
37-
if (timer) {
38-
core.clearTimeout(timer);
39-
}
40-
41-
timers.delete(id);
42-
};
43-
44-
globalThis.setInterval = (fn, ms, ...args) => {
45-
const timer = core.setInterval(fn, ms, ...args);
46-
const id = getNextId();
47-
48-
timers.set(id, timer);
49-
50-
return id;
51-
};
52-
53-
globalThis.clearInterval = id => {
54-
const timer = timers.get(id);
55-
56-
if (timer) {
57-
core.clearInterval(timer);
58-
}
59-
60-
timers.delete(id);
61-
};
6+
globalThis.setInterval = core.setInterval;
7+
globalThis.clearInterval = core.setInterval;

src/mem.h

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* txiki.js
3+
*
4+
* Copyright (c) 2024-present Saúl Ibarra Corretgé <s@saghul.net>
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19+
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
* THE SOFTWARE.
23+
*/
24+
25+
#ifndef TJS_MEM_H
26+
#define TJS_MEM_H
27+
28+
#include "../deps/quickjs/cutils.h"
29+
30+
#include <stdlib.h>
31+
32+
#ifdef TJS__HAS_MIMALLOC
33+
#include <mimalloc.h>
34+
#endif
35+
36+
static inline size_t tjs__malloc_usable_size(const void *ptr) {
37+
#if defined(TJS__HAS_MIMALLOC)
38+
return mi_malloc_usable_size(ptr);
39+
#else
40+
return js__malloc_usable_size(ptr):
41+
#endif
42+
}
43+
44+
static inline void *tjs__malloc(size_t size) {
45+
#ifdef TJS__HAS_MIMALLOC
46+
return mi_malloc(size);
47+
#else
48+
return malloc(size);
49+
#endif
50+
}
51+
52+
static inline void *tjs__calloc(size_t count, size_t size) {
53+
#ifdef TJS__HAS_MIMALLOC
54+
return mi_calloc(count, size);
55+
#else
56+
return calloc(count, size);
57+
#endif
58+
}
59+
60+
static inline void tjs__free(void *ptr) {
61+
#ifdef TJS__HAS_MIMALLOC
62+
mi_free(ptr);
63+
#else
64+
free(ptr);
65+
#endif
66+
}
67+
68+
static inline void *tjs__realloc(void *ptr, size_t size) {
69+
#ifdef TJS__HAS_MIMALLOC
70+
return mi_realloc(ptr, size);
71+
#else
72+
return realloc(ptr, size);
73+
#endif
74+
}
75+
76+
#endif

src/private.h

+7
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <stdbool.h>
3535
#include <uv.h>
3636

37+
typedef struct TJSTimer TJSTimer;
3738

3839
struct TJSRuntime {
3940
TJSRunOptions options;
@@ -54,6 +55,10 @@ struct TJSRuntime {
5455
struct {
5556
IM3Environment env;
5657
} wasm_ctx;
58+
struct {
59+
TJSTimer *timers;
60+
int64_t next_timer;
61+
} timers;
5762
};
5863

5964
void tjs__mod_dns_init(JSContext *ctx, JSValue ns);
@@ -96,6 +101,8 @@ JSValue tjs__get_args(JSContext *ctx);
96101

97102
int tjs__eval_bytecode(JSContext *ctx, const uint8_t *buf, size_t buf_len);
98103

104+
void tjs__destroy_timers(TJSRuntime *qrt);
105+
99106
uv_loop_t *TJS_GetLoop(TJSRuntime *qrt);
100107
TJSRuntime *TJS_NewRuntimeWorker(void);
101108
TJSRuntime *TJS_NewRuntimeInternal(bool is_worker, TJSRunOptions *options);

0 commit comments

Comments
 (0)