MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix coroutine processing

+230 -29
+2 -1
include/ant.h
··· 72 72 73 73 jsval_t js_mkpromise(struct js *js); 74 74 void js_resolve_promise(struct js *js, jsval_t promise, jsval_t value); 75 - void js_reject_promise(struct js *js, jsval_t promise, jsval_t value); 75 + void js_reject_promise(struct js *js, jsval_t promise, jsval_t value); 76 + void js_run_event_loop(struct js *js);
+1 -1
meson.build
··· 41 41 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 42 42 43 43 version_conf = configuration_data() 44 - version_conf.set('ANT_VERSION', '0.0.6.6') 44 + version_conf.set('ANT_VERSION', '0.0.6.7') 45 45 version_conf.set('ANT_GIT_HASH', git_hash) 46 46 version_conf.set('ANT_BUILD_DATE', build_date) 47 47
+65 -12
src/ant.c
··· 11 11 #include <string.h> 12 12 #include <sys/time.h> 13 13 #include <time.h> 14 + #include <unistd.h> 14 15 #include <libgen.h> 15 16 #include <sys/stat.h> 16 17 ··· 343 344 344 345 static bool has_pending_coroutines(void) { 345 346 return pending_coroutines.head != NULL; 347 + } 348 + 349 + void js_run_event_loop(struct js *js) { 350 + while (has_pending_microtasks() || has_pending_timers()) { 351 + process_microtasks(js); 352 + 353 + if (has_pending_timers()) { 354 + int64_t next_timeout_ms = get_next_timer_timeout(); 355 + 356 + if (next_timeout_ms <= 0) { 357 + process_timers(js); 358 + continue; 359 + } else { 360 + usleep(next_timeout_ms > 1000000 ? 1000000 : next_timeout_ms * 1000); 361 + } 362 + } 363 + } 346 364 } 347 365 348 366 static void free_coroutine(coroutine_t *coro) { ··· 2839 2857 builtin_promise_then(js, then_args, 2); 2840 2858 js->this_val = saved_this; 2841 2859 2860 + uint8_t saved_flags = js->flags; 2861 + const char *saved_code = js->code; 2862 + jsoff_t saved_clen = js->clen; 2863 + jsoff_t saved_pos = js->pos; 2864 + uint8_t saved_tok = js->tok; 2865 + uint8_t saved_consumed = js->consumed; 2866 + 2842 2867 while (!coro->is_settled) { 2868 + if (has_pending_timers()) { 2869 + int64_t next_timeout = get_next_timer_timeout(); 2870 + if (next_timeout <= 0) { 2871 + process_timers(js); 2872 + js->flags = saved_flags; 2873 + js->code = saved_code; 2874 + js->clen = saved_clen; 2875 + js->pos = saved_pos; 2876 + js->tok = saved_tok; 2877 + js->consumed = saved_consumed; 2878 + } 2879 + } 2880 + 2843 2881 process_microtasks(js); 2882 + js->flags = saved_flags; 2883 + js->code = saved_code; 2884 + js->clen = saved_clen; 2885 + js->pos = saved_pos; 2886 + js->tok = saved_tok; 2887 + js->consumed = saved_consumed; 2844 2888 2845 - while (has_pending_coroutines()) { 2889 + int coroutines_checked = 0; 2890 + int total_coroutines = 0; 2891 + 2892 + coroutine_t *temp = pending_coroutines.head; 2893 + while (temp) { 2894 + total_coroutines++; 2895 + temp = temp->next; 2896 + } 2897 + 2898 + while (has_pending_coroutines() && coroutines_checked < total_coroutines) { 2846 2899 coroutine_t *resumed = dequeue_coroutine(); 2900 + coroutines_checked++; 2901 + 2847 2902 if (resumed == coro) { 2848 2903 jsval_t result = resumed->result; 2849 2904 bool is_error = resumed->is_error; 2850 2905 free_coroutine(resumed); 2851 2906 2852 - if (is_error) { 2853 - return js_throw(js, result); 2854 - } 2907 + if (is_error) return js_throw(js, result); 2855 2908 return result; 2856 2909 } 2857 2910 enqueue_coroutine(resumed); 2858 2911 } 2859 2912 2860 - if (!has_pending_microtasks() && has_pending_timers()) { 2861 - int64_t next_timeout = get_next_timer_timeout(); 2862 - if (next_timeout <= 0) { 2863 - process_timers(js); 2864 - continue; 2865 - } 2866 - } 2867 - 2868 2913 if (!has_pending_microtasks() && !has_pending_coroutines() && !has_pending_timers()) { 2869 2914 free_coroutine(coro); 2870 2915 return js_mkerr(js, "await: promise never settled"); 2916 + } 2917 + 2918 + if (has_pending_timers() && !has_pending_microtasks() && !has_pending_coroutines()) { 2919 + int64_t next_timeout = get_next_timer_timeout(); 2920 + if (next_timeout > 0) { 2921 + int64_t sleep_ms = next_timeout < 1 ? 1 : (next_timeout > 1 ? 1 : next_timeout); 2922 + usleep(sleep_ms * 1000); 2923 + } 2871 2924 } 2872 2925 } 2873 2926
+1 -15
src/main.c
··· 135 135 136 136 int result = execute_module(js, module_file); 137 137 138 - while (has_pending_microtasks() || has_pending_timers()) { 139 - process_microtasks(js); 140 - 141 - if (has_pending_timers()) { 142 - int64_t next_timeout_ms = get_next_timer_timeout(); 143 - 144 - if (next_timeout_ms <= 0) { 145 - process_timers(js); 146 - continue; 147 - } else { 148 - usleep(next_timeout_ms > 1000000 ? 1000000 : next_timeout_ms * 1000); 149 - } 150 - } 151 - } 152 - 138 + js_run_event_loop(js); 153 139 if (dump) js_dump(js); 154 140 155 141 js_destroy(js);
tests/server/html.js examples/server/html.js
tests/server/meow.txt examples/server/meow.txt
tests/server/radix3.js examples/server/radix3.js
tests/server/server.js examples/server/server.js
+5
tests/simple_await_test.cjs
··· 1 + async function test() { 2 + await new Promise(resolve => setTimeout(resolve, 10)); 3 + return "done"; 4 + } 5 + test().then(r => console.log(r));
+9
tests/simple_sync_await.cjs
··· 1 + // Test that works (sync promise) 2 + async function testSync() { 3 + console.log("Before await"); 4 + const result = await Promise.resolve("SYNC"); 5 + console.log("After await:", result); 6 + return "RETURNED_" + result; 7 + } 8 + 9 + testSync().then(r => console.log("Final:", r));
+16
tests/simple_timer_await.cjs
··· 1 + async function test() { 2 + console.log("1: Before await"); 3 + const x = await new Promise(resolve => setTimeout(() => { 4 + console.log("2: Timer fired"); 5 + resolve("VALUE"); 6 + }, 50)); 7 + console.log("3: After await, x =", x); 8 + console.log("4: About to return"); 9 + return "FINAL_" + x; 10 + } 11 + 12 + console.log("A: Calling test()"); 13 + const p = test(); 14 + console.log("B: test() returned"); 15 + p.then(result => console.log("C: Promise resolved:", result)); 16 + console.log("D: Script end");
+7
tests/test_await_return.cjs
··· 1 + async function test() { 2 + console.log("Before"); 3 + await new Promise(resolve => setTimeout(resolve, 10)); 4 + return "done"; 5 + } 6 + 7 + test().then(r => console.log("Result:", r));
+20
tests/test_concurrent_timing.cjs
··· 1 + console.log("START"); 2 + const start = Date.now(); 3 + 4 + async function delay(ms, name) { 5 + console.log(`${name}: Starting ${ms}ms wait at +${Date.now() - start}ms`); 6 + await new Promise(resolve => setTimeout(() => { 7 + console.log(`${name}: Timer fired at +${Date.now() - start}ms`); 8 + resolve(); 9 + }, ms)); 10 + console.log(`${name}: Resumed at +${Date.now() - start}ms`); 11 + return `${name}_done`; 12 + } 13 + 14 + console.log("Calling func1 at +${Date.now() - start}ms"); 15 + delay(100, "func1").then(r => console.log(`func1 complete: ${r} at +${Date.now() - start}ms`)); 16 + console.log("Called func1, calling func2 at +${Date.now() - start}ms"); 17 + delay(50, "func2").then(r => console.log(`func2 complete: ${r} at +${Date.now() - start}ms`)); 18 + console.log("Called func2 at +${Date.now() - start}ms"); 19 + 20 + console.log("END at +${Date.now() - start}ms");
+8
tests/test_cpu_usage.cjs
··· 1 + async function test() { 2 + console.log("Starting wait..."); 3 + await new Promise(resolve => setTimeout(resolve, 500)); 4 + console.log("Done!"); 5 + return "success"; 6 + } 7 + 8 + test().then(r => console.log("Result:", r));
+14
tests/test_debug_await.cjs
··· 1 + async function test() { 2 + console.log("1: Before await"); 3 + const x = await new Promise(resolve => setTimeout(() => { 4 + console.log("2: Timer callback"); 5 + resolve("VALUE"); 6 + }, 10)); 7 + console.log("3: x assigned, x =", x); 8 + console.log("4: About to return"); 9 + return x; 10 + } 11 + 12 + console.log("A: Calling test"); 13 + test().then(r => console.log("Final:", r)); 14 + console.log("B: After test call");
+21
tests/test_immediate_concurrent.cjs
··· 1 + // Test with IMMEDIATELY resolved promises (should work) 2 + console.log("=== Immediate Promises Test ==="); 3 + 4 + async function func1() { 5 + console.log("func1: start"); 6 + const result = await Promise.resolve("func1_result"); 7 + console.log("func1: after await, result:", result); 8 + return result; 9 + } 10 + 11 + async function func2() { 12 + console.log("func2: start"); 13 + const result = await Promise.resolve("func2_result"); 14 + console.log("func2: after await, result:", result); 15 + return result; 16 + } 17 + 18 + func1().then(r => console.log("func1 final:", r)); 19 + func2().then(r => console.log("func2 final:", r)); 20 + 21 + console.log("=== Both called ===");
+29
tests/test_practical_async.cjs
··· 1 + // Real-world async pattern: sequential operations 2 + async function fetchUser(id) { 3 + console.log(`Fetching user ${id}...`); 4 + return new Promise(resolve => setTimeout(() => { 5 + resolve({ id, name: `User${id}` }); 6 + }, 50)); 7 + } 8 + 9 + async function fetchUserPosts(userId) { 10 + console.log(`Fetching posts for user ${userId}...`); 11 + return new Promise(resolve => setTimeout(() => { 12 + resolve([`Post1 by ${userId}`, `Post2 by ${userId}`]); 13 + }, 30)); 14 + } 15 + 16 + async function getUserData(id) { 17 + const user = await fetchUser(id); 18 + console.log("Got user:", user.name); 19 + 20 + const posts = await fetchUserPosts(user.id); 21 + console.log("Got posts:", posts.length); 22 + 23 + return { user, posts }; 24 + } 25 + 26 + // This is the common pattern - sequential async calls within one function 27 + getUserData(123).then(data => { 28 + console.log("Complete!", data.user.name, "has", data.posts.length, "posts"); 29 + });
+32
tests/test_two_awaits.cjs
··· 1 + // Test what happens when TWO async functions are awaiting simultaneously 2 + console.log("=== Multiple Awaits Test ==="); 3 + 4 + async function delay(ms, name) { 5 + console.log(`${name}: Creating ${ms}ms delay`); 6 + return new Promise(resolve => { 7 + setTimeout(() => { 8 + console.log(`${name}: Timer fired after ${ms}ms`); 9 + resolve(`${name}_RESULT`); 10 + }, ms); 11 + }); 12 + } 13 + 14 + async function func1() { 15 + console.log("func1: Before await"); 16 + const result = await delay(100, "func1"); 17 + console.log("func1: After await, result:", result); 18 + return result; 19 + } 20 + 21 + async function func2() { 22 + console.log("func2: Before await"); 23 + const result = await delay(50, "func2"); 24 + console.log("func2: After await, result:", result); 25 + return result; 26 + } 27 + 28 + // Call both functions - they should run concurrently 29 + func1().then(r => console.log("func1 final:", r)); 30 + func2().then(r => console.log("func2 final:", r)); 31 + 32 + console.log("=== Both functions called ===");