Skip to content

Timeout systematically too early on Linux #402

@advieser

Description

@advieser

There appears to be a bug on linux where a process’s timeout is consistently biased: the process is terminated too early by a sub-second offset that remains constant during a single boot but changes after rebooting.

Using this example, I got rough values for the actual time till a timeout from 5 different reboots of my system:

replicate(10, {
  start_time <- Sys.time()
  processx::run("sleep", "10", timeout = 3, error_on_status = FALSE)
  end_time <- Sys.time()
  difftime(end_time, start_time, units = "secs")
})
# Boot 1: 2.672711 2.667453 2.670226 2.670044 2.670001 2.672757 2.668645 2.669582 2.669642 2.669321
# Boot 2: 3.002664 2.976912 2.980564 2.979576 2.979316 2.984085 2.977271 2.979840 2.979048 2.981039
# Boot 3: 2.609917 2.586380 2.590400 2.590042 2.590023 2.591098 2.588827 2.589941 2.589849 2.590309
# Boot 4: 2.138885 2.106352 2.108275 2.106977 2.100902 2.111049 2.109790 2.110651 2.108229 2.110446
# Boot 5: 2.629206 2.606612 2.610635 2.609579 2.610023 2.620473 2.609882 2.610334 2.609502 2.610581

This is what @mb706 and I could figure out:
Internally, the timeout is determined by Sys.time() - start_time > timeout in run_manage():

processx/R/run.R

Lines 410 to 414 in 6a16b63

if (
!is.null(timeout) &&
is.finite(timeout) &&
Sys.time() - start_time > timeout
) {

with start_time ultimately getting defined here:

processx/src/create-time.c

Lines 183 to 196 in 6a16b63

ct = processx__create_time_since_boot(pid);
if (ct == 0) return 0.0;
bt = processx__boot_time();
if (bt == 0) return 0.0;
/* Query if not yet queried */
if (processx__linux_clock_period == 0) {
clock = sysconf(_SC_CLK_TCK);
if (clock == -1) return 0.0;
processx__linux_clock_period = 1.0 / clock;
}
return bt + ct * processx__linux_clock_period;

Here, ct gets read from the field starttime in /proc/<pid>/stat and bt seems to get defined through ps::ps_boot_time() in .onLoad(), which reads the btime field in /proc/stat.
However, the boot time in /proc/stat is only accurate in seconds.
If this is rounded down, that would explain why processx would think the process is older than it actually is.

This might also relate to this issue: #394


> sessioninfo::session_info()
─ Session info ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 setting  value
 version  R version 4.5.1 (2025-06-13)
 os       Linux Mint 22
 system   x86_64, linux-gnu
 ui       X11
 language en_US:en
 collate  de_DE.UTF-8
 ctype    de_DE.UTF-8
 tz       Europe/Berlin
 date     2026-02-01
 pandoc   3.1.3 @ /usr/bin/pandoc
 quarto   1.7.29 @ /opt/quarto/bin/quartoPackages ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 package     * version date (UTC) lib source
 cli           3.6.5   2025-04-23 [1] CRAN (R 4.5.0)
 processx      3.8.6   2025-02-21 [1] CRAN (R 4.5.0)
 ps            1.9.1   2025-04-12 [1] CRAN (R 4.5.0)
 R6            2.6.1   2025-02-15 [1] CRAN (R 4.5.0)
 sessioninfo   1.2.3   2025-02-05 [1] CRAN (R 4.5.0)

 [1] /home/keno/R/x86_64-pc-linux-gnu-library/4.5
 [2] /usr/local/lib/R/site-library
 [3] /usr/lib/R/site-library
 [4] /usr/lib/R/library

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions