From: Dmitry Volyntsev Date: Tue, 5 Dec 2023 16:54:18 +0000 (-0800) Subject: Refactored asynchronous events. X-Git-Url: http://www.kaiwu.me/postgresql/commit/?a=commitdiff_plain;h=16004b37e9fee21ad8e1369023903163cf55f6a0;p=njs.git Refactored asynchronous events. To align njs with other JS engines, async events are removed from njs core. The following functions were removed: njs_vm_add_event(), njs_vm_del_event(), njs_vm_waiting(). Instead the host is expected to manage async events by itself. In addition, the posted events are renamed to jobs, to better align with the ECMA specs. The following methods are removed: njs_vm_run(). Instead, the host is expected to call njs_vm_execute_pending_job() in a loop to execute pending jobs. The following functions were added: njs_vm_enqueue_job(). --- diff --git a/auto/sources b/auto/sources index 9f5d9d5a..d2172e37 100644 --- a/auto/sources +++ b/auto/sources @@ -34,7 +34,6 @@ NJS_LIB_SRCS=" \ src/njs_generator.c \ src/njs_disassembler.c \ src/njs_module.c \ - src/njs_event.c \ src/njs_extern.c \ src/njs_boolean.c \ src/njs_number.c \ diff --git a/external/njs_fs_module.c b/external/njs_fs_module.c index 819feafb..da9afe67 100644 --- a/external/njs_fs_module.c +++ b/external/njs_fs_module.c @@ -3264,7 +3264,6 @@ njs_fs_result(njs_vm_t *vm, njs_opaque_value_t *result, njs_index_t calltype, const njs_value_t *callback, njs_uint_t nargs, njs_value_t *retval) { njs_int_t ret; - njs_vm_event_t vm_event; njs_function_t *cb; njs_opaque_value_t promise, callbacks[2], arguments[2]; @@ -3290,16 +3289,11 @@ njs_fs_result(njs_vm_t *vm, njs_opaque_value_t *result, njs_index_t calltype, return NJS_ERROR; } - vm_event = njs_vm_add_event(vm, cb, 1, NULL, NULL); - if (njs_slow_path(vm_event == NULL)) { - return NJS_ERROR; - } - njs_value_assign(&arguments[0], &callbacks[njs_value_is_error(njs_value_arg(result))]); njs_value_assign(&arguments[1], result); - ret = njs_vm_post_event(vm, vm_event, njs_value_arg(&arguments), 2); + ret = njs_vm_enqueue_job(vm, cb, njs_value_arg(&arguments), 2); if (njs_slow_path(ret == NJS_ERROR)) { return NJS_ERROR; } @@ -3318,13 +3312,8 @@ njs_fs_result(njs_vm_t *vm, njs_opaque_value_t *result, njs_index_t calltype, njs_value_assign(&arguments[1], result); } - vm_event = njs_vm_add_event(vm, njs_value_function(callback), 1, NULL, - NULL); - if (njs_slow_path(vm_event == NULL)) { - return NJS_ERROR; - } - - ret = njs_vm_post_event(vm, vm_event, njs_value_arg(&arguments), 2); + ret = njs_vm_enqueue_job(vm, njs_value_function(callback), + njs_value_arg(&arguments), 2); if (njs_slow_path(ret == NJS_ERROR)) { return NJS_ERROR; } diff --git a/external/njs_shell.c b/external/njs_shell.c index eaabbb07..f1836df5 100644 --- a/external/njs_shell.c +++ b/external/njs_shell.c @@ -1096,12 +1096,18 @@ njs_process_script(njs_vm_t *vm, void *runtime, const njs_str_t *script) } for ( ;; ) { - ret = njs_vm_run(vm); - if (ret == NJS_ERROR) { - njs_process_output(vm, njs_value_arg(&retval), ret); + for ( ;; ) { + ret = njs_vm_execute_pending_job(vm); + if (ret <= NJS_OK) { + if (ret == NJS_ERROR || njs_vm_unhandled_rejection(vm)) { + njs_process_output(vm, NULL, ret); + + if (!njs_vm_options(vm)->interactive) { + return NJS_ERROR; + } + } - if (!njs_vm_options(vm)->interactive) { - return NJS_ERROR; + break; } } diff --git a/external/njs_webcrypto_module.c b/external/njs_webcrypto_module.c index cf715186..b8adc0b2 100644 --- a/external/njs_webcrypto_module.c +++ b/external/njs_webcrypto_module.c @@ -4771,7 +4771,6 @@ njs_webcrypto_result(njs_vm_t *vm, njs_opaque_value_t *result, njs_int_t rc, { njs_int_t ret; njs_function_t *callback; - njs_vm_event_t vm_event; njs_opaque_value_t promise, arguments[2]; ret = njs_vm_promise_create(vm, njs_value_arg(&promise), @@ -4785,11 +4784,6 @@ njs_webcrypto_result(njs_vm_t *vm, njs_opaque_value_t *result, njs_int_t rc, goto error; } - vm_event = njs_vm_add_event(vm, callback, 1, NULL, NULL); - if (vm_event == NULL) { - goto error; - } - njs_value_assign(&arguments[0], &arguments[(rc != NJS_OK)]); if (rc != NJS_OK) { @@ -4799,7 +4793,7 @@ njs_webcrypto_result(njs_vm_t *vm, njs_opaque_value_t *result, njs_int_t rc, njs_value_assign(&arguments[1], result); } - ret = njs_vm_post_event(vm, vm_event, njs_value_arg(&arguments), 2); + ret = njs_vm_enqueue_job(vm, callback, njs_value_arg(&arguments), 2); if (ret == NJS_ERROR) { goto error; } diff --git a/nginx/ngx_http_js_module.c b/nginx/ngx_http_js_module.c index 3d27f7fb..9ffc58c8 100644 --- a/nginx/ngx_http_js_module.c +++ b/nginx/ngx_http_js_module.c @@ -266,9 +266,7 @@ static ngx_msec_t ngx_http_js_fetch_timeout(njs_vm_t *vm, static size_t ngx_http_js_buffer_size(njs_vm_t *vm, ngx_http_request_t *r); static size_t ngx_http_js_max_response_buffer_size(njs_vm_t *vm, ngx_http_request_t *r); -static void ngx_http_js_handle_vm_event(ngx_http_request_t *r, - njs_vm_event_t vm_event, njs_value_t *args, njs_uint_t nargs); -static void ngx_http_js_event_finalize(ngx_http_request_t *r, njs_int_t rc); +static void ngx_http_js_event_finalize(ngx_http_request_t *r, ngx_int_t rc); static ngx_js_ctx_t *ngx_http_js_ctx(njs_vm_t *vm, ngx_http_request_t *r); static void ngx_http_js_periodic_handler(ngx_event_t *ev); @@ -852,14 +850,13 @@ static uintptr_t ngx_http_js_uptr[] = { (uintptr_t) ngx_http_js_pool, (uintptr_t) ngx_http_js_resolver, (uintptr_t) ngx_http_js_resolver_timeout, - (uintptr_t) ngx_http_js_handle_vm_event, + (uintptr_t) ngx_http_js_event_finalize, (uintptr_t) ngx_http_js_ssl, (uintptr_t) ngx_http_js_ssl_verify, (uintptr_t) ngx_http_js_fetch_timeout, (uintptr_t) ngx_http_js_buffer_size, (uintptr_t) ngx_http_js_max_response_buffer_size, (uintptr_t) 0 /* main_conf ptr */, - (uintptr_t) ngx_http_js_event_finalize, (uintptr_t) ngx_http_js_ctx, }; @@ -950,8 +947,8 @@ ngx_http_js_content_event_handler(ngx_http_request_t *r) ctx->status = NGX_HTTP_INTERNAL_SERVER_ERROR; - rc = ngx_js_call(ctx->vm, &jlcf->content, r->connection->log, - &ctx->request, 1); + rc = ngx_js_name_call(ctx->vm, &jlcf->content, r->connection->log, + &ctx->request, 1); if (rc == NGX_ERROR) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); @@ -1081,8 +1078,8 @@ ngx_http_js_header_filter(ngx_http_request_t *r) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http js header call \"%V\"", &jlcf->header_filter); - rc = ngx_js_call(ctx->vm, &jlcf->header_filter, r->connection->log, - &ctx->request, 1); + rc = ngx_js_name_call(ctx->vm, &jlcf->header_filter, r->connection->log, + &ctx->request, 1); if (rc == NGX_ERROR) { return NGX_ERROR; @@ -1184,8 +1181,8 @@ ngx_http_js_body_filter(ngx_http_request_t *r, ngx_chain_t *in) ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http js body call \"%V\"", &jlcf->body_filter); - rc = ngx_js_call(ctx->vm, &jlcf->body_filter, c->log, &arguments[0], - 3); + rc = ngx_js_name_call(ctx->vm, &jlcf->body_filter, c->log, + &arguments[0], 3); if (rc == NGX_ERROR) { return NGX_ERROR; @@ -1260,8 +1257,8 @@ ngx_http_js_variable_set(ngx_http_request_t *r, ngx_http_variable_value_t *v, pending = ngx_vm_pending(ctx); - rc = ngx_js_invoke(ctx->vm, fname, r->connection->log, &ctx->request, 1, - &ctx->retval); + rc = ngx_js_name_invoke(ctx->vm, fname, r->connection->log, &ctx->request, + 1, &ctx->retval); if (rc == NGX_ERROR) { v->not_found = 1; @@ -3389,7 +3386,7 @@ ngx_http_js_subrequest(ngx_http_request_t *r, njs_str_t *uri_arg, { ngx_int_t flags; ngx_str_t uri, args; - njs_vm_event_t vm_event; + ngx_js_event_t *event; ngx_http_js_ctx_t *ctx; ngx_http_post_subrequest_t *ps; @@ -3404,20 +3401,25 @@ ngx_http_js_subrequest(ngx_http_request_t *r, njs_str_t *uri_arg, return NJS_ERROR; } - vm_event = njs_vm_add_event(ctx->vm, callback, 1, NULL, NULL); - if (vm_event == NULL) { - njs_vm_error(ctx->vm, "internal error"); + event = njs_mp_zalloc(njs_vm_memory_pool(ctx->vm), + sizeof(ngx_js_event_t)); + if (njs_slow_path(event == NULL)) { + njs_vm_memory_error(ctx->vm); return NJS_ERROR; } + event->vm = ctx->vm; + event->function = callback; + event->fd = ctx->event_id++; + ps->handler = ngx_http_js_subrequest_done; - ps->data = vm_event; + ps->data = event; flags |= NGX_HTTP_SUBREQUEST_IN_MEMORY; } else { ps = NULL; - vm_event = NULL; + event = NULL; } uri.len = uri_arg->length; @@ -3429,14 +3431,14 @@ ngx_http_js_subrequest(ngx_http_request_t *r, njs_str_t *uri_arg, if (ngx_http_subrequest(r, &uri, args.len ? &args : NULL, sr, ps, flags) != NGX_OK) { - if (vm_event != NULL) { - njs_vm_del_event(ctx->vm, vm_event); - } - njs_vm_error(ctx->vm, "subrequest creation failed"); return NJS_ERROR; } + if (event != NULL) { + ngx_js_add_event(ctx, event); + } + return NJS_OK; } @@ -3444,7 +3446,7 @@ ngx_http_js_subrequest(ngx_http_request_t *r, njs_str_t *uri_arg, static ngx_int_t ngx_http_js_subrequest_done(ngx_http_request_t *r, void *data, ngx_int_t rc) { - njs_vm_event_t vm_event = data; + ngx_js_event_t *event = data; njs_int_t ret; ngx_http_js_ctx_t *ctx; @@ -3493,7 +3495,11 @@ ngx_http_js_subrequest_done(ngx_http_request_t *r, void *data, ngx_int_t rc) return NGX_ERROR; } - ngx_http_js_handle_vm_event(r->parent, vm_event, njs_value_arg(&reply), 1); + rc = ngx_js_call(ctx->vm, event->function, njs_value_arg(&reply), 1); + + ngx_js_del_event(ctx, event); + + ngx_http_js_event_finalize(r->parent, rc); return NGX_OK; } @@ -4248,8 +4254,8 @@ ngx_http_js_periodic_handler(ngx_event_t *ev) r->count++; - rc = ngx_js_invoke(ctx->vm, &periodic->method, &periodic->log, - &ctx->request, 1, &ctx->retval); + rc = ngx_js_name_invoke(ctx->vm, &periodic->method, &periodic->log, + &ctx->request, 1, &ctx->retval); if (rc == NGX_AGAIN) { rc = NGX_OK; @@ -4440,41 +4446,12 @@ ngx_http_js_max_response_buffer_size(njs_vm_t *vm, ngx_http_request_t *r) static void -ngx_http_js_handle_vm_event(ngx_http_request_t *r, njs_vm_event_t vm_event, - njs_value_t *args, njs_uint_t nargs) -{ - njs_int_t rc; - ngx_str_t exception; - ngx_http_js_ctx_t *ctx; - - ctx = ngx_http_get_module_ctx(r, ngx_http_js_module); - - njs_vm_post_event(ctx->vm, vm_event, args, nargs); - - rc = njs_vm_run(ctx->vm); - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http js post event handler rc: %i event: %p", - (ngx_int_t) rc, vm_event); - - if (rc == NJS_ERROR) { - ngx_js_exception(ctx->vm, &exception); - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "js exception: %V", &exception); - } - - ngx_http_js_event_finalize(r, rc); -} - - -static void -ngx_http_js_event_finalize(ngx_http_request_t *r, njs_int_t rc) +ngx_http_js_event_finalize(ngx_http_request_t *r, ngx_int_t rc) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http js event finalize rc: %i", (ngx_int_t) rc); + "http js event finalize rc: %i", rc); - if (rc == NJS_ERROR) { + if (rc == NGX_ERROR) { if (r->health_check) { ngx_http_js_periodic_finalize(r, NGX_ERROR); return; @@ -4484,7 +4461,7 @@ ngx_http_js_event_finalize(ngx_http_request_t *r, njs_int_t rc) return; } - if (rc == NJS_OK) { + if (rc == NGX_OK) { ngx_http_post_request(r, NULL); } diff --git a/nginx/ngx_js.c b/nginx/ngx_js.c index 2b11c4bf..c28995ed 100644 --- a/nginx/ngx_js.c +++ b/nginx/ngx_js.c @@ -334,17 +334,57 @@ static njs_int_t ngx_js_console_proto_id; ngx_int_t -ngx_js_call(njs_vm_t *vm, ngx_str_t *fname, ngx_log_t *log, +ngx_js_call(njs_vm_t *vm, njs_function_t *func, njs_value_t *args, + njs_uint_t nargs) +{ + njs_int_t ret; + ngx_str_t exception; + ngx_connection_t *c; + + ret = njs_vm_call(vm, func, args, nargs); + if (ret == NJS_ERROR) { + ngx_js_exception(vm, &exception); + + c = ngx_external_connection(vm, njs_vm_external_ptr(vm)); + + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "js exception: %V", &exception); + return NGX_ERROR; + } + + for ( ;; ) { + ret = njs_vm_execute_pending_job(vm); + if (ret <= NJS_OK) { + c = ngx_external_connection(vm, njs_vm_external_ptr(vm)); + + if (ret == NJS_ERROR || njs_vm_unhandled_rejection(vm)) { + ngx_js_exception(vm, &exception); + + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "js job exception: %V", &exception); + return NGX_ERROR; + } + + break; + } + } + + return NGX_OK; +} + + +ngx_int_t +ngx_js_name_call(njs_vm_t *vm, ngx_str_t *fname, ngx_log_t *log, njs_opaque_value_t *args, njs_uint_t nargs) { njs_opaque_value_t unused; - return ngx_js_invoke(vm, fname, log, args, nargs, &unused); + return ngx_js_name_invoke(vm, fname, log, args, nargs, &unused); } ngx_int_t -ngx_js_invoke(njs_vm_t *vm, ngx_str_t *fname, ngx_log_t *log, +ngx_js_name_invoke(njs_vm_t *vm, ngx_str_t *fname, ngx_log_t *log, njs_opaque_value_t *args, njs_uint_t nargs, njs_opaque_value_t *retval) { njs_int_t ret; @@ -374,18 +414,19 @@ ngx_js_invoke(njs_vm_t *vm, ngx_str_t *fname, ngx_log_t *log, return NGX_ERROR; } - ret = njs_vm_run(vm); - if (ret == NJS_ERROR) { - ngx_js_exception(vm, &exception); - - ngx_log_error(NGX_LOG_ERR, log, 0, - "js exception: %V", &exception); + for ( ;; ) { + ret = njs_vm_execute_pending_job(vm); + if (ret <= NJS_OK) { + if (ret == NJS_ERROR || njs_vm_unhandled_rejection(vm)) { + ngx_js_exception(vm, &exception); - return NGX_ERROR; - } + ngx_log_error(NGX_LOG_ERR, log, 0, + "js job exception: %V", &exception); + return NGX_ERROR; + } - if (ret == NJS_AGAIN) { - return NGX_AGAIN; + break; + } } ctx = ngx_external_ctx(vm, njs_vm_external_ptr(vm)); @@ -966,34 +1007,21 @@ not_found: static void ngx_js_timer_handler(ngx_event_t *ev) { - njs_vm_t *vm; - njs_int_t ret; - ngx_str_t exception; - ngx_js_ctx_t *ctx; - ngx_js_event_t *event; - ngx_connection_t *c; - njs_external_ptr_t external; + njs_vm_t *vm; + ngx_int_t rc; + ngx_js_ctx_t *ctx; + ngx_js_event_t *event; event = (ngx_js_event_t *) ((u_char *) ev - offsetof(ngx_js_event_t, ev)); vm = event->vm; - ret = njs_vm_call(vm, event->function, event->args, event->nargs); + rc = ngx_js_call(vm, event->function, event->args, event->nargs); - external = njs_vm_external_ptr(vm); - ctx = ngx_external_ctx(vm, external); - njs_rbtree_delete(&ctx->waiting_events, &event->node); - - if (ret == NJS_ERROR) { - ngx_js_exception(vm, &exception); - - c = ngx_external_connection(vm, njs_vm_external_ptr(vm)); - - ngx_log_error(NGX_LOG_ERR, c->log, 0, - "js exception: %V", &exception); - } + ctx = ngx_external_ctx(vm, njs_vm_external_ptr(vm)); + ngx_js_del_event(ctx, event); - ngx_external_event_finalize(vm)(external, ret); + ngx_external_event_finalize(vm)(njs_vm_external_ptr(vm), rc); } @@ -1065,7 +1093,7 @@ njs_set_timer(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, sizeof(njs_opaque_value_t) * event->nargs); } - njs_rbtree_insert(&ctx->waiting_events, &event->node); + ngx_js_add_event(ctx, event); ngx_add_timer(&event->ev, delay); @@ -1113,14 +1141,9 @@ njs_clear_timeout(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, return NJS_ERROR; } - event = (ngx_js_event_t *) ((u_char *) rb - - offsetof(ngx_js_event_t, node)); - - if (event->ev.timer_set) { - ngx_del_timer(&event->ev); - } + event = (ngx_js_event_t *) ((u_char *) rb - offsetof(ngx_js_event_t, node)); - njs_rbtree_delete(&ctx->waiting_events, (njs_rbtree_part_t *) rb); + ngx_js_del_event(ctx, event); njs_value_undefined_set(retval); diff --git a/nginx/ngx_js.h b/nginx/ngx_js.h index 418fccb1..e0e3adac 100644 --- a/nginx/ngx_js.h +++ b/nginx/ngx_js.h @@ -39,9 +39,7 @@ typedef struct ngx_js_ctx_s ngx_js_ctx_t; typedef ngx_pool_t *(*ngx_external_pool_pt)(njs_vm_t *vm, njs_external_ptr_t e); -typedef void (*ngx_js_event_handler_pt)(njs_external_ptr_t e, - njs_vm_event_t vm_event, njs_value_t *args, njs_uint_t nargs); -typedef void (*ngx_js_event_finalize_pt)(njs_external_ptr_t e, njs_int_t rc); +typedef void (*ngx_js_event_finalize_pt)(njs_external_ptr_t e, ngx_int_t rc); typedef ngx_resolver_t *(*ngx_external_resolver_pt)(njs_vm_t *vm, njs_external_ptr_t e); typedef ngx_msec_t (*ngx_external_timeout_pt)(njs_vm_t *vm, @@ -73,6 +71,7 @@ struct ngx_js_event_s { void (*destructor)(njs_external_ptr_t external, ngx_js_event_t *event); ngx_event_t ev; + void *data; }; @@ -116,6 +115,20 @@ struct ngx_js_event_s { ngx_socket_t event_id +#define ngx_js_add_event(ctx, event) \ + njs_rbtree_insert(&(ctx)->waiting_events, &(event)->node) + + +#define ngx_js_del_event(ctx, event) \ + do { \ + if ((event)->destructor) { \ + (event)->destructor(njs_vm_external_ptr((event)->vm), event); \ + } \ + \ + njs_rbtree_delete(&(ctx)->waiting_events, &(event)->node); \ + } while (0) + + typedef struct { NGX_JS_COMMON_MAIN_CONF; } ngx_js_main_conf_t; @@ -139,8 +152,8 @@ struct ngx_js_ctx_s { ((ngx_external_resolver_pt) njs_vm_meta(vm, 2))(vm, e) #define ngx_external_resolver_timeout(vm, e) \ ((ngx_external_timeout_pt) njs_vm_meta(vm, 3))(vm, e) -#define ngx_external_event_handler(vm, e) \ - ((ngx_js_event_handler_pt) njs_vm_meta(vm, 4)) +#define ngx_external_event_finalize(vm) \ + ((ngx_js_event_finalize_pt) njs_vm_meta(vm, 4)) #define ngx_external_ssl(vm, e) \ ((ngx_external_ssl_pt) njs_vm_meta(vm, 5))(vm, e) #define ngx_external_ssl_verify(vm, e) \ @@ -154,10 +167,8 @@ struct ngx_js_ctx_s { #define NGX_JS_MAIN_CONF_INDEX 10 #define ngx_main_conf(vm) \ ((ngx_js_main_conf_t *) njs_vm_meta(vm, NGX_JS_MAIN_CONF_INDEX)) -#define ngx_external_event_finalize(vm) \ - ((ngx_js_event_finalize_pt) njs_vm_meta(vm, 11)) #define ngx_external_ctx(vm, e) \ - ((ngx_js_external_ctx_pt) njs_vm_meta(vm, 12))(vm, e) + ((ngx_js_external_ctx_pt) njs_vm_meta(vm, 11))(vm, e) #define ngx_js_prop(vm, type, value, start, len) \ @@ -171,9 +182,11 @@ struct ngx_js_ctx_s { void ngx_js_ctx_init(ngx_js_ctx_t *ctx); void ngx_js_ctx_destroy(ngx_js_ctx_t *ctx); -ngx_int_t ngx_js_call(njs_vm_t *vm, ngx_str_t *fname, ngx_log_t *log, +ngx_int_t ngx_js_call(njs_vm_t *vm, njs_function_t *func, njs_value_t *args, + njs_uint_t nargs); +ngx_int_t ngx_js_name_call(njs_vm_t *vm, ngx_str_t *fname, ngx_log_t *log, njs_opaque_value_t *args, njs_uint_t nargs); -ngx_int_t ngx_js_invoke(njs_vm_t *vm, ngx_str_t *fname, ngx_log_t *log, +ngx_int_t ngx_js_name_invoke(njs_vm_t *vm, ngx_str_t *fname, ngx_log_t *log, njs_opaque_value_t *args, njs_uint_t nargs, njs_opaque_value_t *retval); ngx_int_t ngx_js_exception(njs_vm_t *vm, ngx_str_t *s); diff --git a/nginx/ngx_js_fetch.c b/nginx/ngx_js_fetch.c index c3d15aa0..6fb723d4 100644 --- a/nginx/ngx_js_fetch.c +++ b/nginx/ngx_js_fetch.c @@ -116,9 +116,7 @@ struct ngx_js_http_s { ngx_pool_t *pool; njs_vm_t *vm; - njs_external_ptr_t external; - njs_vm_event_t vm_event; - ngx_js_event_handler_pt event_handler; + ngx_js_event_t *event; ngx_resolver_ctx_t *ctx; ngx_addr_t addr; @@ -177,7 +175,7 @@ static njs_int_t ngx_js_headers_fill(njs_vm_t *vm, ngx_js_headers_t *headers, static ngx_js_http_t *ngx_js_http_alloc(njs_vm_t *vm, ngx_pool_t *pool, ngx_log_t *log); static void njs_js_http_destructor(njs_external_ptr_t external, - njs_host_event_t host); + ngx_js_event_t *event); static void ngx_js_resolve_handler(ngx_resolver_ctx_t *ctx); static njs_int_t ngx_js_fetch_promissified_result(njs_vm_t *vm, njs_value_t *result, njs_int_t rc, njs_value_t *retval); @@ -695,9 +693,6 @@ ngx_js_ext_fetch(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, return NJS_ERROR; } - http->external = external; - http->event_handler = ngx_external_event_handler(vm, external); - ret = ngx_js_request_constructor(vm, &request, &u, external, args, nargs); if (ret != NJS_OK) { goto fail; @@ -1273,8 +1268,9 @@ static ngx_js_http_t * ngx_js_http_alloc(njs_vm_t *vm, ngx_pool_t *pool, ngx_log_t *log) { njs_int_t ret; + ngx_js_ctx_t *ctx; ngx_js_http_t *http; - njs_vm_event_t vm_event; + ngx_js_event_t *event; njs_function_t *callback; http = ngx_pcalloc(pool, sizeof(ngx_js_http_t)); @@ -1301,12 +1297,22 @@ ngx_js_http_alloc(njs_vm_t *vm, ngx_pool_t *pool, ngx_log_t *log) goto failed; } - vm_event = njs_vm_add_event(vm, callback, 1, http, njs_js_http_destructor); - if (vm_event == NULL) { + event = njs_mp_zalloc(njs_vm_memory_pool(vm), sizeof(ngx_js_event_t)); + if (njs_slow_path(event == NULL)) { goto failed; } - http->vm_event = vm_event; + ctx = ngx_external_ctx(vm, njs_vm_external_ptr(vm)); + + event->vm = vm; + event->function = callback; + event->destructor = njs_js_http_destructor; + event->fd = ctx->event_id++; + event->data = http; + + ngx_js_add_event(ctx, event); + + http->event = event; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, "js fetch alloc:%p", http); @@ -1428,11 +1434,11 @@ ngx_js_http_close_connection(ngx_connection_t *c) static void -njs_js_http_destructor(njs_external_ptr_t external, njs_host_event_t host) +njs_js_http_destructor(njs_external_ptr_t external, ngx_js_event_t *event) { ngx_js_http_t *http; - http = host; + http = event->data; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, http->log, 0, "js fetch destructor:%p", http); @@ -1455,7 +1461,6 @@ ngx_js_fetch_promissified_result(njs_vm_t *vm, njs_value_t *result, { njs_int_t ret; njs_function_t *callback; - njs_vm_event_t vm_event; njs_opaque_value_t promise, arguments[2]; ret = njs_vm_promise_create(vm, njs_value_arg(&promise), @@ -1469,11 +1474,6 @@ ngx_js_fetch_promissified_result(njs_vm_t *vm, njs_value_t *result, goto error; } - vm_event = njs_vm_add_event(vm, callback, 1, NULL, NULL); - if (vm_event == NULL) { - goto error; - } - njs_value_assign(&arguments[0], &arguments[(rc != NJS_OK)]); if (rc != NJS_OK) { @@ -1483,7 +1483,7 @@ ngx_js_fetch_promissified_result(njs_vm_t *vm, njs_value_t *result, njs_value_assign(&arguments[1], result); } - ret = njs_vm_post_event(vm, vm_event, njs_value_arg(&arguments), 2); + ret = njs_vm_enqueue_job(vm, callback, njs_value_arg(&arguments), 2); if (ret == NJS_ERROR) { goto error; } @@ -1504,7 +1504,10 @@ static void ngx_js_http_fetch_done(ngx_js_http_t *http, njs_opaque_value_t *retval, njs_int_t rc) { - njs_opaque_value_t arguments[2], *action; + njs_vm_t *vm; + ngx_js_ctx_t *ctx; + ngx_js_event_t *event; + njs_opaque_value_t arguments[2], *action; ngx_log_debug2(NGX_LOG_DEBUG_EVENT, http->log, 0, "js fetch done http:%p rc:%i", http, (ngx_int_t) rc); @@ -1514,12 +1517,20 @@ ngx_js_http_fetch_done(ngx_js_http_t *http, njs_opaque_value_t *retval, http->peer.connection = NULL; } - if (http->vm_event != NULL) { + if (http->event != NULL) { action = &http->promise_callbacks[(rc != NJS_OK)]; njs_value_assign(&arguments[0], action); njs_value_assign(&arguments[1], retval); - http->event_handler(http->external, http->vm_event, - njs_value_arg(&arguments), 2); + + vm = http->vm; + event = http->event; + + rc = ngx_js_call(vm, event->function, njs_value_arg(&arguments), 2); + + ctx = ngx_external_ctx(vm, njs_vm_external_ptr(vm)); + ngx_js_del_event(ctx, event); + + ngx_external_event_finalize(vm)(njs_vm_external_ptr(vm), rc); } } diff --git a/nginx/ngx_stream_js_module.c b/nginx/ngx_stream_js_module.c index bb19f811..b6a51eaa 100644 --- a/nginx/ngx_stream_js_module.c +++ b/nginx/ngx_stream_js_module.c @@ -22,7 +22,7 @@ typedef struct { typedef struct { - njs_vm_event_t ev; + njs_function_t *function; ngx_uint_t data_type; } ngx_stream_js_ev_t; @@ -67,6 +67,12 @@ typedef struct { } ngx_stream_js_ctx_t; +#define ngx_stream_pending(ctx) \ + (ngx_vm_pending(ctx) \ + || (ctx)->events[NGX_JS_EVENT_UPLOAD].function != NULL \ + || (ctx)->events[NGX_JS_EVENT_DOWNLOAD].function != NULL) + + static ngx_int_t ngx_stream_js_access_handler(ngx_stream_session_t *s); static ngx_int_t ngx_stream_js_preread_handler(ngx_stream_session_t *s); static ngx_int_t ngx_stream_js_phase_handler(ngx_stream_session_t *s, @@ -86,7 +92,7 @@ static void ngx_stream_js_cleanup(void *data); static njs_int_t ngx_stream_js_run_event(ngx_stream_session_t *s, ngx_stream_js_ctx_t *ctx, ngx_stream_js_ev_t *event, ngx_uint_t from_upstream); -static njs_vm_event_t *ngx_stream_js_event(ngx_stream_session_t *s, +static njs_function_t **ngx_stream_js_event(ngx_stream_session_t *s, njs_str_t *event); static njs_int_t ngx_stream_js_ext_get_remote_address(njs_vm_t *vm, @@ -123,9 +129,7 @@ static ngx_msec_t ngx_stream_js_fetch_timeout(njs_vm_t *vm, static size_t ngx_stream_js_buffer_size(njs_vm_t *vm, ngx_stream_session_t *s); static size_t ngx_stream_js_max_response_buffer_size(njs_vm_t *vm, ngx_stream_session_t *s); -static void ngx_stream_js_handle_event(ngx_stream_session_t *s, - njs_vm_event_t vm_event, njs_value_t *args, njs_uint_t nargs); -static void ngx_stream_js_event_finalize(ngx_stream_session_t *s, njs_int_t rc); +static void ngx_stream_js_event_finalize(ngx_stream_session_t *s, ngx_int_t rc); static ngx_js_ctx_t *ngx_stream_js_ctx(njs_vm_t *vm, ngx_stream_session_t *s); static void ngx_stream_js_periodic_handler(ngx_event_t *ev); @@ -615,14 +619,13 @@ static uintptr_t ngx_stream_js_uptr[] = { (uintptr_t) ngx_stream_js_pool, (uintptr_t) ngx_stream_js_resolver, (uintptr_t) ngx_stream_js_resolver_timeout, - (uintptr_t) ngx_stream_js_handle_event, + (uintptr_t) ngx_stream_js_event_finalize, (uintptr_t) ngx_stream_js_ssl, (uintptr_t) ngx_stream_js_ssl_verify, (uintptr_t) ngx_stream_js_fetch_timeout, (uintptr_t) ngx_stream_js_buffer_size, (uintptr_t) ngx_stream_js_max_response_buffer_size, (uintptr_t) 0 /* main_conf ptr */, - (uintptr_t) ngx_stream_js_event_finalize, (uintptr_t) ngx_stream_js_ctx, }; @@ -734,7 +737,7 @@ ngx_stream_js_phase_handler(ngx_stream_session_t *s, ngx_str_t *name) ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "stream js phase call \"%V\"", name); - rc = ngx_js_call(ctx->vm, name, c->log, &ctx->args[0], 1); + rc = ngx_js_name_call(ctx->vm, name, c->log, &ctx->args[0], 1); if (rc == NGX_ERROR) { return rc; @@ -751,9 +754,9 @@ ngx_stream_js_phase_handler(ngx_stream_session_t *s, ngx_str_t *name) return NGX_ERROR; } - if (ngx_vm_pending(ctx)) { + if (ngx_stream_pending(ctx)) { ctx->in_progress = 1; - rc = ctx->events[NGX_JS_EVENT_UPLOAD].ev ? NGX_AGAIN : NGX_DONE; + rc = ctx->events[NGX_JS_EVENT_UPLOAD].function ? NGX_AGAIN : NGX_DONE; } else { ctx->in_progress = 0; @@ -811,7 +814,7 @@ ngx_stream_js_body_filter(ngx_stream_session_t *s, ngx_chain_t *in, ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0, "stream js filter call \"%V\"" , &jscf->filter); - rc = ngx_js_call(ctx->vm, &jscf->filter, c->log, &ctx->args[0], 1); + rc = ngx_js_name_call(ctx->vm, &jscf->filter, c->log, &ctx->args[0], 1); if (rc == NGX_ERROR) { return rc; @@ -827,7 +830,7 @@ ngx_stream_js_body_filter(ngx_stream_session_t *s, ngx_chain_t *in, event = ngx_stream_event(from_upstream); - if (event->ev != NULL) { + if (event->function != NULL) { ret = ngx_stream_js_run_event(s, ctx, event, from_upstream); if (ret != NJS_OK) { ngx_js_exception(ctx->vm, &exception); @@ -922,10 +925,10 @@ ngx_stream_js_variable_set(ngx_stream_session_t *s, ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module); - pending = ngx_vm_pending(ctx); + pending = ngx_stream_pending(ctx); - rc = ngx_js_invoke(ctx->vm, fname, s->connection->log, &ctx->args[0], 1, - &ctx->retval); + rc = ngx_js_name_invoke(ctx->vm, fname, s->connection->log, &ctx->args[0], + 1, &ctx->retval); if (rc == NGX_ERROR) { v->not_found = 1; @@ -1078,9 +1081,8 @@ ngx_stream_js_drop_events(ngx_stream_js_ctx_t *ctx) ngx_uint_t i; for (i = 0; i < NGX_JS_EVENT_MAX; i++) { - if (ctx->events[i].ev != NULL) { - njs_vm_del_event(ctx->vm, ctx->events[i].ev); - ctx->events[i].ev = NULL; + if (ctx->events[i].function != NULL) { + ctx->events[i].function = NULL; } } } @@ -1119,7 +1121,7 @@ ngx_stream_js_run_event(ngx_stream_session_t *s, ngx_stream_js_ctx_t *ctx, uintptr_t flags; ngx_connection_t *c; - if (event->ev == NULL) { + if (event->function == NULL) { return NJS_OK; } @@ -1152,18 +1154,12 @@ ngx_stream_js_run_event(ngx_stream_session_t *s, ngx_stream_js_ctx_t *ctx, return NGX_ERROR; } - njs_vm_post_event(ctx->vm, event->ev, njs_value_arg(&ctx->args[1]), 2); - - ret = njs_vm_run(ctx->vm); - if (ret == NJS_ERROR) { - return ret; - } - - return NJS_OK; + return ngx_js_call(ctx->vm, event->function, njs_value_arg(&ctx->args[1]), + 2); } -static njs_vm_event_t * +static njs_function_t ** ngx_stream_js_event(ngx_stream_session_t *s, njs_str_t *event) { ngx_uint_t i, n, type; @@ -1231,7 +1227,7 @@ ngx_stream_js_event(ngx_stream_session_t *s, njs_str_t *event) } } - return &ctx->events[events[i].id].ev; + return &ctx->events[events[i].id].function; } @@ -1317,10 +1313,10 @@ static njs_int_t ngx_stream_js_ext_on(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) { - njs_str_t name; - njs_value_t *callback; - njs_vm_event_t *event; - ngx_stream_session_t *s; + njs_str_t name; + njs_value_t *callback; + njs_function_t **cb; + ngx_stream_session_t *s; s = njs_vm_external(vm, ngx_stream_js_session_proto_id, njs_argument(args, 0)); @@ -1340,21 +1336,17 @@ ngx_stream_js_ext_on(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, return NJS_ERROR; } - event = ngx_stream_js_event(s, &name); - if (event == NULL) { + cb = ngx_stream_js_event(s, &name); + if (cb == NULL) { return NJS_ERROR; } - if (*event != NULL) { + if (*cb != NULL) { njs_vm_error(vm, "event handler \"%V\" is already set", &name); return NJS_ERROR; } - *event = njs_vm_add_event(vm, njs_value_function(callback), 0, NULL, NULL); - if (*event == NULL) { - njs_vm_error(vm, "internal error"); - return NJS_ERROR; - } + *cb = njs_value_function(callback); njs_value_undefined_set(retval); @@ -1366,9 +1358,9 @@ static njs_int_t ngx_stream_js_ext_off(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, njs_index_t unused, njs_value_t *retval) { - njs_str_t name; - njs_vm_event_t *event; - ngx_stream_session_t *s; + njs_str_t name; + njs_function_t **callback; + ngx_stream_session_t *s; s = njs_vm_external(vm, ngx_stream_js_session_proto_id, njs_argument(args, 0)); @@ -1382,14 +1374,12 @@ ngx_stream_js_ext_off(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, return NJS_ERROR; } - event = ngx_stream_js_event(s, &name); - if (event == NULL) { + callback = ngx_stream_js_event(s, &name); + if (callback == NULL) { return NJS_ERROR; } - njs_vm_del_event(vm, *event); - - *event = NULL; + *callback = NULL; njs_value_undefined_set(retval); @@ -1726,41 +1716,12 @@ ngx_stream_js_max_response_buffer_size(njs_vm_t *vm, ngx_stream_session_t *s) static void -ngx_stream_js_handle_event(ngx_stream_session_t *s, njs_vm_event_t vm_event, - njs_value_t *args, njs_uint_t nargs) -{ - njs_int_t rc; - ngx_str_t exception; - ngx_stream_js_ctx_t *ctx; - - ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module); - - njs_vm_post_event(ctx->vm, vm_event, args, nargs); - - rc = njs_vm_run(ctx->vm); - - ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, - "stream js post event handler rc: %i event: %p", - (ngx_int_t) rc, vm_event); - - if (rc == NJS_ERROR) { - ngx_js_exception(ctx->vm, &exception); - - ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, - "js exception: %V", &exception); - } - - ngx_stream_js_event_finalize(s, rc); -} - - -static void -ngx_stream_js_event_finalize(ngx_stream_session_t *s, njs_int_t rc) +ngx_stream_js_event_finalize(ngx_stream_session_t *s, ngx_int_t rc) { ngx_log_debug1(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, - "http js event finalize rc: %i", (ngx_int_t) rc); + "http js event finalize rc: %i", rc); - if (rc == NJS_ERROR) { + if (rc == NGX_ERROR) { if (s->health_check) { ngx_stream_js_periodic_finalize(s, NGX_ERROR); return; @@ -1770,7 +1731,7 @@ ngx_stream_js_event_finalize(ngx_stream_session_t *s, njs_int_t rc) return; } - if (rc == NJS_OK) { + if (rc == NGX_OK) { ngx_post_event(s->connection->read, &ngx_posted_events); } } @@ -1930,8 +1891,8 @@ ngx_stream_js_periodic_handler(ngx_event_t *ev) s->received++; - rc = ngx_js_invoke(ctx->vm, &periodic->method, &periodic->log, - &ctx->args[0], 1, &ctx->retval); + rc = ngx_js_name_invoke(ctx->vm, &periodic->method, &periodic->log, + &ctx->args[0], 1, &ctx->retval); if (rc == NGX_AGAIN) { rc = NGX_OK; diff --git a/src/njs.h b/src/njs.h index 319924c8..ba610a7a 100644 --- a/src/njs.h +++ b/src/njs.h @@ -205,34 +205,8 @@ struct njs_external_s { }; -/* - * NJS and event loops. - * - * njs_vm_ops_t callbacks are used to interact with the event loop environment. - * - * Functions get an external object as the first argument. The external - * object is provided as the third argument to njs_vm_clone(). - * - * The callbacks are expected to return to the VM the unique id of an - * underlying event. This id will be passed as the second argument to - * njs_event_destructor() at the moment the VM wants to destroy it. - * - * When an underlying events fires njs_vm_post_event() should be invoked with - * the value provided as vm_event. - * - * The events posted by njs_vm_post_event() are processed as soon as - * njs_vm_run() is invoked. njs_vm_run() returns NJS_AGAIN until pending events - * are present. - */ - -typedef void * njs_vm_event_t; -typedef void * njs_host_event_t; typedef void * njs_external_ptr_t; -typedef njs_host_event_t (*njs_set_timer_t)(njs_external_ptr_t external, - uint64_t delay, njs_vm_event_t vm_event); -typedef void (*njs_event_destructor_t)(njs_external_ptr_t external, - njs_host_event_t event); typedef njs_mod_t *(*njs_module_loader_t)(njs_vm_t *vm, njs_external_ptr_t external, njs_str_t *name); typedef void (*njs_logger_t)(njs_vm_t *vm, njs_external_ptr_t external, @@ -342,25 +316,16 @@ NJS_EXPORT njs_mod_t *njs_vm_compile_module(njs_vm_t *vm, njs_str_t *name, u_char **start, u_char *end); NJS_EXPORT njs_vm_t *njs_vm_clone(njs_vm_t *vm, njs_external_ptr_t external); -NJS_EXPORT njs_vm_event_t njs_vm_add_event(njs_vm_t *vm, - njs_function_t *function, njs_uint_t once, njs_host_event_t host_ev, - njs_event_destructor_t destructor); -NJS_EXPORT void njs_vm_del_event(njs_vm_t *vm, njs_vm_event_t vm_event); -NJS_EXPORT njs_int_t njs_vm_post_event(njs_vm_t *vm, njs_vm_event_t vm_event, +NJS_EXPORT njs_int_t njs_vm_enqueue_job(njs_vm_t *vm, njs_function_t *function, const njs_value_t *args, njs_uint_t nargs); - /* - * Returns 1 if async events are present. - */ -NJS_EXPORT njs_int_t njs_vm_waiting(njs_vm_t *vm); - -/* - * Returns 1 if posted events are ready to be executed. + * Executes a single pending job. + * 1 successful run. + * NJS_OK pending job was not found. + * NJS_ERROR some exception or internal error happens. */ -NJS_EXPORT njs_int_t njs_vm_posted(njs_vm_t *vm); - -#define njs_vm_pending(vm) (njs_vm_waiting(vm) || njs_vm_posted(vm)) - +NJS_EXPORT njs_int_t njs_vm_execute_pending_job(njs_vm_t *vm); +NJS_EXPORT njs_int_t njs_vm_pending(njs_vm_t *vm); NJS_EXPORT njs_int_t njs_vm_unhandled_rejection(njs_vm_t *vm); NJS_EXPORT void *njs_vm_completions(njs_vm_t *vm, njs_str_t *expression); @@ -377,16 +342,6 @@ NJS_EXPORT njs_int_t njs_vm_call(njs_vm_t *vm, njs_function_t *function, NJS_EXPORT njs_int_t njs_vm_invoke(njs_vm_t *vm, njs_function_t *function, const njs_value_t *args, njs_uint_t nargs, njs_value_t *retval); -/* - * Runs posted events. - * NJS_OK successfully processed all posted events, no more events. - * NJS_AGAIN successfully processed all events, some posted events are - * still pending. - * NJS_ERROR some exception or internal error happens. - * njs_vm_exception_get(vm) can be used to get the exception value. - */ -NJS_EXPORT njs_int_t njs_vm_run(njs_vm_t *vm); - /* * Runs the global code. * NJS_OK successful run. diff --git a/src/njs_event.c b/src/njs_event.c deleted file mode 100644 index 56c831fc..00000000 --- a/src/njs_event.c +++ /dev/null @@ -1,95 +0,0 @@ - -/* - * Copyright (C) Dmitry Volyntsev - * Copyright (C) NGINX, Inc. - */ - - -#include - - -static njs_int_t njs_event_hash_test(njs_lvlhsh_query_t *lhq, void *data); - - -const njs_lvlhsh_proto_t njs_event_hash_proto - njs_aligned(64) = -{ - NJS_LVLHSH_DEFAULT, - njs_event_hash_test, - njs_lvlhsh_alloc, - njs_lvlhsh_free, -}; - - -static njs_int_t -njs_event_hash_test(njs_lvlhsh_query_t *lhq, void *data) -{ - njs_str_t id; - njs_event_t *event; - - event = data; - - njs_string_get(&event->id, &id); - - if (njs_strstr_eq(&lhq->key, &id)) { - return NJS_OK; - } - - return NJS_DECLINED; -} - - -njs_int_t -njs_add_event(njs_vm_t *vm, njs_event_t *event) -{ - njs_int_t ret; - njs_lvlhsh_query_t lhq; - - njs_uint32_to_string(&event->id, vm->event_id++); - - njs_string_get(&event->id, &lhq.key); - lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length); - lhq.value = event; - lhq.proto = &njs_event_hash_proto; - lhq.pool = vm->mem_pool; - - ret = njs_lvlhsh_insert(&vm->events_hash, &lhq); - if (njs_slow_path(ret != NJS_OK)) { - njs_internal_error(vm, "Failed to add event with id: %s", - njs_string_short_start(&event->id)); - - njs_del_event(vm, event, NJS_EVENT_RELEASE | NJS_EVENT_DELETE); - return NJS_ERROR; - } - - return NJS_OK; -} - - -void -njs_del_event(njs_vm_t *vm, njs_event_t *ev, njs_uint_t action) -{ - njs_lvlhsh_query_t lhq; - - if (action & NJS_EVENT_RELEASE) { - if (ev->destructor != NULL && ev->host_event != NULL) { - ev->destructor(vm->external, ev->host_event); - } - - ev->host_event = NULL; - } - - if (action & NJS_EVENT_DELETE) { - njs_string_get(&ev->id, &lhq.key); - lhq.key_hash = njs_djb_hash(lhq.key.start, lhq.key.length); - lhq.proto = &njs_event_hash_proto; - lhq.pool = vm->mem_pool; - - if (ev->posted) { - ev->posted = 0; - njs_queue_remove(&ev->link); - } - - (void) njs_lvlhsh_delete(&vm->events_hash, &lhq); - } -} diff --git a/src/njs_event.h b/src/njs_event.h index 9ca3ac08..4870228f 100644 --- a/src/njs_event.h +++ b/src/njs_event.h @@ -8,37 +8,13 @@ #define _NJS_EVENT_H_INCLUDED_ -#define NJS_EVENT_RELEASE 1 -#define NJS_EVENT_DELETE 2 - - -#define njs_waiting_events(vm) (!njs_lvlhsh_is_empty(&(vm)->events_hash)) - -#define njs_posted_events(vm) (!njs_queue_is_empty(&(vm)->posted_events)) - -#define njs_promise_events(vm) (!njs_queue_is_empty(&(vm)->promise_events)) - - typedef struct { njs_function_t *function; njs_value_t *args; njs_uint_t nargs; - njs_host_event_t host_event; - njs_event_destructor_t destructor; - njs_value_t id; njs_queue_link_t link; - - unsigned posted:1; - unsigned once:1; } njs_event_t; -njs_int_t njs_add_event(njs_vm_t *vm, njs_event_t *event); -void njs_del_event(njs_vm_t *vm, njs_event_t *event, njs_uint_t action); - - -extern const njs_lvlhsh_proto_t njs_event_hash_proto; - - #endif /* _NJS_EVENT_H_INCLUDED_ */ diff --git a/src/njs_promise.c b/src/njs_promise.c index 79b5caf0..db128db5 100644 --- a/src/njs_promise.c +++ b/src/njs_promise.c @@ -449,39 +449,6 @@ njs_promise_capability_executor(njs_vm_t *vm, njs_value_t *args, } -njs_inline njs_int_t -njs_promise_add_event(njs_vm_t *vm, njs_function_t *function, njs_value_t *args, - njs_uint_t nargs) -{ - njs_event_t *event; - - event = njs_mp_zalloc(vm->mem_pool, sizeof(njs_event_t)); - if (njs_slow_path(event == NULL)) { - njs_memory_error(vm); - return NJS_ERROR; - } - - event->function = function; - event->once = 1; - - if (nargs != 0) { - event->args = njs_mp_alloc(vm->mem_pool, sizeof(njs_value_t) * nargs); - if (njs_slow_path(event->args == NULL)) { - njs_memory_error(vm); - return NJS_ERROR; - } - - memcpy(event->args, args, sizeof(njs_value_t) * nargs); - - event->nargs = nargs; - } - - njs_queue_insert_tail(&vm->promise_events, &event->link); - - return NJS_OK; -} - - njs_inline njs_value_t * njs_promise_trigger_reactions(njs_vm_t *vm, njs_value_t *value, njs_queue_t *queue) @@ -505,7 +472,7 @@ njs_promise_trigger_reactions(njs_vm_t *vm, njs_value_t *value, njs_set_data(&arguments[0], reaction, 0); arguments[1] = *value; - ret = njs_promise_add_event(vm, function, arguments, 2); + ret = njs_vm_enqueue_job(vm, function, arguments, 2); if (njs_slow_path(ret != NJS_OK)) { return njs_value_arg(&njs_value_null); } @@ -738,7 +705,7 @@ njs_promise_resolve_function(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, function->u.native = njs_promise_resolve_thenable_job; - ret = njs_promise_add_event(vm, function, arguments, 3); + ret = njs_vm_enqueue_job(vm, function, arguments, 3); if (njs_slow_path(ret != NJS_OK)) { return ret; } @@ -994,7 +961,7 @@ njs_promise_perform_then(njs_vm_t *vm, njs_value_t *value, arguments[1] = data->result; - ret = njs_promise_add_event(vm, function, arguments, 2); + ret = njs_vm_enqueue_job(vm, function, arguments, 2); if (njs_slow_path(ret != NJS_OK)) { return ret; } diff --git a/src/njs_vm.c b/src/njs_vm.c index e9601f55..1d1a4ffe 100644 --- a/src/njs_vm.c +++ b/src/njs_vm.c @@ -8,7 +8,6 @@ #include -static njs_int_t njs_vm_handle_events(njs_vm_t *vm); static njs_int_t njs_vm_protos_init(njs_vm_t *vm, njs_value_t *global); @@ -198,27 +197,10 @@ njs_vm_ctor_push(njs_vm_t *vm) void njs_vm_destroy(njs_vm_t *vm) { - njs_event_t *event; - njs_lvlhsh_each_t lhe; - if (vm->hooks[NJS_HOOK_EXIT] != NULL) { (void) njs_vm_call(vm, vm->hooks[NJS_HOOK_EXIT], NULL, 0); } - if (njs_waiting_events(vm)) { - njs_lvlhsh_each_init(&lhe, &njs_event_hash_proto); - - for ( ;; ) { - event = njs_lvlhsh_each(&vm->events_hash, &lhe); - - if (event == NULL) { - break; - } - - njs_del_event(vm, event, NJS_EVENT_RELEASE); - } - } - njs_mp_destroy(vm->mem_pool); } @@ -487,12 +469,10 @@ njs_vm_runtime_init(njs_vm_t *vm) njs_lvlhsh_init(&vm->values_hash); njs_lvlhsh_init(&vm->keywords_hash); njs_lvlhsh_init(&vm->modules_hash); - njs_lvlhsh_init(&vm->events_hash); njs_rbtree_init(&vm->global_symbols, njs_symbol_rbtree_cmp); - njs_queue_init(&vm->posted_events); - njs_queue_init(&vm->promise_events); + njs_queue_init(&vm->jobs); return NJS_OK; } @@ -640,99 +620,73 @@ njs_vm_scopes_restore(njs_vm_t *vm, njs_native_frame_t *native) } -njs_vm_event_t -njs_vm_add_event(njs_vm_t *vm, njs_function_t *function, njs_uint_t once, - njs_host_event_t host_ev, njs_event_destructor_t destructor) -{ - njs_event_t *event; - - event = njs_mp_alloc(vm->mem_pool, sizeof(njs_event_t)); - if (njs_slow_path(event == NULL)) { - return NULL; - } - - event->host_event = host_ev; - event->destructor = destructor; - event->function = function; - event->once = once; - event->posted = 0; - event->nargs = 0; - event->args = NULL; - - if (njs_add_event(vm, event) != NJS_OK) { - return NULL; - } - - return event; -} - - -void -njs_vm_del_event(njs_vm_t *vm, njs_vm_event_t vm_event) +njs_int_t +njs_vm_pending(njs_vm_t *vm) { - njs_event_t *event; - - event = (njs_event_t *) vm_event; - - njs_del_event(vm, event, NJS_EVENT_RELEASE | NJS_EVENT_DELETE); + return !njs_queue_is_empty(&(vm)->jobs); } njs_int_t -njs_vm_waiting(njs_vm_t *vm) +njs_vm_unhandled_rejection(njs_vm_t *vm) { - return njs_waiting_events(vm); -} + njs_int_t ret; + njs_str_t str; + njs_value_t string; + if (!(vm->options.unhandled_rejection + == NJS_VM_OPT_UNHANDLED_REJECTION_THROW + && vm->promise_reason != NULL + && vm->promise_reason->length != 0)) + { + return 0; + } -njs_int_t -njs_vm_posted(njs_vm_t *vm) -{ - return njs_posted_events(vm) || njs_promise_events(vm); -} + njs_value_assign(&string, &vm->promise_reason->start[0]); + ret = njs_value_to_string(vm, &string, &string); + if (njs_slow_path(ret != NJS_OK)) { + return ret; + } + njs_string_get(&string, &str); + njs_vm_error(vm, "unhandled promise rejection: %V", &str); -njs_int_t -njs_vm_unhandled_rejection(njs_vm_t *vm) -{ - return vm->options.unhandled_rejection - == NJS_VM_OPT_UNHANDLED_REJECTION_THROW - && vm->promise_reason != NULL - && vm->promise_reason->length != 0; + njs_mp_free(vm->mem_pool, vm->promise_reason); + vm->promise_reason = NULL; + + return 1; } njs_int_t -njs_vm_post_event(njs_vm_t *vm, njs_vm_event_t vm_event, +njs_vm_enqueue_job(njs_vm_t *vm, njs_function_t *function, const njs_value_t *args, njs_uint_t nargs) { njs_event_t *event; - event = (njs_event_t *) vm_event; + event = njs_mp_zalloc(vm->mem_pool, sizeof(njs_event_t)); + if (njs_slow_path(event == NULL)) { + njs_memory_error(vm); + return NJS_ERROR; + } - if (nargs != 0 && !event->posted) { - event->nargs = nargs; + event->function = function; + + if (nargs != 0) { event->args = njs_mp_alloc(vm->mem_pool, sizeof(njs_value_t) * nargs); if (njs_slow_path(event->args == NULL)) { + njs_memory_error(vm); return NJS_ERROR; } memcpy(event->args, args, sizeof(njs_value_t) * nargs); - } - if (!event->posted) { - event->posted = 1; - njs_queue_insert_tail(&vm->posted_events, &event->link); + event->nargs = nargs; } - return NJS_OK; -} - + njs_queue_insert_tail(&vm->jobs, &event->link); -njs_int_t -njs_vm_run(njs_vm_t *vm) -{ - return njs_vm_handle_events(vm); + return NJS_OK; } @@ -747,80 +701,32 @@ njs_vm_start(njs_vm_t *vm, njs_value_t *retval) } -static njs_int_t -njs_vm_handle_events(njs_vm_t *vm) +njs_int_t +njs_vm_execute_pending_job(njs_vm_t *vm) { njs_int_t ret; - njs_str_t str; - njs_value_t string; njs_event_t *ev; - njs_queue_t *promise_events, *posted_events; + njs_queue_t *jobs; njs_queue_link_t *link; - promise_events = &vm->promise_events; - posted_events = &vm->posted_events; - - do { - for ( ;; ) { - link = njs_queue_first(promise_events); - - if (link == njs_queue_tail(promise_events)) { - break; - } + jobs = &vm->jobs; - ev = njs_queue_link_data(link, njs_event_t, link); - - njs_queue_remove(&ev->link); - - ret = njs_vm_call(vm, ev->function, ev->args, ev->nargs); - if (njs_slow_path(ret == NJS_ERROR)) { - return ret; - } - } + link = njs_queue_first(jobs); - if (njs_vm_unhandled_rejection(vm)) { - njs_value_assign(&string, &vm->promise_reason->start[0]); - ret = njs_value_to_string(vm, &string, &string); - if (njs_slow_path(ret != NJS_OK)) { - return ret; - } - - njs_string_get(&string, &str); - njs_vm_error(vm, "unhandled promise rejection: %V", &str); - - njs_mp_free(vm->mem_pool, vm->promise_reason); - vm->promise_reason = NULL; - - return NJS_ERROR; - } - - for ( ;; ) { - link = njs_queue_first(posted_events); - - if (link == njs_queue_tail(posted_events)) { - break; - } - - ev = njs_queue_link_data(link, njs_event_t, link); - - if (ev->once) { - njs_del_event(vm, ev, NJS_EVENT_RELEASE | NJS_EVENT_DELETE); + if (link == njs_queue_tail(jobs)) { + return NJS_OK; + } - } else { - ev->posted = 0; - njs_queue_remove(&ev->link); - } + ev = njs_queue_link_data(link, njs_event_t, link); - ret = njs_vm_call(vm, ev->function, ev->args, ev->nargs); + njs_queue_remove(&ev->link); - if (ret == NJS_ERROR) { - return ret; - } - } - - } while (!njs_queue_is_empty(promise_events)); + ret = njs_vm_call(vm, ev->function, ev->args, ev->nargs); + if (ret == NJS_ERROR) { + return ret; + } - return njs_vm_pending(vm) ? NJS_AGAIN : NJS_OK; + return 1; } diff --git a/src/njs_vm.h b/src/njs_vm.h index 2389113f..1717f929 100644 --- a/src/njs_vm.h +++ b/src/njs_vm.h @@ -136,9 +136,7 @@ struct njs_vm_s { njs_lvlhsh_t modules_hash; uint32_t event_id; - njs_lvlhsh_t events_hash; - njs_queue_t posted_events; - njs_queue_t promise_events; + njs_queue_t jobs; njs_vm_opt_t options; diff --git a/src/test/njs_externals_test.c b/src/test/njs_externals_test.c index 4238fa35..cddb37d1 100644 --- a/src/test/njs_externals_test.c +++ b/src/test/njs_externals_test.c @@ -415,7 +415,6 @@ njs_unit_test_r_subrequest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, { njs_int_t ret; njs_value_t value, *argument, *select; - njs_vm_event_t vm_event; njs_function_t *callback; njs_external_ev_t *ev; njs_external_env_t *env; @@ -444,16 +443,10 @@ njs_unit_test_r_subrequest(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, return NJS_ERROR; } - vm_event = njs_vm_add_event(vm, callback, 1, NULL, NULL); - if (vm_event == NULL) { - njs_internal_error(vm, "njs_vm_add_event() failed"); - return NJS_ERROR; - } - argument = njs_arg(args, nargs, 1); select = njs_arg(args, nargs, 2); - ev->vm_event = vm_event; + ev->function = callback; ev->data = r; ev->nargs = 2; njs_value_assign(&ev->args[0], &ev->callbacks[!!njs_bool(select)]); @@ -1429,10 +1422,15 @@ njs_external_env_init(njs_external_env_t *env) njs_int_t njs_external_process_events(njs_vm_t *vm, njs_external_env_t *env) { + njs_int_t ret; njs_queue_t *events; njs_queue_link_t *link; njs_external_ev_t *ev; + if (env == NULL) { + return NJS_OK; + } + events = &env->events; for ( ;; ) { @@ -1448,11 +1446,13 @@ njs_external_process_events(njs_vm_t *vm, njs_external_env_t *env) ev->link.prev = NULL; ev->link.next = NULL; - njs_vm_post_event(vm, ev->vm_event, njs_value_arg(&ev->args[0]), - ev->nargs); + ret = njs_vm_call(vm, ev->function, njs_value_arg(ev->args), ev->nargs); + if (ret == NJS_ERROR) { + return NJS_ERROR; + } } - return NJS_OK; + return njs_vm_pending(vm) ? NJS_AGAIN: NJS_OK; } @@ -1474,5 +1474,16 @@ njs_external_call(njs_vm_t *vm, const njs_str_t *fname, njs_value_t *args, return NJS_ERROR; } - return njs_vm_run(vm); + for ( ;; ) { + ret = njs_vm_execute_pending_job(vm); + if (ret <= NJS_OK) { + if (ret == NJS_ERROR || njs_vm_unhandled_rejection(vm)) { + return NJS_ERROR; + } + + break; + } + } + + return NJS_OK; } diff --git a/src/test/njs_externals_test.h b/src/test/njs_externals_test.h index 4d9b6fd0..fc67eb43 100644 --- a/src/test/njs_externals_test.h +++ b/src/test/njs_externals_test.h @@ -15,7 +15,7 @@ typedef struct { typedef struct { - njs_vm_event_t vm_event; + njs_function_t *function; void *data; njs_uint_t nargs; njs_opaque_value_t args[3]; diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index e9ff3a6b..8561bfcf 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -23705,25 +23705,29 @@ njs_process_test(njs_external_state_t *state, njs_opts_t *opts, case sw_loop: default: for ( ;; ) { - if (!njs_vm_pending(state->vm)) { - break; + for ( ;; ) { + ret = njs_vm_execute_pending_job(state->vm); + if (ret <= NJS_OK) { + if (ret == NJS_ERROR + || njs_vm_unhandled_rejection(state->vm)) + { + return NJS_ERROR; + } + + break; + } } ret = njs_external_process_events(state->vm, state->env); - if (ret != NJS_OK) { + if (ret == NJS_ERROR) { njs_stderror("njs_external_process_events() failed\n"); return NJS_ERROR; } - if (njs_vm_waiting(state->vm) && !njs_vm_posted(state->vm)) { - /*TODO: async events. */ - - njs_stderror("njs_process_test(): async events unsupported\n"); - return NJS_ERROR; + if (ret == NJS_OK) { + break; } - (void) njs_vm_run(state->vm); - if (opts->async) { return NJS_OK; }