summaryrefslogtreecommitdiff
path: root/ext/web/timers.rs
diff options
context:
space:
mode:
authorMatt Mastracci <matthew@mastracci.com>2023-05-17 13:59:55 -0600
committerGitHub <noreply@github.com>2023-05-17 13:59:55 -0600
commitad223362451688c13a4441563210f58bdb046a78 (patch)
tree81e041febfdcd83040f3b50bfad247b53a70c3f6 /ext/web/timers.rs
parent1541c2ac9b9b4380adeedad10ed87682c0fc6d49 (diff)
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.
Diffstat (limited to 'ext/web/timers.rs')
-rw-r--r--ext/web/timers.rs18
1 files changed, 17 insertions, 1 deletions
diff --git a/ext/web/timers.rs b/ext/web/timers.rs
index 252cd4ad4..54e185abd 100644
--- a/ext/web/timers.rs
+++ b/ext/web/timers.rs
@@ -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())
}