summaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2021-12-11 15:56:45 +0100
committerGitHub <noreply@github.com>2021-12-11 15:56:45 +0100
commit0dec9b4381e0aa1d4b75ab5837cb75598f19c727 (patch)
tree960f9bd48c5b733317c5592d9843f315883413f8 /runtime
parent13d7d5722771bf8c4de7083dc0f964dfffcb318a (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.rs11
-rw-r--r--runtime/ops/os.rs21
-rw-r--r--runtime/ops/worker_host.rs9
-rw-r--r--runtime/web_worker.rs6
-rw-r--r--runtime/worker.rs13
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)]