]> git.kaiwu.me - njs.git/commitdiff
Refactored asynchronous events.
authorDmitry Volyntsev <xeioex@nginx.com>
Tue, 5 Dec 2023 16:54:18 +0000 (08:54 -0800)
committerDmitry Volyntsev <xeioex@nginx.com>
Tue, 5 Dec 2023 16:54:18 +0000 (08:54 -0800)
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().

18 files changed:
auto/sources
external/njs_fs_module.c
external/njs_shell.c
external/njs_webcrypto_module.c
nginx/ngx_http_js_module.c
nginx/ngx_js.c
nginx/ngx_js.h
nginx/ngx_js_fetch.c
nginx/ngx_stream_js_module.c
src/njs.h
src/njs_event.c [deleted file]
src/njs_event.h
src/njs_promise.c
src/njs_vm.c
src/njs_vm.h
src/test/njs_externals_test.c
src/test/njs_externals_test.h
src/test/njs_unit_test.c

index 9f5d9d5ab99621ac8a45468a626ce9fb0d9e4ff1..d2172e3718808d5e74fac695488e36f2f991e1cd 100644 (file)
@@ -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 \
index 819feafb42f476651d147175b2cba467b39ac321..da9afe67a589285f0dded690def54053ed2144b7 100644 (file)
@@ -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;
         }
index eaabbb07b7a851af411bba699e8d6314a1ad8eba..f1836df51a859e95a1e59120dbf3163fcfaf10ac 100644 (file)
@@ -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;
             }
         }
 
index cf7151866a33dd4f1bd37f783dc2dec17d24f220..b8adc0b2435a6eb7e413cc9bc960e4de6ceb537f 100644 (file)
@@ -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;
     }
index 3d27f7fb22599887a8c8795a8bf02c9a8139ae6c..9ffc58c8c83f4968deb60c6d2cd2ff5a2abc0cb6 100644 (file)
@@ -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);
     }
 
index 2b11c4bfee34a5acdd073ab924d52c1a5ae58ec8..c28995ede2eb766f0f259f2f8b55c34358c5532e 100644 (file)
@@ -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);
 
index 418fccb162911e64805a77e2c7e3d159bf4d9ba7..e0e3adac7da3aac20a0251d5ba38e462eaded9e9 100644 (file)
@@ -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);
 
index c3d15aa092375eac058bf7d0c2bdb8ed492793c5..6fb723d4b0becb513975b570cf15f5d7429d231b 100644 (file)
@@ -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);
     }
 }
 
index bb19f811ef3e45ecc386bdadc9e24fe3d767344d..b6a51eaa65ebf9d484d339c1dce1bedce9164439 100644 (file)
@@ -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;
index 319924c81c80c8d5a783434b8fd6ecc497e7165e..ba610a7a334cf8d21f71bd0aac678704d724fb08 100644 (file)
--- 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 (file)
index 56c831f..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-
-/*
- * Copyright (C) Dmitry Volyntsev
- * Copyright (C) NGINX, Inc.
- */
-
-
-#include <njs_main.h>
-
-
-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);
-    }
-}
index 9ca3ac08702949bc2df128a6f6783db556e99b2f..4870228f0b49610d02d313cecac9771af97925e2 100644 (file)
@@ -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_ */
index 79b5caf06acc4481e1d70aba05fe59e445333f2a..db128db540f68541bd1941a4478a76603ca989d6 100644 (file)
@@ -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;
         }
index e9601f55bad8aa49796c01e80e61c5901bc4e83b..1d1a4ffe3475b5733003539fdf5a3bbd6738edaa 100644 (file)
@@ -8,7 +8,6 @@
 #include <njs_main.h>
 
 
-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;
 }
 
 
index 2389113ffd047c0a54a8ceb162c16183d5727142..1717f929ec20540f59285002242dbbe5db374540 100644 (file)
@@ -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;
 
index 4238fa353c1434962a71914b4d4be6e3b1fe4d51..cddb37d1691f2f7a540d7d66aaa33d20ca67d59d 100644 (file)
@@ -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;
 }
index 4d9b6fd057f16a6329a5ec5a41abf80e2b8c9b66..fc67eb432c28f86d253a2d764bb4243d0ff1462c 100644 (file)
@@ -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];
index e9ff3a6bd0e363ebf07d0cee7f7f6b1f0dbe8d6a..8561bfcf5493da0969edb91a0e86cda508310949 100644 (file)
@@ -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;
             }