deno_web 0.142.0

Collection of Web APIs
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
#[cfg(target_os = "windows")]
mod windows {
  use std::marker::PhantomData;
  use std::sync::atomic::AtomicU32;

  pub(crate) struct HrTimerLock {
    pub(super) _unconstructable: PhantomData<()>,
  }

  /// Decrease the reference count of the HR timer on drop.
  impl Drop for HrTimerLock {
    fn drop(&mut self) {
      dec_ref();
    }
  }

  /// Maintains the HR timer refcount. This should be more than sufficient as 2^32 timers would be
  /// an impossible situation, and if it does somehow happen, the worst case is that we'll disable
  /// the high-res timer when we shouldn't (and things would eventually return to proper operation).
  static TIMER_REFCOUNT: AtomicU32 = AtomicU32::new(0);

  pub(super) fn inc_ref() {
    let old = TIMER_REFCOUNT.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
    // Overflow/underflow sanity check in debug mode
    debug_assert!(old != u32::MAX);
    if old == 0 {
      lock_hr();
    }
  }

  fn dec_ref() {
    let old = TIMER_REFCOUNT.fetch_sub(1, std::sync::atomic::Ordering::SeqCst);
    // Overflow/underflow sanity check in debug mode
    debug_assert!(old != 0);
    if old == 1 {
      unlock_hr();
    }
  }

  /// If the refcount is > 0, we ask Windows for a lower timer period once. While the underlying
  /// Windows timeBeginPeriod/timeEndPeriod API can manage its own reference counts, we choose to
  /// use it once per process and avoid nesting these calls.
  fn lock_hr() {
    // SAFETY: We just want to set the timer period here
    unsafe { windows_sys::Win32::Media::timeBeginPeriod(1) };
  }

  fn unlock_hr() {
    // SAFETY: We just want to set the timer period here
    unsafe { windows_sys::Win32::Media::timeEndPeriod(1) };
  }
}

#[cfg(target_os = "windows")]
pub(crate) fn hr_timer_lock() -> windows::HrTimerLock {
  windows::inc_ref();
  windows::HrTimerLock {
    _unconstructable: Default::default(),
  }
}

/// No-op on other platforms.
#[cfg(not(target_os = "windows"))]
pub(crate) fn hr_timer_lock() -> (std::marker::PhantomData<()>,) {
  (std::marker::PhantomData::default(),)
}