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.

migrate to libuv

+396 -131
+3 -1
examples/server/server.js
··· 28 28 }); 29 29 30 30 router.insert('/status', async c => { 31 - const result = (await fetch('http://localhost:8000/meow')).text(); 31 + await new Promise(resolve => setTimeout(resolve, 100)); 32 + const result = await Promise.resolve('Hello'); 33 + // const result = (await fetch('http://localhost:8000/meow')).text(); 32 34 return c.res.body(`server is responding with ${result}`); 33 35 }); 34 36
+1
include/ant.h
··· 75 75 void js_reject_promise(struct js *js, jsval_t promise, jsval_t value); 76 76 77 77 void js_run_event_loop(struct js *js); 78 + void js_poll_events(struct js *js); 78 79 void js_setup_import_meta(struct js *js, const char *filename); 79 80 80 81 typedef jsval_t (*ant_library_init_fn)(struct js *js);
+2 -1
meson.build
··· 51 51 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 52 52 53 53 version_conf = configuration_data() 54 - version_conf.set('ANT_VERSION', '0.0.6.20') 54 + version_conf.set('ANT_VERSION', '0.0.6.21') 55 55 version_conf.set('ANT_GIT_HASH', git_hash) 56 56 version_conf.set('ANT_BUILD_DATE', build_date) 57 57 ··· 75 75 gen_snapshot_sources, 76 76 include_directories: [include, build_include], 77 77 dependencies: [ 78 + libuv_dep, 78 79 curl_dep, 79 80 yyjson_dep, 80 81 uuidv7_dep,
+46 -42
src/ant.c
··· 417 417 return false; 418 418 } 419 419 420 - void js_run_event_loop(struct js *js) { 421 - while (has_pending_microtasks() || has_pending_timers() || has_pending_coroutines()) { 422 - if (has_pending_timers()) { 423 - int64_t next_timeout_ms = get_next_timer_timeout(); 424 - if (next_timeout_ms <= 0) process_timers(js); 425 - } 426 - 427 - process_microtasks(js); 428 - 429 - coroutine_t *temp = pending_coroutines.head; 430 - coroutine_t *prev = NULL; 420 + void js_poll_events(struct js *js) { 421 + if (has_pending_timers()) { 422 + int64_t next_timeout_ms = get_next_timer_timeout(); 423 + if (next_timeout_ms <= 0) process_timers(js); 424 + } 425 + 426 + process_microtasks(js); 427 + 428 + coroutine_t *temp = pending_coroutines.head; 429 + coroutine_t *prev = NULL; 430 + 431 + while (temp) { 432 + coroutine_t *next = temp->next; 431 433 432 - while (temp) { 433 - coroutine_t *next = temp->next; 434 + if (temp->is_ready && temp->mco && mco_status(temp->mco) == MCO_SUSPENDED) { 435 + if (prev) { 436 + prev->next = next; 437 + } else { 438 + pending_coroutines.head = next; 439 + } 440 + if (pending_coroutines.tail == temp) { 441 + pending_coroutines.tail = prev; 442 + } 434 443 435 - if (temp->is_ready && temp->mco && mco_status(temp->mco) == MCO_SUSPENDED) { 436 - if (prev) { 437 - prev->next = next; 438 - } else { 439 - pending_coroutines.head = next; 440 - } 441 - if (pending_coroutines.tail == temp) { 442 - pending_coroutines.tail = prev; 443 - } 444 - 445 - mco_result res = mco_resume(temp->mco); 446 - 447 - if (res == MCO_SUCCESS && mco_status(temp->mco) == MCO_DEAD) { 448 - free_coroutine(temp); 449 - } else if (res == MCO_SUCCESS) { 450 - temp->is_ready = false; 451 - if (pending_coroutines.tail) { 452 - pending_coroutines.tail->next = temp; 453 - pending_coroutines.tail = temp; 454 - } else { 455 - pending_coroutines.head = pending_coroutines.tail = temp; 456 - } 457 - temp->next = NULL; 458 - prev = temp; 444 + mco_result res = mco_resume(temp->mco); 445 + 446 + if (res == MCO_SUCCESS && mco_status(temp->mco) == MCO_DEAD) { 447 + free_coroutine(temp); 448 + } else if (res == MCO_SUCCESS) { 449 + temp->is_ready = false; 450 + if (pending_coroutines.tail) { 451 + pending_coroutines.tail->next = temp; 452 + pending_coroutines.tail = temp; 459 453 } else { 460 - free_coroutine(temp); 454 + pending_coroutines.head = pending_coroutines.tail = temp; 461 455 } 462 - 463 - temp = next; 456 + temp->next = NULL; 457 + prev = temp; 464 458 } else { 465 - prev = temp; 466 - temp = next; 459 + free_coroutine(temp); 467 460 } 461 + 462 + temp = next; 463 + } else { 464 + prev = temp; 465 + temp = next; 468 466 } 467 + } 468 + } 469 + 470 + void js_run_event_loop(struct js *js) { 471 + while (has_pending_microtasks() || has_pending_timers() || has_pending_coroutines()) { 472 + js_poll_events(js); 469 473 470 474 if (!has_pending_microtasks() && has_pending_timers() && !has_ready_coroutines()) { 471 475 int64_t next_timeout_ms = get_next_timer_timeout();
+344 -87
src/modules/server.c
··· 2 2 #include <stdlib.h> 3 3 #include <string.h> 4 4 #include <signal.h> 5 - #include <mongoose.h> 5 + #include <unistd.h> 6 + #include <uv.h> 6 7 7 8 #include "ant.h" 8 9 #include "runtime.h" ··· 10 11 #include "modules/timer.h" 11 12 #include "modules/json.h" 12 13 13 - typedef struct { 14 + #define MAX_WRITE_HANDLES 1000 15 + #define READ_BUFFER_SIZE 8192 16 + 17 + typedef struct response_ctx_s { 14 18 int status; 15 19 char *body; 16 20 char *content_type; 17 21 int sent; 22 + uv_tcp_t *client_handle; 23 + struct response_ctx_s *next; 18 24 } response_ctx_t; 19 25 20 - typedef struct { 26 + typedef struct http_server_s { 21 27 struct js *js; 22 28 jsval_t handler; 23 29 int port; 30 + uv_tcp_t server; 31 + uv_loop_t *loop; 32 + response_ctx_t *pending_responses; 24 33 } http_server_t; 25 34 26 - static struct mg_mgr s_mgr; 27 - static int g_mgr_initialized = 0; 35 + typedef struct { 36 + uv_tcp_t handle; 37 + http_server_t *server; 38 + char *buffer; 39 + size_t buffer_len; 40 + size_t buffer_capacity; 41 + response_ctx_t *response_ctx; 42 + } client_t; 43 + 44 + typedef struct { 45 + uv_write_t req; 46 + uv_buf_t buf; 47 + } write_req_t; 48 + 49 + static uv_loop_t *g_loop = NULL; 50 + static int g_loop_initialized = 0; 51 + static uv_timer_t g_js_timer; 52 + static struct js *g_js = NULL; 28 53 29 54 static void server_signal_handler(int signum) { 30 55 (void)signum; 31 - printf("\nShutting down server...\n"); 32 - 33 - if (g_mgr_initialized) { 34 - mg_mgr_free(&s_mgr); 35 - g_mgr_initialized = 0; 36 - } 37 - 56 + if (g_loop_initialized && g_loop) uv_stop(g_loop); 38 57 exit(0); 39 58 } 40 59 41 - static jsval_t wait_for_promise(struct js *js, jsval_t promise_val) { 42 - if (js_type(promise_val) != JS_PRIV) return promise_val; 60 + static void on_js_timer(uv_timer_t *handle) { 61 + (void)handle; 62 + } 63 + 64 + typedef struct { 65 + char method[16]; 66 + char uri[2048]; 67 + char query[2048]; 68 + char *body; 69 + size_t body_len; 70 + } http_request_t; 71 + 72 + static int parse_http_request(const char *buffer, size_t len, http_request_t *req) { 73 + const char *method_end = strchr(buffer, ' '); 74 + if (!method_end || method_end - buffer >= sizeof(req->method)) return -1; 43 75 44 - jsval_t state_check = js_get(js, promise_val, "__state"); 45 - if (js_type(state_check) == JS_UNDEF) return promise_val; 76 + memcpy(req->method, buffer, method_end - buffer); 77 + req->method[method_end - buffer] = '\0'; 78 + 79 + const char *uri_start = method_end + 1; 80 + const char *uri_end = strchr(uri_start, ' '); 81 + if (!uri_end) return -1; 46 82 47 - while (has_pending_microtasks()) { 48 - process_microtasks(js); 83 + const char *query_start = strchr(uri_start, '?'); 84 + if (query_start && query_start < uri_end) { 85 + size_t uri_len = query_start - uri_start; 86 + if (uri_len >= sizeof(req->uri)) return -1; 87 + memcpy(req->uri, uri_start, uri_len); 88 + req->uri[uri_len] = '\0'; 49 89 50 - jsval_t state_val = js_get(js, promise_val, "__state"); 51 - if (js_type(state_val) == JS_NUM) { 52 - int state = (int)js_getnum(state_val); 53 - if (state != 0) { 54 - jsval_t value_val = js_get(js, promise_val, "__value"); 55 - return value_val; 56 - } 57 - } 90 + size_t query_len = uri_end - query_start - 1; 91 + if (query_len >= sizeof(req->query)) return -1; 92 + memcpy(req->query, query_start + 1, query_len); 93 + req->query[query_len] = '\0'; 94 + } else { 95 + size_t uri_len = uri_end - uri_start; 96 + if (uri_len >= sizeof(req->uri)) return -1; 97 + memcpy(req->uri, uri_start, uri_len); 98 + req->uri[uri_len] = '\0'; 99 + req->query[0] = '\0'; 58 100 } 59 101 60 - jsval_t state_val = js_get(js, promise_val, "__state"); 61 - if (js_type(state_val) == JS_NUM) { 62 - int state = (int)js_getnum(state_val); 63 - if (state != 0) { 64 - jsval_t value_val = js_get(js, promise_val, "__value"); 65 - return value_val; 102 + const char *body_start = strstr(buffer, "\r\n\r\n"); 103 + if (body_start) { 104 + body_start += 4; 105 + req->body_len = len - (body_start - buffer); 106 + if (req->body_len > 0) { 107 + req->body = malloc(req->body_len + 1); 108 + if (req->body) { 109 + memcpy(req->body, body_start, req->body_len); 110 + req->body[req->body_len] = '\0'; 111 + } 112 + } else { 113 + req->body = NULL; 66 114 } 115 + } else { 116 + req->body = NULL; 117 + req->body_len = 0; 67 118 } 68 119 69 - return promise_val; 120 + return 0; 121 + } 122 + 123 + static void free_http_request(http_request_t *req) { 124 + if (req->body) { 125 + free(req->body); 126 + req->body = NULL; 127 + } 70 128 } 129 + 130 + static void on_close(uv_handle_t *handle); 131 + static void send_response(uv_stream_t *client, response_ctx_t *res_ctx); 71 132 72 133 static jsval_t res_status(struct js *js, jsval_t *args, int nargs) { 73 134 if (nargs < 1) return js_mkundef(); ··· 171 232 return js_mkundef(); 172 233 } 173 234 174 - static void http_handler(struct mg_connection *c, int ev, void *ev_data) { 175 - if (ev == MG_EV_HTTP_MSG) { 176 - http_server_t *server = (http_server_t *)c->fn_data; 177 - if (server == NULL || server->js == NULL) { 178 - mg_http_reply(c, 500, "Content-Type: text/plain\r\n", "Server error"); 179 - return; 180 - } 235 + static void on_write(uv_write_t *req, int status) { 236 + write_req_t *wr = (write_req_t *)req; 237 + if (status) fprintf(stderr, "Write error: %s\n", uv_strerror(status)); 238 + if (wr->buf.base) free(wr->buf.base); 239 + free(wr); 240 + } 241 + 242 + static void send_response(uv_stream_t *client, response_ctx_t *res_ctx) { 243 + char header[4096]; 244 + int header_len = snprintf(header, sizeof(header), 245 + "HTTP/1.1 %d %s\r\n" 246 + "Content-Type: %s\r\n" 247 + "Content-Length: %zu\r\n" 248 + "Connection: close\r\n" 249 + "\r\n", 250 + res_ctx->status, 251 + res_ctx->status == 200 ? "OK" : 252 + res_ctx->status == 404 ? "Not Found" : 253 + res_ctx->status == 500 ? "Internal Server Error" : "Unknown", 254 + res_ctx->content_type ? res_ctx->content_type : "text/plain", 255 + res_ctx->body ? strlen(res_ctx->body) : 0 256 + ); 257 + 258 + size_t body_len = res_ctx->body ? strlen(res_ctx->body) : 0; 259 + size_t total_len = header_len + body_len; 260 + 261 + write_req_t *write_req = malloc(sizeof(write_req_t)); 262 + if (!write_req) return; 263 + 264 + char *response = malloc(total_len); 265 + if (!response) { 266 + free(write_req); 267 + return; 268 + } 269 + 270 + memcpy(response, header, header_len); 271 + if (body_len > 0) memcpy(response + header_len, res_ctx->body, body_len); 272 + 273 + write_req->buf = uv_buf_init(response, total_len); 274 + uv_write((uv_write_t *)write_req, client, &write_req->buf, 1, on_write); 275 + } 276 + 277 + static void handle_http_request(client_t *client, http_request_t *http_req) { 278 + http_server_t *server = client->server; 279 + jsval_t result = js_mkundef(); 280 + 281 + response_ctx_t *res_ctx = malloc(sizeof(response_ctx_t)); 282 + if (!res_ctx) { 283 + fprintf(stderr, "Failed to allocate response context\n"); 284 + uv_close((uv_handle_t *)&client->handle, on_close); 285 + return; 286 + } 287 + 288 + res_ctx->status = 200; 289 + res_ctx->body = ""; 290 + res_ctx->content_type = "text/plain"; 291 + res_ctx->sent = 0; 292 + res_ctx->client_handle = &client->handle; 293 + res_ctx->next = NULL; 294 + 295 + client->response_ctx = res_ctx; 296 + res_ctx->next = server->pending_responses; 297 + server->pending_responses = res_ctx; 298 + 299 + if (server->handler != 0 && js_type(server->handler) != JS_UNDEF) { 300 + jsval_t req = js_mkobj(server->js); 301 + js_set(server->js, req, "method", js_mkstr(server->js, http_req->method, strlen(http_req->method))); 302 + js_set(server->js, req, "uri", js_mkstr(server->js, http_req->uri, strlen(http_req->uri))); 303 + js_set(server->js, req, "query", js_mkstr(server->js, http_req->query, strlen(http_req->query))); 304 + js_set(server->js, req, "body", js_mkstr(server->js, http_req->body ? http_req->body : "", http_req->body ? http_req->body_len : 0)); 181 305 182 - struct mg_http_message *hm = (struct mg_http_message *) ev_data; 306 + jsval_t res_obj = js_mkobj(server->js); 307 + js_set(server->js, res_obj, "__response_ctx", js_mknum((unsigned long)res_ctx)); 308 + js_set(server->js, res_obj, "status", js_mkfun(res_status)); 309 + js_set(server->js, res_obj, "body", js_mkfun(res_body)); 310 + js_set(server->js, res_obj, "html", js_mkfun(res_html)); 311 + js_set(server->js, res_obj, "json", js_mkfun(res_json)); 183 312 184 - jsval_t result = js_mkundef(); 313 + jsval_t args[2] = {req, res_obj}; 314 + result = js_call(server->js, server->handler, args, 2); 185 315 186 - response_ctx_t res_ctx = { 187 - .status = 200, 188 - .body = "", 189 - .content_type = "text/plain", 190 - .sent = 0 191 - }; 316 + return; 317 + } 318 + 319 + if (js_type(result) == JS_ERR) { 320 + fprintf(stderr, "Handler error: %s\n", js_str(server->js, result)); 321 + res_ctx->status = 500; 322 + res_ctx->body = "Internal Server Error"; 323 + res_ctx->content_type = "text/plain"; 324 + res_ctx->sent = 1; 325 + } else { 326 + res_ctx->status = 404; 327 + res_ctx->body = "Not Found"; 328 + res_ctx->content_type = "text/plain"; 329 + res_ctx->sent = 1; 330 + } 331 + 332 + } 333 + 334 + static void on_close(uv_handle_t *handle) { 335 + client_t *client = (client_t *)handle->data; 336 + if (client) { 337 + if (client->buffer) free(client->buffer); 338 + free(client); 339 + } 340 + } 341 + 342 + static void check_pending_responses(http_server_t *server) { 343 + response_ctx_t **current = &server->pending_responses; 344 + 345 + while (*current) { 346 + response_ctx_t *ctx = *current; 192 347 193 - if (server->handler != 0 && js_type(server->handler) != JS_UNDEF) { 194 - jsval_t req = js_mkobj(server->js); 195 - js_set(server->js, req, "method", js_mkstr(server->js, hm->method.buf, hm->method.len)); 196 - js_set(server->js, req, "uri", js_mkstr(server->js, hm->uri.buf, hm->uri.len)); 197 - js_set(server->js, req, "query", js_mkstr(server->js, hm->query.buf, hm->query.len)); 198 - js_set(server->js, req, "body", js_mkstr(server->js, hm->body.buf, hm->body.len)); 199 - 200 - jsval_t res_obj = js_mkobj(server->js); 201 - js_set(server->js, res_obj, "__response_ctx", js_mknum((unsigned long)&res_ctx)); 202 - js_set(server->js, res_obj, "status", js_mkfun(res_status)); 203 - js_set(server->js, res_obj, "body", js_mkfun(res_body)); 204 - js_set(server->js, res_obj, "html", js_mkfun(res_html)); 205 - js_set(server->js, res_obj, "json", js_mkfun(res_json)); 206 - 207 - jsval_t args[2] = {req, res_obj}; 208 - 209 - result = js_call(server->js, server->handler, args, 2); 210 - result = wait_for_promise(server->js, result); 348 + if (ctx->sent) { 349 + *current = ctx->next; 211 350 212 - if (res_ctx.sent) { 213 - char headers[256]; 214 - snprintf(headers, sizeof(headers), "Content-Type: %s\r\n", res_ctx.content_type ? res_ctx.content_type : "text/plain"); 215 - mg_http_reply(c, res_ctx.status, headers, "%s", res_ctx.body ? res_ctx.body : ""); 216 - return; 351 + if (!uv_is_closing((uv_handle_t *)ctx->client_handle)) { 352 + send_response((uv_stream_t *)ctx->client_handle, ctx); 353 + uv_close((uv_handle_t *)ctx->client_handle, on_close); 217 354 } 355 + 356 + free(ctx); 357 + } else { 358 + current = &ctx->next; 218 359 } 360 + } 361 + } 362 + 363 + static void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { 364 + buf->base = malloc(suggested_size); 365 + buf->len = suggested_size; 366 + } 367 + 368 + static void on_read(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { 369 + client_t *client = (client_t *)stream->data; 370 + 371 + if (nread < 0) { 372 + if (nread != UV_EOF) fprintf(stderr, "Read error: %s\n", uv_strerror(nread)); 373 + uv_close((uv_handle_t *)stream, on_close); 374 + free(buf->base); 375 + return; 376 + } 377 + 378 + if (nread == 0) { 379 + free(buf->base); 380 + return; 381 + } 382 + 383 + size_t new_len = client->buffer_len + nread; 384 + if (new_len > client->buffer_capacity) { 385 + size_t new_capacity = client->buffer_capacity * 2; 386 + if (new_capacity < new_len) new_capacity = new_len; 387 + char *new_buffer = realloc(client->buffer, new_capacity); 388 + if (!new_buffer) { 389 + free(buf->base); 390 + uv_close((uv_handle_t *)stream, on_close); 391 + return; 392 + } 393 + client->buffer = new_buffer; 394 + client->buffer_capacity = new_capacity; 395 + } 396 + 397 + memcpy(client->buffer + client->buffer_len, buf->base, nread); 398 + client->buffer_len = new_len; 399 + free(buf->base); 400 + 401 + if (strstr(client->buffer, "\r\n\r\n")) { 402 + uv_read_stop(stream); 219 403 220 - if (js_type(result) == JS_ERR) { 221 - fprintf(stderr, "Handler error: %s\n", js_str(server->js, result)); 222 - mg_http_reply(c, 500, "Content-Type: text/plain\r\n", "Internal Server Error"); 404 + http_request_t http_req = {0}; 405 + if (parse_http_request(client->buffer, client->buffer_len, &http_req) == 0) { 406 + handle_http_request(client, &http_req); 407 + free_http_request(&http_req); 223 408 } else { 224 - mg_http_reply(c, 404, "Content-Type: text/plain\r\n", "Not Found"); 409 + response_ctx_t *res_ctx = malloc(sizeof(response_ctx_t)); 410 + if (res_ctx) { 411 + res_ctx->status = 400; 412 + res_ctx->body = "Bad Request"; 413 + res_ctx->content_type = "text/plain"; 414 + res_ctx->sent = 1; 415 + res_ctx->client_handle = &client->handle; 416 + res_ctx->next = client->server->pending_responses; 417 + client->server->pending_responses = res_ctx; 418 + client->response_ctx = res_ctx; 419 + } 225 420 } 226 421 } 227 422 } 228 423 424 + static void on_connection(uv_stream_t *server, int status) { 425 + if (status < 0) { 426 + fprintf(stderr, "Connection error: %s\n", uv_strerror(status)); 427 + return; 428 + } 429 + 430 + http_server_t *http_server = (http_server_t *)server->data; 431 + 432 + client_t *client = malloc(sizeof(client_t)); 433 + if (!client) { 434 + fprintf(stderr, "Failed to allocate client\n"); 435 + return; 436 + } 437 + 438 + client->server = http_server; 439 + client->buffer_capacity = READ_BUFFER_SIZE; 440 + client->buffer = malloc(client->buffer_capacity); 441 + client->buffer_len = 0; 442 + client->response_ctx = NULL; 443 + 444 + if (!client->buffer) { 445 + free(client); 446 + return; 447 + } 448 + 449 + uv_tcp_init(http_server->loop, &client->handle); 450 + client->handle.data = client; 451 + 452 + if (uv_accept(server, (uv_stream_t *)&client->handle) == 0) { 453 + uv_read_start((uv_stream_t *)&client->handle, alloc_buffer, on_read); 454 + } else { 455 + uv_close((uv_handle_t *)&client->handle, on_close); 456 + } 457 + } 458 + 229 459 // Ant.serve(port, handler) 230 460 jsval_t js_serve(struct js *js, jsval_t *args, int nargs) { 231 461 if (nargs < 1) { ··· 248 478 server->port = port; 249 479 server->handler = (nargs >= 2) ? args[1] : js_mkundef(); 250 480 251 - char url[64]; 252 - snprintf(url, sizeof(url), "http://0.0.0.0:%d", port); 253 - 254 - if (!g_mgr_initialized) { 255 - mg_log_set(MG_LL_INFO); 256 - mg_mgr_init(&s_mgr); 257 - g_mgr_initialized = 1; 481 + if (!g_loop_initialized) { 482 + g_loop = uv_default_loop(); 483 + g_loop_initialized = 1; 258 484 259 485 signal(SIGINT, server_signal_handler); 260 486 signal(SIGTERM, server_signal_handler); 261 487 } 262 488 263 - struct mg_connection *c = mg_http_listen(&s_mgr, url, http_handler, server); 264 - if (c == NULL) { 265 - fprintf(stderr, "Error: Failed to start HTTP server on port %d\n", port); 489 + server->loop = g_loop; 490 + 491 + uv_tcp_init(g_loop, &server->server); 492 + server->server.data = server; 493 + 494 + struct sockaddr_in addr; 495 + uv_ip4_addr("0.0.0.0", port, &addr); 496 + 497 + int r = uv_tcp_bind(&server->server, (const struct sockaddr *)&addr, 0); 498 + if (r) { 499 + fprintf(stderr, "Error: Failed to bind to port %d: %s\n", port, uv_strerror(r)); 500 + free(server); 501 + return js_mknum(0); 502 + } 503 + 504 + r = uv_listen((uv_stream_t *)&server->server, 128, on_connection); 505 + if (r) { 506 + fprintf(stderr, "Error: Failed to listen on port %d: %s\n", port, uv_strerror(r)); 266 507 free(server); 267 508 return js_mknum(0); 268 509 } 510 + 511 + server->pending_responses = NULL; 512 + g_js = js; 513 + 514 + uv_timer_init(g_loop, &g_js_timer); 515 + 516 + while (uv_loop_alive(g_loop)) { 517 + if (has_pending_timers()) { 518 + int64_t next_timeout_ms = get_next_timer_timeout(); 519 + if (next_timeout_ms >= 0) { 520 + uint64_t timeout = next_timeout_ms > 0 ? (uint64_t)next_timeout_ms : 0; 521 + uv_timer_start(&g_js_timer, on_js_timer, timeout, 0); 522 + } 523 + } else uv_timer_stop(&g_js_timer); 269 524 270 - for (;;) { 271 - mg_mgr_poll(&s_mgr, 1000); 525 + uv_run(g_loop, UV_RUN_ONCE); 526 + js_poll_events(js); 527 + 528 + check_pending_responses(server); 272 529 } 273 530 274 531 return js_mknum(1);