diff options
-rw-r--r-- | core/runtime.rs | 119 |
1 files changed, 72 insertions, 47 deletions
diff --git a/core/runtime.rs b/core/runtime.rs index 6a3d694e6..d80518de6 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -825,7 +825,10 @@ impl JsRuntime { // TODO(andreubotella) The event loop will spin as long as there are pending // background tasks. We should look into having V8 notify us when a // background task is done. - if state.have_unpolled_ops || has_pending_background_tasks { + if state.have_unpolled_ops + || has_pending_background_tasks + || has_tick_scheduled + { state.waker.wake(); } @@ -834,6 +837,7 @@ impl JsRuntime { || has_pending_dyn_imports || has_pending_dyn_module_evaluation || has_pending_background_tasks + || has_tick_scheduled { // pass, will be polled again } else { @@ -846,6 +850,7 @@ impl JsRuntime { if has_pending_refed_ops || has_pending_dyn_imports || has_pending_background_tasks + || has_tick_scheduled { // pass, will be polled again } else if state.dyn_module_evaluate_idle_counter >= 1 { @@ -2527,39 +2532,40 @@ assertEquals(1, notify_return_value); 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(¯otask); + #[test] + fn test_has_tick_scheduled() { + use futures::task::ArcWake; - let next_tick = Arc::new(AtomicUsize::default()); - let next_tick_ = Arc::clone(&next_tick); + let macrotask = Arc::new(AtomicUsize::default()); + let macrotask_ = Arc::clone(¯otask); - let op_macrotask = move |_: &mut OpState, _: (), _: ()| { - macrotask_.fetch_add(1, Ordering::Relaxed); - Ok(()) - }; + let next_tick = Arc::new(AtomicUsize::default()); + let next_tick_ = Arc::clone(&next_tick); - let op_next_tick = move |_: &mut OpState, _: (), _: ()| { - next_tick_.fetch_add(1, Ordering::Relaxed); - Ok(()) - }; + let op_macrotask = move |_: &mut OpState, _: (), _: ()| { + macrotask_.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 op_next_tick = move |_: &mut OpState, _: (), _: ()| { + next_tick_.fetch_add(1, Ordering::Relaxed); + Ok(()) + }; - let mut runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![extension], - ..Default::default() - }); + let extension = Extension::builder() + .ops(vec![("op_macrotask", op_sync(op_macrotask))]) + .ops(vec![("op_next_tick", op_sync(op_next_tick))]) + .build(); - runtime - .execute_script( - "has_tick_scheduled.js", - r#" + 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. @@ -2567,25 +2573,44 @@ assertEquals(1, notify_return_value); 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(())) - )); - }); + ) + .unwrap(); + + struct ArcWakeImpl(Arc<AtomicUsize>); + impl ArcWake for ArcWakeImpl { + fn wake_by_ref(arc_self: &Arc<Self>) { + arc_self.0.fetch_add(1, Ordering::Relaxed); + } + } + + let awoken_times = Arc::new(AtomicUsize::new(0)); + let waker = + futures::task::waker(Arc::new(ArcWakeImpl(awoken_times.clone()))); + let cx = &mut Context::from_waker(&waker); + + 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_eq!(awoken_times.swap(0, Ordering::Relaxed), 1); + assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending)); + assert_eq!(awoken_times.swap(0, Ordering::Relaxed), 1); + assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending)); + assert_eq!(awoken_times.swap(0, Ordering::Relaxed), 1); + assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending)); + assert_eq!(awoken_times.swap(0, Ordering::Relaxed), 1); + + 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_eq!(awoken_times.load(Ordering::Relaxed), 0); + assert!(matches!( + runtime.poll_event_loop(cx, false), + Poll::Ready(Ok(())) + )); + assert_eq!(awoken_times.load(Ordering::Relaxed), 0); } #[test] |