diff --git a/CMakeLists.txt b/CMakeLists.txt index 004c42d..9249478 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -206,6 +206,14 @@ target_link_libraries( hex ) +if(MSVC) + target_compile_options( + bare + PRIVATE + /experimental:c11atomics + ) +endif() + add_library(bare_shared SHARED) set_target_properties( diff --git a/README.md b/README.md index 760d08a..3dca0db 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ An object containing the version strings of Bare and its dependencies. Immediately terminate the process or current thread with an exit status of `code` which defaults to `Bare.exitCode`. -#### `Bare.suspend()` +#### `Bare.suspend([linger])` Suspend the process and all threads. This will emit a `suspend` event signalling that all work should stop immediately. When all work has stopped and the process would otherwise exit, an `idle` event will be emitted. If the process is not resumed from an `idle` event listener and no additional work is scheduled, the loop will block until the process is resumed. If additional work is scheduled from an `idle` event, the `idle` event will be emitted again once all work has stopped unless the process was resumed. @@ -122,7 +122,7 @@ Emitted after the process or current thread has terminated and just before the J > Bare.prependListener('teardown', () => { ... }) > ``` -#### `Bare.on('suspend')` +#### `Bare.on('suspend', linger)` Emitted when the process or current thread is suspended. Any in-progress or outstanding work, such as network activity or file system access, should be deferred, cancelled, or paused when the `suspend` event is emitted and no additional work may be scheduled. diff --git a/include/bare.h b/include/bare.h index 5acf17e..0b57630 100644 --- a/include/bare.h +++ b/include/bare.h @@ -18,7 +18,7 @@ typedef struct bare_options_s bare_options_t; typedef void (*bare_before_exit_cb)(bare_t *); typedef void (*bare_exit_cb)(bare_t *); typedef void (*bare_teardown_cb)(bare_t *); -typedef void (*bare_suspend_cb)(bare_t *); +typedef void (*bare_suspend_cb)(bare_t *, int linger); typedef void (*bare_idle_cb)(bare_t *); typedef void (*bare_resume_cb)(bare_t *); typedef void (*bare_thread_cb)(bare_t *, js_env_t *); @@ -77,7 +77,7 @@ bare_run (bare_t *bare); * process. It's safe to call this function from any thread. */ int -bare_suspend (bare_t *bare); +bare_suspend (bare_t *bare, int linger); /** * Resume the process as soon as possible. If the process is not yet idle after diff --git a/src/bare.c b/src/bare.c index 872e1b5..c695006 100644 --- a/src/bare.c +++ b/src/bare.c @@ -109,7 +109,9 @@ bare_run (bare_t *bare) { } int -bare_suspend (bare_t *bare) { +bare_suspend (bare_t *bare, int linger) { + bare->process.runtime->linger = linger; + return uv_async_send(&bare->process.runtime->signals.suspend); } diff --git a/src/bare.js b/src/bare.js index b9c0427..6d06f59 100644 --- a/src/bare.js +++ b/src/bare.js @@ -123,8 +123,8 @@ class Bare extends EventEmitter { function noop () {} } - suspend () { - bare.suspend() + suspend (linger = 0) { + bare.suspend(linger) } resume () { @@ -169,10 +169,10 @@ class Bare extends EventEmitter { this.emit('teardown') } - _onsuspend () { + _onsuspend (linger) { this.suspended = true - this.emit('suspend') + this.emit('suspend', linger) } _onidle () { diff --git a/src/runtime.c b/src/runtime.c index ef4f90a..f0d20b3 100644 --- a/src/runtime.c +++ b/src/runtime.c @@ -47,7 +47,7 @@ bare_runtime_on_uncaught_exception (js_env_t *env, js_value_t *error, void *data err = js_get_global(env, &global); assert(err == 0); - js_call_function(env, global, fn, 1, (js_value_t *[]){error}, NULL); + js_call_function(env, global, fn, 1, &error, NULL); err = js_close_handle_scope(env, scope); assert(err == 0); @@ -270,14 +270,18 @@ bare_runtime_on_suspend (bare_runtime_t *runtime) { err = js_get_global(env, &global); assert(err == 0); - js_call_function(env, global, fn, 0, NULL, NULL); + js_value_t *linger; + err = js_create_int32(env, runtime->linger, &linger); + assert(err == 0); + + js_call_function(env, global, fn, 1, &linger, NULL); err = js_close_handle_scope(env, scope); assert(err == 0); if (bare_runtime_is_main_thread(runtime)) { if (runtime->process->on_suspend) { - runtime->process->on_suspend((bare_t *) runtime->process); + runtime->process->on_suspend((bare_t *) runtime->process, runtime->linger); } } } @@ -675,9 +679,20 @@ bare_runtime_suspend (js_env_t *env, js_callback_info_t *info) { bare_runtime_t *runtime; - err = js_get_callback_info(env, info, NULL, NULL, NULL, (void **) &runtime); + js_value_t *argv[1]; + size_t argc = 1; + + err = js_get_callback_info(env, info, &argc, argv, NULL, (void **) &runtime); + assert(err == 0); + + assert(argc == 1); + + int32_t linger; + err = js_get_value_int32(env, argv[0], &linger); assert(err == 0); + runtime->linger = linger; + uv_ref((uv_handle_t *) &runtime->signals.suspend); err = uv_async_send(&runtime->process->runtime->signals.suspend); @@ -886,6 +901,7 @@ bare_runtime_setup (uv_loop_t *loop, bare_process_t *process, bare_runtime_t *ru runtime->suspended = false; runtime->exiting = false; runtime->terminated = false; + runtime->linger = 0; err = uv_async_init(runtime->loop, &runtime->signals.suspend, bare_runtime_on_suspend_signal); assert(err == 0); diff --git a/src/types.h b/src/types.h index f9837a2..4560a95 100644 --- a/src/types.h +++ b/src/types.h @@ -2,6 +2,7 @@ #define BARE_TYPES_H #include +#include #include #include @@ -33,6 +34,8 @@ struct bare_runtime_s { bool suspended; bool exiting; bool terminated; + + atomic_int linger; }; struct bare_process_s { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ebee961..c633f3d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -22,6 +22,7 @@ list(APPEND tests suspend-resume-from-thread.js suspend-resume-on-idle.js suspend-resume-on-suspend.js + suspend-resume-with-linger.js thread.js thread-join.js thread-source.js diff --git a/test/suspend-resume-with-linger.js b/test/suspend-resume-with-linger.js new file mode 100644 index 0000000..44f9e50 --- /dev/null +++ b/test/suspend-resume-with-linger.js @@ -0,0 +1,17 @@ +/* global Bare */ +const assert = require('bare-assert') + +Bare + .on('suspend', (linger) => { + console.log('emit suspend') + assert(linger === 1000) + }) + .on('idle', () => { + assert(false, 'Should not idle') + }) + .on('resume', () => { + console.log('emit resume') + }) + +Bare.suspend(1000) +Bare.resume()