Skip to content

Commit cebd3d0

Browse files
committed
fix(timefns): support process CPU time on Windows
Guard the Unix clock_gettime path with cfg_select and use GetProcessTimes on Windows so current-cpu-time reports process CPU ticks on every supported platform.
1 parent a758382 commit cebd3d0

1 file changed

Lines changed: 59 additions & 13 deletions

File tree

neovm-core/src/emacs_core/builtins/misc_eval.rs

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2361,19 +2361,65 @@ pub(crate) fn builtin_current_cpu_time(args: Vec<Value>) -> EvalResult {
23612361

23622362
// GNU timefns.c Fcurrent_cpu_time: (clock() . CLOCKS_PER_SEC) — CPU time
23632363
// consumed by the process (all threads), not wall time, so a sleeping or
2364-
// descheduled process accrues nothing. glibc clock() reads
2365-
// CLOCK_PROCESS_CPUTIME_ID truncated to CLOCKS_PER_SEC (1e6) ticks;
2366-
// do the same directly.
2367-
let mut ts = libc::timespec {
2368-
tv_sec: 0,
2369-
tv_nsec: 0,
2370-
};
2371-
let ticks = if unsafe { libc::clock_gettime(libc::CLOCK_PROCESS_CPUTIME_ID, &mut ts) } == 0 {
2372-
ts.tv_sec as i64 * 1_000_000 + ts.tv_nsec as i64 / 1_000
2373-
} else {
2374-
0
2375-
};
2376-
Ok(Value::cons(Value::fixnum(ticks), Value::fixnum(1_000_000)))
2364+
// descheduled process accrues nothing.
2365+
Ok(Value::cons(
2366+
Value::fixnum(process_cpu_time_micros()),
2367+
Value::fixnum(1_000_000),
2368+
))
2369+
}
2370+
2371+
fn process_cpu_time_micros() -> i64 {
2372+
std::cfg_select! {
2373+
unix => {
2374+
// glibc clock() reads CLOCK_PROCESS_CPUTIME_ID truncated to
2375+
// CLOCKS_PER_SEC (1e6) ticks; do the same directly.
2376+
let mut ts = libc::timespec {
2377+
tv_sec: 0,
2378+
tv_nsec: 0,
2379+
};
2380+
if unsafe {
2381+
libc::clock_gettime(libc::CLOCK_PROCESS_CPUTIME_ID, &mut ts)
2382+
} == 0 {
2383+
ts.tv_sec as i64 * 1_000_000 + ts.tv_nsec as i64 / 1_000
2384+
} else {
2385+
0
2386+
}
2387+
}
2388+
windows => {
2389+
use windows_sys::Win32::Foundation::FILETIME;
2390+
use windows_sys::Win32::System::Threading::{
2391+
GetCurrentProcess, GetProcessTimes,
2392+
};
2393+
2394+
let mut creation = FILETIME::default();
2395+
let mut exit = FILETIME::default();
2396+
let mut kernel = FILETIME::default();
2397+
let mut user = FILETIME::default();
2398+
let ok = unsafe {
2399+
GetProcessTimes(
2400+
GetCurrentProcess(),
2401+
&mut creation,
2402+
&mut exit,
2403+
&mut kernel,
2404+
&mut user,
2405+
)
2406+
};
2407+
if ok == 0 {
2408+
return 0;
2409+
}
2410+
2411+
let filetime_ticks = |time: FILETIME| {
2412+
((time.dwHighDateTime as u64) << 32) | time.dwLowDateTime as u64
2413+
};
2414+
// FILETIME counts 100 ns intervals. GNU-compatible ticks are
2415+
// microseconds.
2416+
let micros = filetime_ticks(kernel).saturating_add(filetime_ticks(user)) / 10;
2417+
micros.min(i64::MAX as u64) as i64
2418+
}
2419+
_ => {
2420+
0
2421+
}
2422+
}
23772423
}
23782424

23792425
pub(crate) fn builtin_current_idle_time(

0 commit comments

Comments
 (0)