Skip to content

Commit

Permalink
a few time fixes
Browse files Browse the repository at this point in the history
1) Rename ticks() (arbitrary millisecond counter) to make it clearly
   distinct from system time.
2) msvcrt's time() gets unix time which is fed to srand so it needs system
   time, not ticks.
3) time64 returns 64-bit time_t which normally goes through edx:eax, but
   the shims machinery is not set up for this so we truncate at y2k38.
  • Loading branch information
evmar committed Sep 20, 2024
1 parent e5fc2b3 commit 0c3e485
Show file tree
Hide file tree
Showing 8 changed files with 23 additions and 29 deletions.
2 changes: 1 addition & 1 deletion cli/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ impl win32::Host for EnvRef {
self.0.borrow_mut().exit_code = Some(code);
}

fn time(&self) -> u32 {
fn ticks(&self) -> u32 {
let mut env = self.0.borrow_mut();
let gui = env.ensure_gui().unwrap();
gui.time()
Expand Down
2 changes: 1 addition & 1 deletion web/glue/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ impl win32::Host for JsHost {
JsHost::exit(self, exit_code)
}

fn time(&self) -> u32 {
fn ticks(&self) -> u32 {
web_sys::window().unwrap().performance().unwrap().now() as u32
}

Expand Down
3 changes: 2 additions & 1 deletion win32/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@ pub struct Message {

pub trait Host {
fn exit(&self, code: u32);
fn time(&self) -> u32;
/// Get an arbitrary time counter, measured in milliseconds.
fn ticks(&self) -> u32;
fn system_time(&self) -> chrono::DateTime<chrono::Local>;

/// Get the next pending message, or None if no message waiting.
Expand Down
6 changes: 3 additions & 3 deletions win32/src/winapi/kernel32/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const TRACE_CONTEXT: &'static str = "kernel32/time";

#[win32_derive::dllexport]
pub fn GetTickCount(machine: &mut Machine) -> u32 {
machine.host.time()
machine.host.ticks()
}

// The number of "counts" per second, where counts are the units returned by
Expand All @@ -33,7 +33,7 @@ pub fn QueryPerformanceCounter(
lpPerformanceCount: Option<&mut LARGE_INTEGER>,
) -> bool {
let counter = lpPerformanceCount.unwrap();
let ms = machine.host.time();
let ms = machine.host.ticks();
let counts = ms as u64 * (QUERY_PERFORMANCE_FREQ as u64 / 1000);
counter.LowPart = counts as u32;
counter.HighPart = (counts >> 32) as u32 as i32;
Expand Down Expand Up @@ -154,7 +154,7 @@ pub async fn Sleep(machine: &mut Machine, dwMilliseconds: u32) -> u32 {

#[cfg(feature = "x86-emu")]
{
let until = machine.host.time() + dwMilliseconds;
let until = machine.host.ticks() + dwMilliseconds;
machine.emu.x86.cpu_mut().block(Some(until)).await;
}

Expand Down
31 changes: 12 additions & 19 deletions win32/src/winapi/ucrtbase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,8 @@ pub fn free(machine: &mut Machine, ptr: u32) -> u32 {
0
}

static mut RAND_STATE: u32 = 0;
// MSDN: "Calling rand before any call to srand generates the same sequence as calling srand with seed passed as 1."
static mut RAND_STATE: u32 = 1;

#[win32_derive::dllexport(cdecl)]
pub fn srand(machine: &mut Machine, seed: u32) {
Expand All @@ -197,32 +198,24 @@ pub fn rand(machine: &mut Machine) -> u32 {
}
}

fn time64(machine: &mut Machine, destTime: Option<&mut u64>) -> u64 {
let time = machine.host.time() as u64 / 1000;
fn time64(machine: &mut Machine, destTime: Option<&mut u64>) -> u32 {
let time = machine.host.system_time().timestamp() as u64;
if let Some(destTime) = destTime {
*destTime = time;
}

// TODO: need to figure out 64-bit return values in general.
// It appears to go through edx:eax.

#[cfg(feature = "x86-emu")]
{
x86::set_edx_eax(machine.emu.x86.cpu_mut(), time);
time
}
#[cfg(not(feature = "x86-emu"))]
{
unimplemented!();
}
// TODO: 64-bit return values go through edx:eax, which is not yet modeled in the shims
// machinery, so we only return 32 bits here.
// Thankfully 32-bit time_t only overflows in 2038 anyway.
time as u32
}

#[win32_derive::dllexport(cdecl)]
pub fn time(machine: &mut Machine, destTime: Option<&mut u64>) {
time64(machine, destTime);
pub fn time(machine: &mut Machine, destTime: Option<&mut u64>) -> u32 {
time64(machine, destTime)
}

#[win32_derive::dllexport(cdecl)]
pub fn _time64(machine: &mut Machine, destTime: Option<&mut u64>) {
time64(machine, destTime);
pub fn _time64(machine: &mut Machine, destTime: Option<&mut u64>) -> u32 {
time64(machine, destTime)
}
2 changes: 1 addition & 1 deletion win32/src/winapi/user32/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ fn enqueue_timer_event_if_ready(machine: &mut Machine, hwnd: HWND) -> Result<(),
return Err(None);
}

let now = machine.host.time();
let now = machine.host.ticks();
if let Some(timer) = machine.state.user32.timers.find_next(hwnd, now) {
machine
.state
Expand Down
4 changes: 2 additions & 2 deletions win32/src/winapi/user32/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ pub fn SetTimer(
{
Some(timer) => {
timer.period = uElapse;
timer.next = machine.host.time() + uElapse;
timer.next = machine.host.ticks() + uElapse;
timer.func = lpTimerFunc;
timer.id
}
Expand All @@ -90,7 +90,7 @@ pub fn SetTimer(
id,
hwnd: hWnd,
period: uElapse,
next: machine.host.time() + uElapse,
next: machine.host.ticks() + uElapse,
func: lpTimerFunc,
};
machine.state.user32.timers.0.push(timer);
Expand Down
2 changes: 1 addition & 1 deletion win32/src/winapi/winmm/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub fn timeSetEvent(

#[win32_derive::dllexport]
pub fn timeGetTime(machine: &mut Machine) -> u32 {
machine.host.time()
machine.host.ticks()
}

const TIMERR_NOERROR: u32 = 0;
Expand Down

0 comments on commit 0c3e485

Please sign in to comment.