diff options
author | Bartek IwaĆczuk <biwanczuk@gmail.com> | 2021-05-26 21:07:12 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-26 21:07:12 +0200 |
commit | e5beb800c94099852964d482a32a13f5c29ec147 (patch) | |
tree | 1ad89cc15efa84efe690e05b18d5827e1983dbca /core/runtime.rs | |
parent | e9edd7e14d9d78f03c5f2e67fcc44e4dbaab8f2c (diff) |
refactor: move JsRuntimeInspector to deno_core (#10763)
This commit moves implementation of "JsRuntimeInspector" to "deno_core" crate.
To achieve that following changes were made:
* "Worker" and "WebWorker" no longer own instance of "JsRuntimeInspector",
instead it is now owned by "deno_core::JsRuntime".
* Consequently polling of inspector is no longer done in "Worker"/"WebWorker",
instead it's done in "deno_core::JsRuntime::poll_event_loop".
* "deno_core::JsRuntime::poll_event_loop" and "deno_core::JsRuntime::run_event_loop",
now accept "wait_for_inspector" boolean that tells if event loop should still be
"pending" if there are active inspector sessions - this change fixes the problem
that inspector disconnects from the frontend and process exits once the code has
stopped executing.
Diffstat (limited to 'core/runtime.rs')
-rw-r--r-- | core/runtime.rs | 59 |
1 files changed, 51 insertions, 8 deletions
diff --git a/core/runtime.rs b/core/runtime.rs index 0dbca0ae3..428add8e3 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -8,6 +8,7 @@ use crate::error::generic_error; use crate::error::AnyError; use crate::error::ErrWithV8Handle; use crate::error::JsError; +use crate::inspector::JsRuntimeInspector; use crate::module_specifier::ModuleSpecifier; use crate::modules::ModuleId; use crate::modules::ModuleLoadId; @@ -23,6 +24,7 @@ use crate::OpState; use crate::PromiseId; use futures::channel::mpsc; use futures::future::poll_fn; +use futures::future::FutureExt; use futures::stream::FuturesUnordered; use futures::stream::StreamExt; use futures::task::AtomicWaker; @@ -75,6 +77,7 @@ pub struct JsRuntime { // This is an Option<OwnedIsolate> instead of just OwnedIsolate to workaround // an safety issue with SnapshotCreator. See JsRuntime::drop. v8_isolate: Option<v8::OwnedIsolate>, + inspector: Option<Box<JsRuntimeInspector>>, snapshot_creator: Option<v8::SnapshotCreator>, has_snapshotted: bool, allocations: IsolateAllocations, @@ -113,6 +116,10 @@ pub(crate) struct JsRuntimeState { impl Drop for JsRuntime { fn drop(&mut self) { + // The Isolate object must outlive the Inspector object, but this is + // currently not enforced by the type system. + self.inspector.take(); + if let Some(creator) = self.snapshot_creator.take() { // TODO(ry): in rusty_v8, `SnapShotCreator::get_owned_isolate()` returns // a `struct OwnedIsolate` which is not actually owned, hence the need @@ -198,6 +205,9 @@ pub struct RuntimeOptions { /// V8 platform instance to use. Used when Deno initializes V8 /// (which it only does once), otherwise it's silenty dropped. pub v8_platform: Option<v8::UniquePtr<v8::Platform>>, + + /// Create a V8 inspector and attach to the runtime. + pub attach_inspector: bool, } impl JsRuntime { @@ -258,6 +268,14 @@ impl JsRuntime { (isolate, None) }; + let maybe_inspector = if options.attach_inspector { + let inspector = + JsRuntimeInspector::new(&mut isolate, global_context.clone()); + Some(inspector) + } else { + None + }; + let loader = options .module_loader .unwrap_or_else(|| Rc::new(NoopModuleLoader)); @@ -298,6 +316,7 @@ impl JsRuntime { let mut js_runtime = Self { v8_isolate: Some(isolate), + inspector: maybe_inspector, snapshot_creator: maybe_snapshot_creator, has_snapshotted: false, allocations: IsolateAllocations::default(), @@ -328,6 +347,10 @@ impl JsRuntime { self.v8_isolate.as_mut().unwrap() } + pub fn inspector(&mut self) -> Option<&mut Box<JsRuntimeInspector>> { + self.inspector.as_mut() + } + pub fn handle_scope(&mut self) -> v8::HandleScope { let context = self.global_context(); v8::HandleScope::with_context(self.v8_isolate(), context) @@ -568,15 +591,26 @@ impl JsRuntime { /// This future resolves when: /// - there are no more pending dynamic imports /// - there are no more pending ops - pub async fn run_event_loop(&mut self) -> Result<(), AnyError> { - poll_fn(|cx| self.poll_event_loop(cx)).await + /// - there are no more active inspector sessions (only if `wait_for_inspector` is set to true) + pub async fn run_event_loop( + &mut self, + wait_for_inspector: bool, + ) -> Result<(), AnyError> { + poll_fn(|cx| self.poll_event_loop(cx, wait_for_inspector)).await } /// Runs a single tick of event loop + /// + /// If `wait_for_inspector` is set to true event loop + /// will return `Poll::Pending` if there are active inspector sessions. pub fn poll_event_loop( &mut self, cx: &mut Context, + wait_for_inspector: bool, ) -> Poll<Result<(), AnyError>> { + // We always poll the inspector if it exists. + let _ = self.inspector().map(|i| i.poll_unpin(cx)); + let state_rc = Self::state(self.v8_isolate()); let module_map_rc = Self::module_map(self.v8_isolate()); { @@ -617,12 +651,21 @@ impl JsRuntime { let has_pending_dyn_module_evaluation = !state.pending_dyn_mod_evaluate.is_empty(); let has_pending_module_evaluation = state.pending_mod_evaluate.is_some(); + let inspector_has_active_sessions = self + .inspector + .as_ref() + .map(|i| i.has_active_sessions()) + .unwrap_or(false); if !has_pending_ops && !has_pending_dyn_imports && !has_pending_dyn_module_evaluation && !has_pending_module_evaluation { + if wait_for_inspector && inspector_has_active_sessions { + return Poll::Pending; + } + return Poll::Ready(Ok(())); } @@ -1562,7 +1605,7 @@ pub mod tests { "#, ) .unwrap(); - if let Poll::Ready(Err(_)) = runtime.poll_event_loop(&mut cx) { + if let Poll::Ready(Err(_)) = runtime.poll_event_loop(&mut cx, false) { unreachable!(); } }); @@ -1588,7 +1631,7 @@ pub mod tests { include_str!("encode_decode_test.js"), ) .unwrap(); - if let Poll::Ready(Err(_)) = runtime.poll_event_loop(&mut cx) { + if let Poll::Ready(Err(_)) = runtime.poll_event_loop(&mut cx, false) { unreachable!(); } }); @@ -1604,7 +1647,7 @@ pub mod tests { include_str!("serialize_deserialize_test.js"), ) .unwrap(); - if let Poll::Ready(Err(_)) = runtime.poll_event_loop(&mut cx) { + if let Poll::Ready(Err(_)) = runtime.poll_event_loop(&mut cx, false) { unreachable!(); } }); @@ -1637,7 +1680,7 @@ pub mod tests { include_str!("error_builder_test.js"), ) .unwrap(); - if let Poll::Ready(Err(_)) = runtime.poll_event_loop(&mut cx) { + if let Poll::Ready(Err(_)) = runtime.poll_event_loop(&mut cx, false) { unreachable!(); } }); @@ -1817,7 +1860,7 @@ pub mod tests { .unwrap(); runtime.mod_evaluate(module_id); - futures::executor::block_on(runtime.run_event_loop()).unwrap(); + futures::executor::block_on(runtime.run_event_loop(false)).unwrap(); let _snapshot = runtime.snapshot(); } @@ -1896,7 +1939,7 @@ main(); at async error_async_stack.js:4:5 at async error_async_stack.js:10:5"#; - match runtime.poll_event_loop(cx) { + match runtime.poll_event_loop(cx, false) { Poll::Ready(Err(e)) => { assert_eq!(e.to_string(), expected_error); } |