feat(ext/web): Request higher-resolution timer on Windows if user requests setTimeout w/short delay (#19149)

If a timer is requested with <=100ms resolution, request the high-res
timer. Since the default Windows timer period is 15ms, this means a
100ms timer could fire at 115ms (15% late). We assume that timers longer
than 100ms are a reasonable cutoff here.

The high-res timers on Windows are still limited. Unfortuntely this
means that our shortest duration 4ms timers can still be 25% late, but
without a more complex timer system or spinning on the clock itself,
we're somewhat bounded by the OS' scheduler itself.
This commit is contained in:
Matt Mastracci 2023-05-17 13:59:55 -06:00 committed by GitHub
parent 1541c2ac9b
commit ad22336245
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 88 additions and 1 deletions

View file

@ -2,9 +2,9 @@
//! This module helps deno implement timers and performance APIs.
use crate::hr_timer_lock::hr_timer_lock;
use deno_core::error::AnyError;
use deno_core::op;
use deno_core::CancelFuture;
use deno_core::CancelHandle;
use deno_core::OpState;
@ -86,8 +86,24 @@ pub async fn op_sleep(
rid: ResourceId,
) -> Result<bool, AnyError> {
let handle = state.borrow().resource_table.get::<TimerHandle>(rid)?;
// If a timer is requested with <=100ms resolution, request the high-res timer. Since the default
// Windows timer period is 15ms, this means a 100ms timer could fire at 115ms (15% late). We assume that
// timers longer than 100ms are a reasonable cutoff here.
// The high-res timers on Windows are still limited. Unfortuntely this means that our shortest duration 4ms timers
// can still be 25% late, but without a more complex timer system or spinning on the clock itself, we're somewhat
// bounded by the OS' scheduler itself.
let _hr_timer_lock = if millis <= 100 {
Some(hr_timer_lock())
} else {
None
};
let res = tokio::time::sleep(Duration::from_millis(millis))
.or_cancel(handle.0.clone())
.await;
// We release the high-res timer lock here, either by being cancelled or resolving.
Ok(res.is_ok())
}