summaryrefslogtreecommitdiff
path: root/core/runtime.rs
diff options
context:
space:
mode:
authorBen Noordhuis <info@bnoordhuis.nl>2021-11-19 14:01:30 +0100
committerGitHub <noreply@github.com>2021-11-19 14:01:30 +0100
commit22dcf8223041feb985c025338b5d60eae9357d31 (patch)
tree97f78e5e4af6252b69ddac1eb41d874d4cd8e684 /core/runtime.rs
parentc82ce7413366c49ae44128797f91fe44113c5e8c (diff)
fix(core): keep event loop alive if there are ticks scheduled (#12814)
Co-authored-by: Bartek IwaƄczuk <biwanczuk@gmail.com>
Diffstat (limited to 'core/runtime.rs')
-rw-r--r--core/runtime.rs64
1 files changed, 63 insertions, 1 deletions
diff --git a/core/runtime.rs b/core/runtime.rs
index 5d8e9231c..db59b092d 100644
--- a/core/runtime.rs
+++ b/core/runtime.rs
@@ -802,13 +802,13 @@ impl JsRuntime {
let module_map = module_map_rc.borrow();
let has_pending_ops = !state.pending_ops.is_empty();
-
let has_pending_dyn_imports = module_map.has_pending_dynamic_imports();
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 has_pending_background_tasks =
self.v8_isolate().has_pending_background_tasks();
+ let has_tick_scheduled = state.has_tick_scheduled;
let inspector_has_active_sessions = self
.inspector
.as_ref()
@@ -820,6 +820,7 @@ impl JsRuntime {
&& !has_pending_dyn_module_evaluation
&& !has_pending_module_evaluation
&& !has_pending_background_tasks
+ && !has_tick_scheduled
{
if wait_for_inspector && inspector_has_active_sessions {
return Poll::Pending;
@@ -2464,4 +2465,65 @@ assertEquals(1, notify_return_value);
assert_eq!(state.js_macrotask_cbs.len(), 2);
assert_eq!(state.js_nexttick_cbs.len(), 2);
}
+
+ #[tokio::test]
+ async fn test_has_tick_scheduled() {
+ run_in_task(|cx| {
+ let macrotask = Arc::new(AtomicUsize::default());
+ let macrotask_ = Arc::clone(&macrotask);
+
+ let next_tick = Arc::new(AtomicUsize::default());
+ let next_tick_ = Arc::clone(&next_tick);
+
+ let op_macrotask = move |_: &mut OpState, _: (), _: ()| {
+ macrotask_.fetch_add(1, Ordering::Relaxed);
+ Ok(())
+ };
+
+ let op_next_tick = move |_: &mut OpState, _: (), _: ()| {
+ next_tick_.fetch_add(1, Ordering::Relaxed);
+ Ok(())
+ };
+
+ let extension = Extension::builder()
+ .ops(vec![("op_macrotask", op_sync(op_macrotask))])
+ .ops(vec![("op_next_tick", op_sync(op_next_tick))])
+ .build();
+
+ let mut runtime = JsRuntime::new(RuntimeOptions {
+ extensions: vec![extension],
+ ..Default::default()
+ });
+
+ runtime
+ .execute_script(
+ "has_tick_scheduled.js",
+ r#"
+ Deno.core.setMacrotaskCallback(() => {
+ Deno.core.opSync("op_macrotask");
+ return true; // We're done.
+ });
+ Deno.core.setNextTickCallback(() => Deno.core.opSync("op_next_tick"));
+ Deno.core.setHasTickScheduled(true);
+ "#,
+ )
+ .unwrap();
+ assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending));
+ assert_eq!(1, macrotask.load(Ordering::Relaxed));
+ assert_eq!(1, next_tick.load(Ordering::Relaxed));
+ assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending));
+ assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending));
+ assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending));
+ let state_rc = JsRuntime::state(runtime.v8_isolate());
+ state_rc.borrow_mut().has_tick_scheduled = false;
+ assert!(matches!(
+ runtime.poll_event_loop(cx, false),
+ Poll::Ready(Ok(()))
+ ));
+ assert!(matches!(
+ runtime.poll_event_loop(cx, false),
+ Poll::Ready(Ok(()))
+ ));
+ });
+ }
}