Created
December 27, 2018 13:58
-
-
Save xeioex/0e36f4f105ca7b8c410f5cc651c10746 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # HG changeset patch | |
| # User Dmitry Volyntsev <[email protected]> | |
| # Date 1545914285 -10800 | |
| # Thu Dec 27 15:38:05 2018 +0300 | |
| # Node ID 52c69512c5d6b8f7466e75f8d7179b8146d91150 | |
| # Parent 9ab8d11c151d4af4e634fa9bb8ef0bfef662c064 | |
| njs_vm_run() is rectified. | |
| Previously, both njs_vm_call() and njs_vm_run() can be used to run njs | |
| code. njs_vm_call() was used to invoke a single function, while | |
| njs_vm_run() was used to run global code as well to process the events. | |
| At first invocation njs_vm_run() executed global code, all the next | |
| invocations it processed pending events. | |
| The solution is splitting njs_vm_run() into two functions. One for | |
| events processing and another for running the global code. | |
| diff --git a/nginx/ngx_http_js_module.c b/nginx/ngx_http_js_module.c | |
| --- a/nginx/ngx_http_js_module.c | |
| +++ b/nginx/ngx_http_js_module.c | |
| @@ -913,7 +913,7 @@ ngx_http_js_init_vm(ngx_http_request_t * | |
| cln->handler = ngx_http_js_cleanup_ctx; | |
| cln->data = ctx; | |
| - if (njs_vm_run(ctx->vm) == NJS_ERROR) { | |
| + if (njs_vm_start(ctx->vm) == NJS_ERROR) { | |
| njs_vm_retval_to_ext_string(ctx->vm, &exception); | |
| ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
| diff --git a/nginx/ngx_stream_js_module.c b/nginx/ngx_stream_js_module.c | |
| --- a/nginx/ngx_stream_js_module.c | |
| +++ b/nginx/ngx_stream_js_module.c | |
| @@ -727,7 +727,7 @@ ngx_stream_js_init_vm(ngx_stream_session | |
| cln->handler = ngx_stream_js_cleanup_ctx; | |
| cln->data = ctx; | |
| - if (njs_vm_run(ctx->vm) == NJS_ERROR) { | |
| + if (njs_vm_start(ctx->vm) == NJS_ERROR) { | |
| njs_vm_retval_to_ext_string(ctx->vm, &exception); | |
| ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, | |
| diff --git a/njs/njs.c b/njs/njs.c | |
| --- a/njs/njs.c | |
| +++ b/njs/njs.c | |
| @@ -595,27 +595,26 @@ njs_vm_post_event(njs_vm_t *vm, njs_vm_e | |
| nxt_int_t | |
| njs_vm_run(njs_vm_t *vm) | |
| { | |
| - nxt_int_t ret; | |
| - | |
| if (nxt_slow_path(vm->backtrace != NULL)) { | |
| nxt_array_reset(vm->backtrace); | |
| } | |
| + return njs_vm_handle_events(vm); | |
| +} | |
| + | |
| + | |
| +nxt_int_t | |
| +njs_vm_start(njs_vm_t *vm) | |
| +{ | |
| + njs_ret_t ret; | |
| + | |
| ret = njs_vmcode_interpreter(vm); | |
| if (ret == NJS_STOP) { | |
| - ret = njs_vm_handle_events(vm); | |
| + ret = NJS_OK; | |
| } | |
| - switch (ret) { | |
| - case NJS_STOP: | |
| - return NJS_OK; | |
| - | |
| - case NXT_AGAIN: | |
| - case NXT_ERROR: | |
| - default: | |
| - return ret; | |
| - } | |
| + return ret; | |
| } | |
| @@ -653,7 +652,7 @@ njs_vm_handle_events(njs_vm_t *vm) | |
| } | |
| } | |
| - return njs_is_pending_events(vm) ? NJS_AGAIN : NJS_STOP; | |
| + return njs_is_pending_events(vm) ? NJS_AGAIN : NJS_OK; | |
| } | |
| diff --git a/njs/njs.h b/njs/njs.h | |
| --- a/njs/njs.h | |
| +++ b/njs/njs.h | |
| @@ -162,8 +162,6 @@ NXT_EXPORT void njs_vm_destroy(njs_vm_t | |
| NXT_EXPORT nxt_int_t njs_vm_compile(njs_vm_t *vm, u_char **start, u_char *end); | |
| NXT_EXPORT njs_vm_t *njs_vm_clone(njs_vm_t *vm, njs_external_ptr_t external); | |
| -NXT_EXPORT nxt_int_t njs_vm_call(njs_vm_t *vm, njs_function_t *function, | |
| - const njs_value_t *args, nxt_uint_t nargs); | |
| NXT_EXPORT njs_vm_event_t njs_vm_add_event(njs_vm_t *vm, | |
| njs_function_t *function, nxt_uint_t once, njs_host_event_t host_ev, | |
| @@ -173,8 +171,35 @@ NXT_EXPORT nxt_int_t njs_vm_pending(njs_ | |
| NXT_EXPORT nxt_int_t njs_vm_post_event(njs_vm_t *vm, njs_vm_event_t vm_event, | |
| const njs_value_t *args, nxt_uint_t nargs); | |
| +/* | |
| + * Runs the specified function with provided arguments. | |
| + * NJS_OK successful run. | |
| + * NJS_ERROR some exception or internal error happens. | |
| + * | |
| + * njs_vm_retval(vm) can be used to get the retval or exception value. | |
| + */ | |
| +NXT_EXPORT nxt_int_t njs_vm_call(njs_vm_t *vm, njs_function_t *function, | |
| + const njs_value_t *args, nxt_uint_t nargs); | |
| + | |
| +/* | |
| + * 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_retval(vm) can be used to get the retval or exception value. | |
| + */ | |
| NXT_EXPORT nxt_int_t njs_vm_run(njs_vm_t *vm); | |
| +/* | |
| + * Runs the global code. | |
| + * NJS_OK successful run. | |
| + * NJS_ERROR some exception or internal error happens. | |
| + * | |
| + * njs_vm_retval(vm) can be used to get the retval or exception value. | |
| + */ | |
| +NXT_EXPORT nxt_int_t njs_vm_start(njs_vm_t *vm); | |
| + | |
| NXT_EXPORT const njs_extern_t *njs_vm_external_prototype(njs_vm_t *vm, | |
| njs_external_t *external); | |
| NXT_EXPORT nxt_int_t njs_vm_external_create(njs_vm_t *vm, | |
| diff --git a/njs/njs_shell.c b/njs/njs_shell.c | |
| --- a/njs/njs_shell.c | |
| +++ b/njs/njs_shell.c | |
| @@ -490,7 +490,7 @@ njs_process_script(njs_vm_t *vm, njs_opt | |
| printf("\n"); | |
| } | |
| - ret = njs_vm_run(vm); | |
| + ret = njs_vm_start(vm); | |
| } | |
| if (njs_vm_retval_dump(vm, out, 1) != NXT_OK) { | |
| diff --git a/njs/test/njs_interactive_test.c b/njs/test/njs_interactive_test.c | |
| --- a/njs/test/njs_interactive_test.c | |
| +++ b/njs/test/njs_interactive_test.c | |
| @@ -285,7 +285,7 @@ njs_interactive_test(nxt_bool_t verbose) | |
| ret = njs_vm_compile(vm, &start, end); | |
| if (ret == NXT_OK) { | |
| - ret = njs_vm_run(vm); | |
| + ret = njs_vm_start(vm); | |
| } | |
| } | |
| diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c | |
| --- a/njs/test/njs_unit_test.c | |
| +++ b/njs/test/njs_unit_test.c | |
| @@ -11801,7 +11801,7 @@ njs_unit_test(njs_unit_test_t tests[], s | |
| goto done; | |
| } | |
| - ret = njs_vm_run(nvm); | |
| + ret = njs_vm_start(nvm); | |
| if (njs_vm_retval_to_ext_string(nvm, &s) != NXT_OK) { | |
| printf("njs_vm_retval_to_ext_string() failed\n"); | |
| # HG changeset patch | |
| # User Dmitry Volyntsev <[email protected]> | |
| # Date 1545914357 -10800 | |
| # Thu Dec 27 15:39:17 2018 +0300 | |
| # Node ID 60d07e60d7fad21501cfb38da993466314221b73 | |
| # Parent 52c69512c5d6b8f7466e75f8d7179b8146d91150 | |
| njs_vm_pending() is split in njs_vm_posted() and njs_vm_waiting(). | |
| There are two types of events in njs: | |
| Posted - are ready to be executed by njs_vm_run(). | |
| Waiting - await external async events. | |
| diff --git a/njs/njs.c b/njs/njs.c | |
| --- a/njs/njs.c | |
| +++ b/njs/njs.c | |
| @@ -196,7 +196,7 @@ njs_vm_destroy(njs_vm_t *vm) | |
| njs_event_t *event; | |
| nxt_lvlhsh_each_t lhe; | |
| - if (njs_is_pending_events(vm)) { | |
| + if (njs_waiting_events(vm)) { | |
| nxt_lvlhsh_each_init(&lhe, &njs_event_hash_proto); | |
| for ( ;; ) { | |
| @@ -558,9 +558,16 @@ njs_vm_del_event(njs_vm_t *vm, njs_vm_ev | |
| nxt_int_t | |
| -njs_vm_pending(njs_vm_t *vm) | |
| +njs_vm_waiting(njs_vm_t *vm) | |
| { | |
| - return njs_is_pending_events(vm); | |
| + return njs_waiting_events(vm); | |
| +} | |
| + | |
| + | |
| +nxt_int_t | |
| +njs_vm_posted(njs_vm_t *vm) | |
| +{ | |
| + return njs_posted_events(vm); | |
| } | |
| @@ -652,7 +659,7 @@ njs_vm_handle_events(njs_vm_t *vm) | |
| } | |
| } | |
| - return njs_is_pending_events(vm) ? NJS_AGAIN : NJS_OK; | |
| + return njs_posted_events(vm) ? NJS_AGAIN : NJS_OK; | |
| } | |
| diff --git a/njs/njs.h b/njs/njs.h | |
| --- a/njs/njs.h | |
| +++ b/njs/njs.h | |
| @@ -167,11 +167,23 @@ NXT_EXPORT njs_vm_event_t njs_vm_add_eve | |
| njs_function_t *function, nxt_uint_t once, njs_host_event_t host_ev, | |
| njs_event_destructor destructor); | |
| NXT_EXPORT void njs_vm_del_event(njs_vm_t *vm, njs_vm_event_t vm_event); | |
| -NXT_EXPORT nxt_int_t njs_vm_pending(njs_vm_t *vm); | |
| NXT_EXPORT nxt_int_t njs_vm_post_event(njs_vm_t *vm, njs_vm_event_t vm_event, | |
| const njs_value_t *args, nxt_uint_t nargs); | |
| /* | |
| + * Returns 1 if async events are present. | |
| + */ | |
| +NXT_EXPORT nxt_int_t njs_vm_waiting(njs_vm_t *vm); | |
| + | |
| +/* | |
| + * Returns 1 if posted events are ready to be executed. | |
| + */ | |
| +NXT_EXPORT nxt_int_t njs_vm_posted(njs_vm_t *vm); | |
| + | |
| +#define njs_vm_pending(vm) (njs_vm_waiting(vm) || njs_vm_posted(vm)) | |
| + | |
| + | |
| +/* | |
| * Runs the specified function with provided arguments. | |
| * NJS_OK successful run. | |
| * NJS_ERROR some exception or internal error happens. | |
| diff --git a/njs/njs_event.h b/njs/njs_event.h | |
| --- a/njs/njs_event.h | |
| +++ b/njs/njs_event.h | |
| @@ -12,7 +12,9 @@ | |
| #define NJS_EVENT_DELETE 2 | |
| -#define njs_is_pending_events(vm) (!nxt_lvlhsh_is_empty(&(vm)->events_hash)) | |
| +#define njs_waiting_events(vm) (!nxt_lvlhsh_is_empty(&(vm)->events_hash)) | |
| + | |
| +#define njs_posted_events(vm) (!nxt_queue_is_empty(&(vm)->posted_events)) | |
| typedef struct { | |
| # HG changeset patch | |
| # User Dmitry Volyntsev <[email protected]> | |
| # Date 1545917281 -10800 | |
| # Thu Dec 27 16:28:01 2018 +0300 | |
| # Node ID 0f63a2fa6f2f5c2e388218d8ed9d915afca70f8c | |
| # Parent 60d07e60d7fad21501cfb38da993466314221b73 | |
| Interactive shell: initial support of posted events. | |
| diff --git a/njs/njs_shell.c b/njs/njs_shell.c | |
| --- a/njs/njs_shell.c | |
| +++ b/njs/njs_shell.c | |
| @@ -54,7 +54,7 @@ static nxt_int_t njs_interactive_shell(n | |
| njs_vm_opt_t *vm_options); | |
| static nxt_int_t njs_process_file(njs_opts_t *opts, njs_vm_opt_t *vm_options); | |
| static nxt_int_t njs_process_script(njs_vm_t *vm, njs_opts_t *opts, | |
| - const nxt_str_t *script, nxt_str_t *out); | |
| + const nxt_str_t *script); | |
| static nxt_int_t njs_editline_init(njs_vm_t *vm); | |
| static char **njs_completion_handler(const char *text, int start, int end); | |
| static char *njs_completion_generator(const char *text, int state); | |
| @@ -297,7 +297,7 @@ static nxt_int_t | |
| njs_interactive_shell(njs_opts_t *opts, njs_vm_opt_t *vm_options) | |
| { | |
| njs_vm_t *vm; | |
| - nxt_str_t line, out; | |
| + nxt_str_t line; | |
| vm = njs_vm_create(vm_options); | |
| if (vm == NULL) { | |
| @@ -335,9 +335,7 @@ njs_interactive_shell(njs_opts_t *opts, | |
| add_history((char *) line.start); | |
| - njs_process_script(vm, opts, &line, &out); | |
| - | |
| - printf("%.*s\n", (int) out.length, out.start); | |
| + njs_process_script(vm, opts, &line); | |
| /* editline allocs a new buffer every time. */ | |
| free(line.start); | |
| @@ -357,7 +355,7 @@ njs_process_file(njs_opts_t *opts, njs_v | |
| ssize_t n; | |
| njs_vm_t *vm; | |
| nxt_int_t ret; | |
| - nxt_str_t out, script; | |
| + nxt_str_t script; | |
| struct stat sb; | |
| file = opts->file; | |
| @@ -448,9 +446,8 @@ njs_process_file(njs_opts_t *opts, njs_v | |
| goto done; | |
| } | |
| - ret = njs_process_script(vm, opts, &script, &out); | |
| + ret = njs_process_script(vm, opts, &script); | |
| if (ret != NXT_OK) { | |
| - fprintf(stderr, "%.*s\n", (int) out.length, out.start); | |
| ret = NXT_ERROR; | |
| goto done; | |
| } | |
| @@ -473,9 +470,27 @@ close_fd: | |
| } | |
| +static void | |
| +njs_output(njs_vm_t *vm, njs_opts_t *opts, njs_ret_t ret) | |
| +{ | |
| + nxt_str_t out; | |
| + | |
| + if (njs_vm_retval_dump(vm, &out, 1) != NXT_OK) { | |
| + out = nxt_string_value("failed to get retval from VM"); | |
| + ret = NJS_ERROR; | |
| + } | |
| + | |
| + if (ret != NJS_OK) { | |
| + fprintf(stderr, "%.*s\n", (int) out.length, out.start); | |
| + | |
| + } else if (opts->interactive) { | |
| + printf("%.*s\n", (int) out.length, out.start); | |
| + } | |
| +} | |
| + | |
| + | |
| static nxt_int_t | |
| -njs_process_script(njs_vm_t *vm, njs_opts_t *opts, const nxt_str_t *script, | |
| - nxt_str_t *out) | |
| +njs_process_script(njs_vm_t *vm, njs_opts_t *opts, const nxt_str_t *script) | |
| { | |
| u_char *start; | |
| nxt_int_t ret; | |
| @@ -493,9 +508,17 @@ njs_process_script(njs_vm_t *vm, njs_opt | |
| ret = njs_vm_start(vm); | |
| } | |
| - if (njs_vm_retval_dump(vm, out, 1) != NXT_OK) { | |
| - *out = nxt_string_value("failed to get retval from VM"); | |
| - return NXT_ERROR; | |
| + njs_output(vm, opts, ret); | |
| + | |
| + if (ret == NJS_OK) { | |
| + while (njs_vm_posted(vm)) { | |
| + ret = njs_vm_run(vm); | |
| + | |
| + if (ret == NJS_ERROR) { | |
| + njs_output(vm, opts, ret); | |
| + return ret; | |
| + } | |
| + } | |
| } | |
| return ret; | |
| # HG changeset patch | |
| # User Dmitry Volyntsev <[email protected]> | |
| # Date 1545917348 -10800 | |
| # Thu Dec 27 16:29:08 2018 +0300 | |
| # Node ID a711ef15fe0cda47516a48a45ec3b79c9eabac16 | |
| # Parent 0f63a2fa6f2f5c2e388218d8ed9d915afca70f8c | |
| Added setImmediate(). | |
| diff --git a/njs/njs.c b/njs/njs.c | |
| --- a/njs/njs.c | |
| +++ b/njs/njs.c | |
| @@ -521,7 +521,7 @@ njs_vm_call(njs_vm_t *vm, njs_function_t | |
| njs_vm_event_t | |
| njs_vm_add_event(njs_vm_t *vm, njs_function_t *function, nxt_uint_t once, | |
| - njs_host_event_t host_ev, njs_event_destructor destructor) | |
| + njs_host_event_t host_ev, njs_event_destructor_t destructor) | |
| { | |
| njs_event_t *event; | |
| diff --git a/njs/njs.h b/njs/njs.h | |
| --- a/njs/njs.h | |
| +++ b/njs/njs.h | |
| @@ -125,15 +125,15 @@ typedef void * njs_ | |
| typedef void * njs_host_event_t; | |
| typedef void * njs_external_ptr_t; | |
| -typedef njs_host_event_t (*njs_set_timer)(njs_external_ptr_t external, | |
| +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)(njs_external_ptr_t external, | |
| +typedef void (*njs_event_destructor_t)(njs_external_ptr_t external, | |
| njs_host_event_t event); | |
| typedef struct { | |
| - njs_set_timer set_timer; | |
| - njs_event_destructor clear_timer; | |
| + njs_set_timer_t set_timer; | |
| + njs_event_destructor_t clear_timer; | |
| } njs_vm_ops_t; | |
| @@ -165,7 +165,7 @@ NXT_EXPORT njs_vm_t *njs_vm_clone(njs_vm | |
| NXT_EXPORT njs_vm_event_t njs_vm_add_event(njs_vm_t *vm, | |
| njs_function_t *function, nxt_uint_t once, njs_host_event_t host_ev, | |
| - njs_event_destructor destructor); | |
| + njs_event_destructor_t destructor); | |
| NXT_EXPORT void njs_vm_del_event(njs_vm_t *vm, njs_vm_event_t vm_event); | |
| NXT_EXPORT nxt_int_t njs_vm_post_event(njs_vm_t *vm, njs_vm_event_t vm_event, | |
| const njs_value_t *args, nxt_uint_t nargs); | |
| diff --git a/njs/njs_builtin.c b/njs/njs_builtin.c | |
| --- a/njs/njs_builtin.c | |
| +++ b/njs/njs_builtin.c | |
| @@ -111,6 +111,7 @@ const njs_object_init_t *njs_function | |
| &njs_decode_uri_component_function_init, | |
| &njs_require_function_init, | |
| &njs_set_timeout_function_init, | |
| + &njs_set_immediate_function_init, | |
| &njs_clear_timeout_function_init, | |
| NULL | |
| }; | |
| @@ -132,6 +133,8 @@ const njs_function_init_t njs_native_fu | |
| { njs_module_require, { NJS_SKIP_ARG, NJS_STRING_ARG } }, | |
| { njs_set_timeout, | |
| { NJS_SKIP_ARG, NJS_FUNCTION_ARG, NJS_NUMBER_ARG } }, | |
| + { njs_set_immediate, | |
| + { NJS_SKIP_ARG, NJS_FUNCTION_ARG } }, | |
| { njs_clear_timeout, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, | |
| }; | |
| diff --git a/njs/njs_event.h b/njs/njs_event.h | |
| --- a/njs/njs_event.h | |
| +++ b/njs/njs_event.h | |
| @@ -18,17 +18,17 @@ | |
| typedef struct { | |
| - njs_function_t *function; | |
| - njs_value_t *args; | |
| - nxt_uint_t nargs; | |
| - njs_host_event_t host_event; | |
| - njs_event_destructor destructor; | |
| + njs_function_t *function; | |
| + njs_value_t *args; | |
| + nxt_uint_t nargs; | |
| + njs_host_event_t host_event; | |
| + njs_event_destructor_t destructor; | |
| - njs_value_t id; | |
| - nxt_queue_link_t link; | |
| + njs_value_t id; | |
| + nxt_queue_link_t link; | |
| - unsigned posted:1; | |
| - unsigned once:1; | |
| + unsigned posted:1; | |
| + unsigned once:1; | |
| } njs_event_t; | |
| diff --git a/njs/njs_generator.c b/njs/njs_generator.c | |
| --- a/njs/njs_generator.c | |
| +++ b/njs/njs_generator.c | |
| @@ -406,6 +406,7 @@ njs_generator(njs_vm_t *vm, njs_generato | |
| case NJS_TOKEN_DECODE_URI_COMPONENT: | |
| case NJS_TOKEN_REQUIRE: | |
| case NJS_TOKEN_SET_TIMEOUT: | |
| + case NJS_TOKEN_SET_IMMEDIATE: | |
| case NJS_TOKEN_CLEAR_TIMEOUT: | |
| return njs_generate_builtin_object(vm, generator, node); | |
| diff --git a/njs/njs_lexer_keyword.c b/njs/njs_lexer_keyword.c | |
| --- a/njs/njs_lexer_keyword.c | |
| +++ b/njs/njs_lexer_keyword.c | |
| @@ -90,6 +90,7 @@ static const njs_keyword_t njs_keywords | |
| { nxt_string("decodeURIComponent"), NJS_TOKEN_DECODE_URI_COMPONENT, 0 }, | |
| { nxt_string("require"), NJS_TOKEN_REQUIRE, 0 }, | |
| { nxt_string("setTimeout"), NJS_TOKEN_SET_TIMEOUT, 0 }, | |
| + { nxt_string("setImmediate"), NJS_TOKEN_SET_IMMEDIATE, 0 }, | |
| { nxt_string("clearTimeout"), NJS_TOKEN_CLEAR_TIMEOUT, 0 }, | |
| /* Reserved words. */ | |
| diff --git a/njs/njs_parser.c b/njs/njs_parser.c | |
| --- a/njs/njs_parser.c | |
| +++ b/njs/njs_parser.c | |
| @@ -2075,6 +2075,7 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa | |
| case NJS_TOKEN_DECODE_URI_COMPONENT: | |
| case NJS_TOKEN_REQUIRE: | |
| case NJS_TOKEN_SET_TIMEOUT: | |
| + case NJS_TOKEN_SET_IMMEDIATE: | |
| case NJS_TOKEN_CLEAR_TIMEOUT: | |
| return njs_parser_builtin_function(vm, parser, node); | |
| diff --git a/njs/njs_parser.h b/njs/njs_parser.h | |
| --- a/njs/njs_parser.h | |
| +++ b/njs/njs_parser.h | |
| @@ -199,6 +199,7 @@ typedef enum { | |
| NJS_TOKEN_DECODE_URI_COMPONENT, | |
| NJS_TOKEN_REQUIRE, | |
| NJS_TOKEN_SET_TIMEOUT, | |
| + NJS_TOKEN_SET_IMMEDIATE, | |
| NJS_TOKEN_CLEAR_TIMEOUT, | |
| NJS_TOKEN_RESERVED, | |
| diff --git a/njs/njs_time.c b/njs/njs_time.c | |
| --- a/njs/njs_time.c | |
| +++ b/njs/njs_time.c | |
| @@ -10,10 +10,11 @@ | |
| #include <stdio.h> | |
| -njs_ret_t | |
| -njs_set_timeout(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, | |
| - njs_index_t unused) | |
| +static njs_ret_t | |
| +njs_set_timer(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, | |
| + njs_index_t unused, nxt_bool_t immediate) | |
| { | |
| + nxt_uint_t n; | |
| uint64_t delay; | |
| njs_event_t *event; | |
| njs_vm_ops_t *ops; | |
| @@ -36,7 +37,7 @@ njs_set_timeout(njs_vm_t *vm, njs_value_ | |
| delay = 0; | |
| - if (nargs >= 3 && njs_is_number(&args[2])) { | |
| + if (!immediate && nargs >= 3 && njs_is_number(&args[2])) { | |
| delay = args[2].data.u.number; | |
| } | |
| @@ -45,9 +46,11 @@ njs_set_timeout(njs_vm_t *vm, njs_value_ | |
| goto memory_error; | |
| } | |
| - event->destructor = ops->clear_timer; | |
| + n = immediate ? 2 : 3; | |
| + | |
| + event->destructor = (ops != NULL) ? ops->clear_timer : NULL; | |
| event->function = args[1].data.u.function; | |
| - event->nargs = (nargs >= 3) ? nargs - 3 : 0; | |
| + event->nargs = (nargs >= n) ? nargs - n : 0; | |
| event->once = 1; | |
| event->posted = 0; | |
| @@ -58,11 +61,11 @@ njs_set_timeout(njs_vm_t *vm, njs_value_ | |
| goto memory_error; | |
| } | |
| - memcpy(event->args, &args[3], sizeof(njs_value_t) * event->nargs); | |
| + memcpy(event->args, &args[n], sizeof(njs_value_t) * event->nargs); | |
| } | |
| event->host_event = ops->set_timer(vm->external, delay, event); | |
| - if (event->host_event == NULL) { | |
| + if (nxt_slow_path(event->host_event == NULL)) { | |
| njs_internal_error(vm, "set_timer() failed"); | |
| return NJS_ERROR; | |
| } | |
| @@ -78,6 +81,22 @@ memory_error: | |
| njs_ret_t | |
| +njs_set_timeout(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, | |
| + njs_index_t unused) | |
| +{ | |
| + return njs_set_timer(vm, args, nargs, unused, 0); | |
| +} | |
| + | |
| + | |
| +njs_ret_t | |
| +njs_set_immediate(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, | |
| + njs_index_t unused) | |
| +{ | |
| + return njs_set_timer(vm, args, nargs, unused, 1); | |
| +} | |
| + | |
| + | |
| +njs_ret_t | |
| njs_clear_timeout(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, | |
| njs_index_t unused) | |
| { | |
| @@ -116,6 +135,12 @@ const njs_object_init_t njs_set_timeout | |
| 0, | |
| }; | |
| +const njs_object_init_t njs_set_immediate_function_init = { | |
| + nxt_string("setImmediate"), | |
| + NULL, | |
| + 0, | |
| +}; | |
| + | |
| const njs_object_init_t njs_clear_timeout_function_init = { | |
| nxt_string("clearTimeout"), | |
| diff --git a/njs/njs_time.h b/njs/njs_time.h | |
| --- a/njs/njs_time.h | |
| +++ b/njs/njs_time.h | |
| @@ -10,11 +10,14 @@ | |
| njs_ret_t njs_set_timeout(njs_vm_t *vm, njs_value_t *args, | |
| nxt_uint_t nargs, njs_index_t unused); | |
| +njs_ret_t njs_set_immediate(njs_vm_t *vm, njs_value_t *args, | |
| + nxt_uint_t nargs, njs_index_t unused); | |
| njs_ret_t njs_clear_timeout(njs_vm_t *vm, njs_value_t *args, | |
| nxt_uint_t nargs, njs_index_t unused); | |
| extern const njs_object_init_t njs_set_timeout_function_init; | |
| +extern const njs_object_init_t njs_set_immediate_function_init; | |
| extern const njs_object_init_t njs_clear_timeout_function_init; | |
| #endif /* _NJS_TIMEOUT_H_INCLUDED_ */ | |
| diff --git a/njs/njs_vm.h b/njs/njs_vm.h | |
| --- a/njs/njs_vm.h | |
| +++ b/njs/njs_vm.h | |
| @@ -950,6 +950,7 @@ enum njs_function_e { | |
| NJS_FUNCTION_STRING_DECODE_URI_COMPONENT, | |
| NJS_FUNCTION_REQUIRE, | |
| NJS_FUNCTION_SET_TIMEOUT, | |
| + NJS_FUNCTION_SET_IMMEDIATE, | |
| NJS_FUNCTION_CLEAR_TIMEOUT, | |
| #define NJS_FUNCTION_MAX (NJS_FUNCTION_CLEAR_TIMEOUT + 1) | |
| }; | |
| # HG changeset patch | |
| # User Dmitry Volyntsev <[email protected]> | |
| # Date 1545917349 -10800 | |
| # Thu Dec 27 16:29:09 2018 +0300 | |
| # Node ID 651dec636dbf55ab7883eda05f7a77615bb7e581 | |
| # Parent a711ef15fe0cda47516a48a45ec3b79c9eabac16 | |
| Interactive shell: immediate events support. | |
| This closes #66 issue on Github. | |
| diff --git a/njs/njs.c b/njs/njs.c | |
| --- a/njs/njs.c | |
| +++ b/njs/njs.c | |
| @@ -645,7 +645,7 @@ njs_vm_handle_events(njs_vm_t *vm) | |
| ev = nxt_queue_link_data(link, njs_event_t, link); | |
| if (ev->once) { | |
| - njs_del_event(vm, ev, NJS_EVENT_DELETE); | |
| + njs_del_event(vm, ev, NJS_EVENT_RELEASE | NJS_EVENT_DELETE); | |
| } else { | |
| ev->posted = 0; | |
| diff --git a/njs/njs_shell.c b/njs/njs_shell.c | |
| --- a/njs/njs_shell.c | |
| +++ b/njs/njs_shell.c | |
| @@ -20,13 +20,6 @@ | |
| #include <readline.h> | |
| -typedef enum { | |
| - NJS_COMPLETION_VAR = 0, | |
| - NJS_COMPLETION_SUFFIX, | |
| - NJS_COMPLETION_GLOBAL | |
| -} njs_completion_phase_t; | |
| - | |
| - | |
| typedef struct { | |
| char *file; | |
| nxt_int_t version; | |
| @@ -40,22 +33,45 @@ typedef struct { | |
| typedef struct { | |
| size_t index; | |
| size_t length; | |
| - njs_vm_t *vm; | |
| nxt_array_t *completions; | |
| nxt_array_t *suffix_completions; | |
| nxt_lvlhsh_each_t lhe; | |
| - njs_completion_phase_t phase; | |
| + | |
| + enum { | |
| + NJS_COMPLETION_VAR = 0, | |
| + NJS_COMPLETION_SUFFIX, | |
| + NJS_COMPLETION_GLOBAL | |
| + } phase; | |
| } njs_completion_t; | |
| +typedef struct { | |
| + njs_vm_event_t vm_event; | |
| + nxt_queue_link_t link; | |
| +} njs_ev_t; | |
| + | |
| + | |
| +typedef struct { | |
| + njs_vm_t *vm; | |
| + | |
| + nxt_lvlhsh_t events; /* njs_ev_t * */ | |
| + nxt_queue_t posted_events; | |
| + | |
| + uint64_t time; | |
| + | |
| + njs_completion_t completion; | |
| +} njs_console_t; | |
| + | |
| + | |
| static nxt_int_t njs_get_options(njs_opts_t *opts, int argc, char **argv); | |
| -static nxt_int_t njs_externals_init(njs_vm_t *vm); | |
| +static nxt_int_t njs_console_init(njs_console_t *console, njs_vm_t *vm); | |
| +static nxt_int_t njs_externals_init(njs_console_t *console, njs_vm_t *vm); | |
| static nxt_int_t njs_interactive_shell(njs_opts_t *opts, | |
| njs_vm_opt_t *vm_options); | |
| static nxt_int_t njs_process_file(njs_opts_t *opts, njs_vm_opt_t *vm_options); | |
| -static nxt_int_t njs_process_script(njs_vm_t *vm, njs_opts_t *opts, | |
| +static nxt_int_t njs_process_script(njs_console_t *console, njs_opts_t *opts, | |
| const nxt_str_t *script); | |
| -static nxt_int_t njs_editline_init(njs_vm_t *vm); | |
| +static nxt_int_t njs_editline_init(void); | |
| static char **njs_completion_handler(const char *text, int start, int end); | |
| static char *njs_completion_generator(const char *text, int state); | |
| @@ -70,6 +86,15 @@ static njs_ret_t njs_ext_console_time(nj | |
| static njs_ret_t njs_ext_console_time_end(njs_vm_t *vm, njs_value_t *args, | |
| nxt_uint_t nargs, njs_index_t unused); | |
| +static njs_host_event_t njs_console_set_timer(njs_external_ptr_t external, | |
| + uint64_t delay, njs_vm_event_t vm_event); | |
| +static void njs_console_clear_timer(njs_external_ptr_t external, | |
| + njs_host_event_t event); | |
| + | |
| +static nxt_int_t lvlhsh_key_test(nxt_lvlhsh_query_t *lhq, void *data); | |
| +static void *lvlhsh_pool_alloc(void *pool, size_t size, nxt_uint_t nalloc); | |
| +static void lvlhsh_pool_free(void *pool, void *p, size_t size); | |
| + | |
| static njs_external_t njs_ext_console[] = { | |
| @@ -150,10 +175,22 @@ static njs_external_t njs_externals[] = | |
| }; | |
| -static njs_completion_t njs_completion; | |
| +static const nxt_lvlhsh_proto_t lvlhsh_proto nxt_aligned(64) = { | |
| + NXT_LVLHSH_LARGE_SLAB, | |
| + 0, | |
| + lvlhsh_key_test, | |
| + lvlhsh_pool_alloc, | |
| + lvlhsh_pool_free, | |
| +}; | |
| -static uint64_t njs_console_time = UINT64_MAX; | |
| +static njs_vm_ops_t njs_console_ops = { | |
| + njs_console_set_timer, | |
| + njs_console_clear_timer | |
| +}; | |
| + | |
| + | |
| +static njs_console_t njs_console; | |
| int | |
| @@ -182,6 +219,8 @@ main(int argc, char **argv) | |
| vm_options.accumulative = opts.interactive; | |
| vm_options.backtrace = 1; | |
| vm_options.sandbox = opts.sandbox; | |
| + vm_options.ops = &njs_console_ops; | |
| + vm_options.external = &njs_console; | |
| if (opts.interactive) { | |
| ret = njs_interactive_shell(&opts, &vm_options); | |
| @@ -259,7 +298,27 @@ njs_get_options(njs_opts_t *opts, int ar | |
| static nxt_int_t | |
| -njs_externals_init(njs_vm_t *vm) | |
| +njs_console_init(njs_console_t *console, njs_vm_t *vm) | |
| +{ | |
| + console->vm = vm; | |
| + | |
| + nxt_lvlhsh_init(&console->events); | |
| + nxt_queue_init(&console->posted_events); | |
| + | |
| + console->time = UINT64_MAX; | |
| + | |
| + console->completion.completions = njs_vm_completions(vm, NULL); | |
| + if (console->completion.completions == NULL) { | |
| + return NXT_ERROR; | |
| + } | |
| + | |
| + return NXT_OK; | |
| +} | |
| + | |
| + | |
| + | |
| +static nxt_int_t | |
| +njs_externals_init(njs_console_t *console, njs_vm_t *vm) | |
| { | |
| nxt_uint_t ret; | |
| njs_value_t *value; | |
| @@ -279,7 +338,7 @@ njs_externals_init(njs_vm_t *vm) | |
| return NXT_ERROR; | |
| } | |
| - ret = njs_vm_external_create(vm, value, proto, NULL); | |
| + ret = njs_vm_external_create(vm, value, proto, &njs_console); | |
| if (ret != NXT_OK) { | |
| return NXT_ERROR; | |
| } | |
| @@ -289,6 +348,11 @@ njs_externals_init(njs_vm_t *vm) | |
| return NXT_ERROR; | |
| } | |
| + ret = njs_console_init(console, vm); | |
| + if (ret != NXT_OK) { | |
| + return NXT_ERROR; | |
| + } | |
| + | |
| return NXT_OK; | |
| } | |
| @@ -299,22 +363,22 @@ njs_interactive_shell(njs_opts_t *opts, | |
| njs_vm_t *vm; | |
| nxt_str_t line; | |
| + if (njs_editline_init() != NXT_OK) { | |
| + fprintf(stderr, "failed to init completions\n"); | |
| + return NXT_ERROR; | |
| + } | |
| + | |
| vm = njs_vm_create(vm_options); | |
| if (vm == NULL) { | |
| fprintf(stderr, "failed to create vm\n"); | |
| return NXT_ERROR; | |
| } | |
| - if (njs_externals_init(vm) != NXT_OK) { | |
| + if (njs_externals_init(&njs_console, vm) != NXT_OK) { | |
| fprintf(stderr, "failed to add external protos\n"); | |
| return NXT_ERROR; | |
| } | |
| - if (njs_editline_init(vm) != NXT_OK) { | |
| - fprintf(stderr, "failed to init completions\n"); | |
| - return NXT_ERROR; | |
| - } | |
| - | |
| if (!opts->quiet) { | |
| printf("interactive njs %s\n\n", NJS_VERSION); | |
| @@ -335,7 +399,7 @@ njs_interactive_shell(njs_opts_t *opts, | |
| add_history((char *) line.start); | |
| - njs_process_script(vm, opts, &line); | |
| + njs_process_script(&njs_console, opts, &line); | |
| /* editline allocs a new buffer every time. */ | |
| free(line.start); | |
| @@ -439,14 +503,14 @@ njs_process_file(njs_opts_t *opts, njs_v | |
| goto done; | |
| } | |
| - ret = njs_externals_init(vm); | |
| + ret = njs_externals_init(&njs_console, vm); | |
| if (ret != NXT_OK) { | |
| fprintf(stderr, "failed to add external protos\n"); | |
| ret = NXT_ERROR; | |
| goto done; | |
| } | |
| - ret = njs_process_script(vm, opts, &script); | |
| + ret = njs_process_script(&njs_console, opts, &script); | |
| if (ret != NXT_OK) { | |
| ret = NXT_ERROR; | |
| goto done; | |
| @@ -490,11 +554,43 @@ njs_output(njs_vm_t *vm, njs_opts_t *opt | |
| static nxt_int_t | |
| -njs_process_script(njs_vm_t *vm, njs_opts_t *opts, const nxt_str_t *script) | |
| +njs_process_events(njs_console_t *console, njs_opts_t *opts) | |
| +{ | |
| + njs_ev_t *ev; | |
| + nxt_queue_t *events; | |
| + nxt_queue_link_t *link; | |
| + | |
| + events = &console->posted_events; | |
| + | |
| + for ( ;; ) { | |
| + link = nxt_queue_first(events); | |
| + | |
| + if (link == nxt_queue_tail(events)) { | |
| + break; | |
| + } | |
| + | |
| + ev = nxt_queue_link_data(link, njs_ev_t, link); | |
| + | |
| + nxt_queue_remove(&ev->link); | |
| + ev->link.prev = NULL; | |
| + ev->link.next = NULL; | |
| + | |
| + njs_vm_post_event(console->vm, ev->vm_event, NULL, 0); | |
| + } | |
| + | |
| + return NXT_OK; | |
| +} | |
| + | |
| + | |
| +static nxt_int_t | |
| +njs_process_script(njs_console_t *console, njs_opts_t *opts, | |
| + const nxt_str_t *script) | |
| { | |
| u_char *start; | |
| + njs_vm_t *vm; | |
| nxt_int_t ret; | |
| + vm = console->vm; | |
| start = script->start; | |
| ret = njs_vm_compile(vm, &start, start + script->length); | |
| @@ -510,14 +606,29 @@ njs_process_script(njs_vm_t *vm, njs_opt | |
| njs_output(vm, opts, ret); | |
| - if (ret == NJS_OK) { | |
| - while (njs_vm_posted(vm)) { | |
| - ret = njs_vm_run(vm); | |
| + for ( ;; ) { | |
| + if (!njs_vm_pending(vm)) { | |
| + break; | |
| + } | |
| - if (ret == NJS_ERROR) { | |
| - njs_output(vm, opts, ret); | |
| - return ret; | |
| - } | |
| + ret = njs_process_events(console, opts); | |
| + if (nxt_slow_path(ret != NXT_OK)) { | |
| + fprintf(stderr, "njs_process_events() failed\n"); | |
| + ret = NJS_ERROR; | |
| + } | |
| + | |
| + if (njs_vm_waiting(vm) && !njs_vm_posted(vm)) { | |
| + /*TODO: async events. */ | |
| + | |
| + fprintf(stderr, "njs_process_script(): " | |
| + "async events unsupported\n"); | |
| + ret = NJS_ERROR; | |
| + } | |
| + | |
| + ret = njs_vm_run(vm); | |
| + | |
| + if (ret == NJS_ERROR) { | |
| + njs_output(vm, opts, ret); | |
| } | |
| } | |
| @@ -526,7 +637,7 @@ njs_process_script(njs_vm_t *vm, njs_opt | |
| static nxt_int_t | |
| -njs_editline_init(njs_vm_t *vm) | |
| +njs_editline_init(void) | |
| { | |
| rl_completion_append_character = '\0'; | |
| rl_attempted_completion_function = njs_completion_handler; | |
| @@ -534,13 +645,6 @@ njs_editline_init(njs_vm_t *vm) | |
| setlocale(LC_ALL, ""); | |
| - njs_completion.completions = njs_vm_completions(vm, NULL); | |
| - if (njs_completion.completions == NULL) { | |
| - return NXT_ERROR; | |
| - } | |
| - | |
| - njs_completion.vm = vm; | |
| - | |
| return NXT_OK; | |
| } | |
| @@ -571,10 +675,12 @@ njs_completion_generator(const char *tex | |
| size_t len; | |
| nxt_str_t expression, *suffix; | |
| const char *p; | |
| + njs_vm_t *vm; | |
| njs_variable_t *var; | |
| njs_completion_t *cmpl; | |
| - cmpl = &njs_completion; | |
| + vm = njs_console.vm; | |
| + cmpl = &njs_console.completion; | |
| if (state == 0) { | |
| cmpl->phase = 0; | |
| @@ -589,12 +695,12 @@ next: | |
| switch (cmpl->phase) { | |
| case NJS_COMPLETION_VAR: | |
| - if (cmpl->vm->parser == NULL) { | |
| + if (vm->parser == NULL) { | |
| njs_next_phase(cmpl); | |
| } | |
| for ( ;; ) { | |
| - var = nxt_lvlhsh_each(&cmpl->vm->parser->scope->variables, | |
| + var = nxt_lvlhsh_each(&vm->parser->scope->variables, | |
| &cmpl->lhe); | |
| if (var == NULL) { | |
| @@ -630,8 +736,7 @@ next: | |
| expression.start = (u_char *) text; | |
| expression.length = p - text; | |
| - cmpl->suffix_completions = njs_vm_completions(cmpl->vm, | |
| - &expression); | |
| + cmpl->suffix_completions = njs_vm_completions(vm, &expression); | |
| if (cmpl->suffix_completions == NULL) { | |
| njs_next_phase(cmpl); | |
| } | |
| @@ -797,15 +902,22 @@ static njs_ret_t | |
| njs_ext_console_time(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, | |
| njs_index_t unused) | |
| { | |
| + njs_console_t *console; | |
| + | |
| if (!njs_value_is_void(njs_arg(args, nargs, 1))) { | |
| njs_vm_error(vm, "labels not implemented"); | |
| return NJS_ERROR; | |
| } | |
| + console = njs_vm_external(vm, njs_arg(args, nargs, 0)); | |
| + if (nxt_slow_path(console == NULL)) { | |
| + return NJS_ERROR; | |
| + } | |
| + | |
| + console->time = nxt_time(); | |
| + | |
| vm->retval = njs_value_void; | |
| - njs_console_time = nxt_time(); | |
| - | |
| return NJS_OK; | |
| } | |
| @@ -814,7 +926,8 @@ static njs_ret_t | |
| njs_ext_console_time_end(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, | |
| njs_index_t unused) | |
| { | |
| - uint64_t ns, ms; | |
| + uint64_t ns, ms; | |
| + njs_console_t *console; | |
| ns = nxt_time(); | |
| @@ -823,16 +936,21 @@ njs_ext_console_time_end(njs_vm_t *vm, n | |
| return NJS_ERROR; | |
| } | |
| - if (nxt_fast_path(njs_console_time != UINT64_MAX)) { | |
| + console = njs_vm_external(vm, njs_arg(args, nargs, 0)); | |
| + if (nxt_slow_path(console == NULL)) { | |
| + return NJS_ERROR; | |
| + } | |
| - ns = ns - njs_console_time; | |
| + if (nxt_fast_path(console->time != UINT64_MAX)) { | |
| + | |
| + ns = ns - console->time; | |
| ms = ns / 1000000; | |
| ns = ns % 1000000; | |
| printf("default: %" PRIu64 ".%06" PRIu64 "ms\n", ms, ns); | |
| - njs_console_time = UINT64_MAX; | |
| + console->time = UINT64_MAX; | |
| } else { | |
| printf("Timer \"default\" doesn’t exist.\n"); | |
| @@ -842,3 +960,107 @@ njs_ext_console_time_end(njs_vm_t *vm, n | |
| return NJS_OK; | |
| } | |
| + | |
| + | |
| +static njs_host_event_t | |
| +njs_console_set_timer(njs_external_ptr_t external, uint64_t delay, | |
| + njs_vm_event_t vm_event) | |
| +{ | |
| + njs_ev_t *ev; | |
| + njs_vm_t *vm; | |
| + nxt_int_t ret; | |
| + njs_console_t *console; | |
| + nxt_lvlhsh_query_t lhq; | |
| + | |
| + if (delay != 0) { | |
| + fprintf(stderr, "njs_console_set_timer(): async timers unsupported\n"); | |
| + return NULL; | |
| + } | |
| + | |
| + console = external; | |
| + vm = console->vm; | |
| + | |
| + ev = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_ev_t)); | |
| + if (nxt_slow_path(ev == NULL)) { | |
| + return NULL; | |
| + } | |
| + | |
| + ev->vm_event = vm_event; | |
| + | |
| + lhq.key.start = (u_char *) &ev->vm_event; | |
| + lhq.key.length = sizeof(njs_vm_event_t); | |
| + lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); | |
| + | |
| + lhq.replace = 0; | |
| + lhq.value = ev; | |
| + lhq.proto = &lvlhsh_proto; | |
| + lhq.pool = vm->mem_cache_pool; | |
| + | |
| + ret = nxt_lvlhsh_insert(&console->events, &lhq); | |
| + if (nxt_slow_path(ret != NXT_OK)) { | |
| + return NULL; | |
| + } | |
| + | |
| + nxt_queue_insert_tail(&console->posted_events, &ev->link); | |
| + | |
| + return (njs_host_event_t) ev; | |
| +} | |
| + | |
| + | |
| +static void | |
| +njs_console_clear_timer(njs_external_ptr_t external, njs_host_event_t event) | |
| +{ | |
| + njs_ev_t *ev; | |
| + nxt_int_t ret; | |
| + njs_console_t *console; | |
| + nxt_lvlhsh_query_t lhq; | |
| + | |
| + ev = event; | |
| + console = external; | |
| + | |
| + lhq.key.start = (u_char *) &ev->vm_event; | |
| + lhq.key.length = sizeof(njs_vm_event_t); | |
| + lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); | |
| + | |
| + lhq.proto = &lvlhsh_proto; | |
| + lhq.pool = console->vm->mem_cache_pool; | |
| + | |
| + if (ev->link.prev != NULL) { | |
| + nxt_queue_remove(&ev->link); | |
| + } | |
| + | |
| + ret = nxt_lvlhsh_delete(&console->events, &lhq); | |
| + if (ret != NXT_OK) { | |
| + fprintf(stderr, "nxt_lvlhsh_delete() failed\n"); | |
| + } | |
| +} | |
| + | |
| + | |
| +static nxt_int_t | |
| +lvlhsh_key_test(nxt_lvlhsh_query_t *lhq, void *data) | |
| +{ | |
| + njs_ev_t *ev; | |
| + | |
| + ev = data; | |
| + | |
| + if (memcmp(&ev->vm_event, lhq->key.start, sizeof(njs_vm_event_t)) == 0) { | |
| + return NXT_OK; | |
| + } | |
| + | |
| + return NXT_DECLINED; | |
| +} | |
| + | |
| + | |
| +static void * | |
| +lvlhsh_pool_alloc(void *pool, size_t size, nxt_uint_t nalloc) | |
| +{ | |
| + return nxt_mem_cache_align(pool, size, size); | |
| +} | |
| + | |
| + | |
| +static void | |
| +lvlhsh_pool_free(void *pool, void *p, size_t size) | |
| +{ | |
| + nxt_mem_cache_free(pool, p); | |
| +} | |
| + | |
| diff --git a/njs/test/njs_expect_test.exp b/njs/test/njs_expect_test.exp | |
| --- a/njs/test/njs_expect_test.exp | |
| +++ b/njs/test/njs_expect_test.exp | |
| @@ -292,6 +292,67 @@ njs_test { | |
| "'й'"} | |
| } | |
| +# Immediate events | |
| + | |
| +njs_test { | |
| + {"var t = setImmediate(console.log, 'a', 'aa')\r\n" | |
| + "undefined\r\n'a' 'aa'"} | |
| +} | |
| + | |
| +njs_test { | |
| + {"var a = 1 + 1; setTimeout(function (x) {a = x}, 0, 'a'); a\r\n" | |
| + "2"} | |
| + {"a\r\n" | |
| + "a\r\n'a'"} | |
| +} | |
| + | |
| +njs_test { | |
| + {"setTimeout(function () {}, 1, 'a')\r\n" | |
| + "njs_console_set_timer(): async timers unsupported"} | |
| +} | |
| + | |
| +njs_test { | |
| + {"var a = 1 + 1; setTimeout(function (x) { setTimeout(function (y) {a = y}, 0, x)}, 0, 'a'); a\r\n" | |
| + "2"} | |
| + {"a\r\n" | |
| + "a\r\n'a'"} | |
| +} | |
| + | |
| +njs_test { | |
| + {"var a = 1 + 1; setImmediate(function (x) { setImmediate(function (y) {a = y}, x)}, 'a'); a\r\n" | |
| + "2"} | |
| + {"a\r\n" | |
| + "a\r\n'a'"} | |
| +} | |
| + | |
| +njs_test { | |
| + {"var i = 0; (function x() { if (i < 10) setImmediate(x); i++; })()\r\n" | |
| + "undefined"} | |
| + {"i\r\n" | |
| + "i\r\n11"} | |
| +} | |
| + | |
| +njs_test { | |
| + {"var a = 0, t = setImmediate(function() {a = 1}); clearTimeout(t)\r\n" | |
| + "undefined"} | |
| + {"a\r\n" | |
| + "a\r\n0"} | |
| +} | |
| + | |
| +njs_test { | |
| + {"var i = 0; (function x() { if (i < 3) setImmediate(x); i++; throw 'Oops';})()\r\n" | |
| + "Oops"} | |
| + {"i\r\n" | |
| + "i\r\n4"} | |
| +} | |
| + | |
| +njs_test { | |
| + {"var i = 0, queue = []; (function x() { if (i < 5) setImmediate(x); queue.push(i++); })()\r\n" | |
| + "undefined"} | |
| + {"queue.toString()\r\n" | |
| + "queue.toString()\r\n'0,1,2,3,4,5'"} | |
| +} | |
| + | |
| # require('fs') | |
| set file [open njs_test_file w] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment