mirror of
https://github.com/denoland/deno.git
synced 2024-11-25 15:29:32 -05:00
fix(core): Wake up the runtime if there are ticks scheduled (#12933)
This commit is contained in:
parent
18a63dd977
commit
48c57001c8
1 changed files with 72 additions and 47 deletions
119
core/runtime.rs
119
core/runtime.rs
|
@ -825,7 +825,10 @@ impl JsRuntime {
|
||||||
// TODO(andreubotella) The event loop will spin as long as there are pending
|
// 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 tasks. We should look into having V8 notify us when a
|
||||||
// background task is done.
|
// 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();
|
state.waker.wake();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -834,6 +837,7 @@ impl JsRuntime {
|
||||||
|| has_pending_dyn_imports
|
|| has_pending_dyn_imports
|
||||||
|| has_pending_dyn_module_evaluation
|
|| has_pending_dyn_module_evaluation
|
||||||
|| has_pending_background_tasks
|
|| has_pending_background_tasks
|
||||||
|
|| has_tick_scheduled
|
||||||
{
|
{
|
||||||
// pass, will be polled again
|
// pass, will be polled again
|
||||||
} else {
|
} else {
|
||||||
|
@ -846,6 +850,7 @@ impl JsRuntime {
|
||||||
if has_pending_refed_ops
|
if has_pending_refed_ops
|
||||||
|| has_pending_dyn_imports
|
|| has_pending_dyn_imports
|
||||||
|| has_pending_background_tasks
|
|| has_pending_background_tasks
|
||||||
|
|| has_tick_scheduled
|
||||||
{
|
{
|
||||||
// pass, will be polled again
|
// pass, will be polled again
|
||||||
} else if state.dyn_module_evaluate_idle_counter >= 1 {
|
} 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);
|
assert_eq!(state.js_nexttick_cbs.len(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[test]
|
||||||
async fn test_has_tick_scheduled() {
|
fn test_has_tick_scheduled() {
|
||||||
run_in_task(|cx| {
|
use futures::task::ArcWake;
|
||||||
let macrotask = Arc::new(AtomicUsize::default());
|
|
||||||
let macrotask_ = Arc::clone(¯otask);
|
|
||||||
|
|
||||||
let next_tick = Arc::new(AtomicUsize::default());
|
let macrotask = Arc::new(AtomicUsize::default());
|
||||||
let next_tick_ = Arc::clone(&next_tick);
|
let macrotask_ = Arc::clone(¯otask);
|
||||||
|
|
||||||
let op_macrotask = move |_: &mut OpState, _: (), _: ()| {
|
let next_tick = Arc::new(AtomicUsize::default());
|
||||||
macrotask_.fetch_add(1, Ordering::Relaxed);
|
let next_tick_ = Arc::clone(&next_tick);
|
||||||
Ok(())
|
|
||||||
};
|
|
||||||
|
|
||||||
let op_next_tick = move |_: &mut OpState, _: (), _: ()| {
|
let op_macrotask = move |_: &mut OpState, _: (), _: ()| {
|
||||||
next_tick_.fetch_add(1, Ordering::Relaxed);
|
macrotask_.fetch_add(1, Ordering::Relaxed);
|
||||||
Ok(())
|
Ok(())
|
||||||
};
|
};
|
||||||
|
|
||||||
let extension = Extension::builder()
|
let op_next_tick = move |_: &mut OpState, _: (), _: ()| {
|
||||||
.ops(vec![("op_macrotask", op_sync(op_macrotask))])
|
next_tick_.fetch_add(1, Ordering::Relaxed);
|
||||||
.ops(vec![("op_next_tick", op_sync(op_next_tick))])
|
Ok(())
|
||||||
.build();
|
};
|
||||||
|
|
||||||
let mut runtime = JsRuntime::new(RuntimeOptions {
|
let extension = Extension::builder()
|
||||||
extensions: vec![extension],
|
.ops(vec![("op_macrotask", op_sync(op_macrotask))])
|
||||||
..Default::default()
|
.ops(vec![("op_next_tick", op_sync(op_next_tick))])
|
||||||
});
|
.build();
|
||||||
|
|
||||||
runtime
|
let mut runtime = JsRuntime::new(RuntimeOptions {
|
||||||
.execute_script(
|
extensions: vec![extension],
|
||||||
"has_tick_scheduled.js",
|
..Default::default()
|
||||||
r#"
|
});
|
||||||
|
|
||||||
|
runtime
|
||||||
|
.execute_script(
|
||||||
|
"has_tick_scheduled.js",
|
||||||
|
r#"
|
||||||
Deno.core.setMacrotaskCallback(() => {
|
Deno.core.setMacrotaskCallback(() => {
|
||||||
Deno.core.opSync("op_macrotask");
|
Deno.core.opSync("op_macrotask");
|
||||||
return true; // We're done.
|
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.setNextTickCallback(() => Deno.core.opSync("op_next_tick"));
|
||||||
Deno.core.setHasTickScheduled(true);
|
Deno.core.setHasTickScheduled(true);
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending));
|
|
||||||
assert_eq!(1, macrotask.load(Ordering::Relaxed));
|
struct ArcWakeImpl(Arc<AtomicUsize>);
|
||||||
assert_eq!(1, next_tick.load(Ordering::Relaxed));
|
impl ArcWake for ArcWakeImpl {
|
||||||
assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending));
|
fn wake_by_ref(arc_self: &Arc<Self>) {
|
||||||
assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending));
|
arc_self.0.fetch_add(1, Ordering::Relaxed);
|
||||||
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!(
|
let awoken_times = Arc::new(AtomicUsize::new(0));
|
||||||
runtime.poll_event_loop(cx, false),
|
let waker =
|
||||||
Poll::Ready(Ok(()))
|
futures::task::waker(Arc::new(ArcWakeImpl(awoken_times.clone())));
|
||||||
));
|
let cx = &mut Context::from_waker(&waker);
|
||||||
assert!(matches!(
|
|
||||||
runtime.poll_event_loop(cx, false),
|
assert!(matches!(runtime.poll_event_loop(cx, false), Poll::Pending));
|
||||||
Poll::Ready(Ok(()))
|
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]
|
#[test]
|
||||||
|
|
Loading…
Reference in a new issue