diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2021-12-11 15:56:45 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-11 15:56:45 +0100 |
commit | 0dec9b4381e0aa1d4b75ab5837cb75598f19c727 (patch) | |
tree | 960f9bd48c5b733317c5592d9843f315883413f8 /runtime | |
parent | 13d7d5722771bf8c4de7083dc0f964dfffcb318a (diff) |
fix: op_set_exit_code (#13034)
Fixes "op_set_exit_code" by sharing a single "Arc" between
all workers (via "op state") instead of having a "global" value stored in
"deno_runtime" crate. As a consequence setting an exit code is always
scoped to a tree of workers, instead of being overridable if there are
multiple worker tree (like in "deno test --jobs" subcommand).
Refactored "cli/main.rs" functions to return "Result<i32, AnyError>" instead
of "Result<(), AnyError>" so they can return exit code.
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/lib.rs | 11 | ||||
-rw-r--r-- | runtime/ops/os.rs | 21 | ||||
-rw-r--r-- | runtime/ops/worker_host.rs | 9 | ||||
-rw-r--r-- | runtime/web_worker.rs | 6 | ||||
-rw-r--r-- | runtime/worker.rs | 13 |
5 files changed, 41 insertions, 19 deletions
diff --git a/runtime/lib.rs b/runtime/lib.rs index ad4a790da..58de3725b 100644 --- a/runtime/lib.rs +++ b/runtime/lib.rs @@ -1,7 +1,5 @@ // Copyright 2018-2021 the Deno authors. All rights reserved. MIT license. -use std::sync::atomic::AtomicI32; - pub use deno_broadcast_channel; pub use deno_console; pub use deno_core; @@ -32,12 +30,3 @@ pub mod worker; mod worker_bootstrap; pub use worker_bootstrap::BootstrapOptions; - -// The global may not be very elegant but: -// -// 1. op_exit() calls std::process::exit() so there is not much point storing -// the exit code in runtime state -// -// 2. storing it in runtime state makes retrieving it again in cli/main.rs -// unduly complicated -pub static EXIT_CODE: AtomicI32 = AtomicI32::new(0); diff --git a/runtime/ops/os.rs b/runtime/ops/os.rs index 8e96de75d..81f8a529e 100644 --- a/runtime/ops/os.rs +++ b/runtime/ops/os.rs @@ -10,9 +10,11 @@ use deno_core::OpState; use serde::Serialize; use std::collections::HashMap; use std::env; +use std::sync::atomic::AtomicI32; use std::sync::atomic::Ordering::Relaxed; +use std::sync::Arc; -pub fn init() -> Extension { +pub fn init(maybe_exit_code: Option<Arc<AtomicI32>>) -> Extension { Extension::builder() .ops(vec![ ("op_exit", op_sync(op_exit)), @@ -27,6 +29,11 @@ pub fn init() -> Extension { ("op_set_exit_code", op_sync(op_set_exit_code)), ("op_system_memory_info", op_sync(op_system_memory_info)), ]) + .state(move |state| { + let exit_code = maybe_exit_code.clone().unwrap_or_default(); + state.put::<Arc<AtomicI32>>(exit_code); + Ok(()) + }) .build() } @@ -97,13 +104,17 @@ fn op_delete_env( Ok(()) } -fn op_set_exit_code(_: &mut OpState, code: i32, _: ()) -> Result<(), AnyError> { - crate::EXIT_CODE.store(code, Relaxed); +fn op_set_exit_code( + state: &mut OpState, + code: i32, + _: (), +) -> Result<(), AnyError> { + state.borrow_mut::<Arc<AtomicI32>>().store(code, Relaxed); Ok(()) } -fn op_exit(_: &mut OpState, _: (), _: ()) -> Result<(), AnyError> { - let code = crate::EXIT_CODE.load(Relaxed); +fn op_exit(state: &mut OpState, _: (), _: ()) -> Result<(), AnyError> { + let code = state.borrow::<Arc<AtomicI32>>().load(Relaxed); std::process::exit(code) } diff --git a/runtime/ops/worker_host.rs b/runtime/ops/worker_host.rs index e9eb380e0..f290b3833 100644 --- a/runtime/ops/worker_host.rs +++ b/runtime/ops/worker_host.rs @@ -23,6 +23,7 @@ use log::debug; use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; +use std::sync::atomic::AtomicI32; use std::sync::Arc; use std::thread::JoinHandle; @@ -34,6 +35,7 @@ pub struct CreateWebWorkerArgs { pub main_module: ModuleSpecifier, pub use_deno_namespace: bool, pub worker_type: WebWorkerType, + pub maybe_exit_code: Option<Arc<AtomicI32>>, } pub type CreateWebWorkerCb = dyn Fn(CreateWebWorkerArgs) -> (WebWorker, SendableWebWorkerHandle) @@ -166,7 +168,11 @@ fn op_create_worker( parent_permissions.clone() }; let parent_permissions = parent_permissions.clone(); - + // `try_borrow` here, because worker might have been started without + // access to `Deno` namespace. + // TODO(bartlomieju): can a situation happen when parent doesn't + // have access to `exit_code` but the child does? + let maybe_exit_code = state.try_borrow::<Arc<AtomicI32>>().cloned(); let worker_id = state.take::<WorkerId>(); let create_module_loader = state.take::<CreateWebWorkerCbHolder>(); state.put::<CreateWebWorkerCbHolder>(create_module_loader.clone()); @@ -199,6 +205,7 @@ fn op_create_worker( main_module: module_specifier.clone(), use_deno_namespace, worker_type, + maybe_exit_code, }); // Send thread safe handle from newly created worker to host thread diff --git a/runtime/web_worker.rs b/runtime/web_worker.rs index f5df2f58b..24306fab5 100644 --- a/runtime/web_worker.rs +++ b/runtime/web_worker.rs @@ -38,6 +38,7 @@ use std::cell::RefCell; use std::fmt; use std::rc::Rc; use std::sync::atomic::AtomicBool; +use std::sync::atomic::AtomicI32; use std::sync::atomic::Ordering; use std::sync::Arc; use std::task::Context; @@ -323,6 +324,7 @@ pub struct WebWorkerOptions { pub broadcast_channel: InMemoryBroadcastChannel, pub shared_array_buffer_store: Option<SharedArrayBufferStore>, pub compiled_wasm_module_store: Option<CompiledWasmModuleStore>, + pub maybe_exit_code: Option<Arc<AtomicI32>>, } impl WebWorker { @@ -408,7 +410,9 @@ impl WebWorker { unstable, options.unsafely_ignore_certificate_errors.clone(), ), - ops::os::init(), + ops::os::init(Some(options.maybe_exit_code.expect( + "Worker has access to OS ops but exit code was not passed.", + ))), ops::permissions::init(), ops::process::init(), ops::signal::init(), diff --git a/runtime/worker.rs b/runtime/worker.rs index 3a16b7b55..545128dff 100644 --- a/runtime/worker.rs +++ b/runtime/worker.rs @@ -25,6 +25,8 @@ use deno_web::BlobStore; use log::debug; use std::pin::Pin; use std::rc::Rc; +use std::sync::atomic::AtomicI32; +use std::sync::atomic::Ordering::Relaxed; use std::sync::Arc; use std::task::Context; use std::task::Poll; @@ -135,7 +137,7 @@ impl MainWorker { unstable, options.unsafely_ignore_certificate_errors.clone(), ), - ops::os::init(), + ops::os::init(None), ops::permissions::init(), ops::process::init(), ops::signal::init(), @@ -289,6 +291,15 @@ impl MainWorker { }; } } + + /// Return exit code set by the executed code (either in main worker + /// or one of child web workers). + pub fn get_exit_code(&mut self) -> i32 { + let op_state_rc = self.js_runtime.op_state(); + let op_state = op_state_rc.borrow(); + let exit_code = op_state.borrow::<Arc<AtomicI32>>().load(Relaxed); + exit_code + } } #[cfg(test)] |