| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Process.times reads four CPU time totals through a new HAL primitive, mrb_hal_process_times(), which reports them as mrb_process_clock_time readings on the same terms a clock reading crosses the HAL: ticks and platform types never cross into the common layer, and turning the four readings into the Floats a Process::Tms is built from happens above the HAL, reusing the clock code's own float conversion. Process::Tms itself needs no HAL at all: unlike Process::Status, it has nothing left to decode once built, so it just stores the four values #initialize is given and hands each back, the way CRuby's own Struct-based Tms does. POSIX reads times(2) scaled by sysconf(_SC_CLK_TCK); Windows reads GetProcessTimes() and answers 0 for cutime/cstime, there being no call that reports a reaped child's CPU time and no children this port creates yet in any case.
The pre-commit prettier hook reflows a continuation line differently than it was hand-wrapped.
Switch the POSIX HAL's mrb_hal_process_times() from times(2) scaled by sysconf(_SC_CLK_TCK) to getrusage(RUSAGE_SELF)/getrusage(RUSAGE_CHILDREN), converting each struct timeval directly into an mrb_process_clock_time. This drops the clock-tick scale factor and reads CPU time to the microsecond instead of a tick (usually 10ms). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VhjkXJBh21sZGNdh4gnufw
RUSAGE_SELF/RUSAGE_CHILDREN are XSI extensions, not guaranteed by base POSIX.1, so a host without getrusage(2) now falls back to the previous times(2)+sysconf(_SC_CLK_TCK) reading instead of failing to build. Gated by a new MRB_PROCESS_HAVE_GETRUSAGE feature macro, following the same #ifndef-overridable pattern as the other MRB_PROCESS_HAVE_* checks in this file. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VhjkXJBh21sZGNdh4gnufw
assert_operator ..., :>=, ... passed even when Process.times always returned 0.0, since 0.0 >= 0.0 is true. The busy loop between the two readings burns far more CPU than any clock this gem falls back to can fail to notice, so require a strict increase instead. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VhjkXJBh21sZGNdh4gnufw
times(2)'s return value is elapsed real time in clock_t ticks, not an error code; POSIX overloads (clock_t)-1 for both. On a host with a 32-bit clock_t that value recurs by simple wraparound roughly every 497 days, well before any struct tms field would overflow, and a raw equality check misreports that as a failure even though tms was filled in correctly. Clear errno before the call and check it instead of trusting the return value alone.
CRuby's Process::Tms is a Struct, and Struct#== checks the two operands' classes for an exact match before comparing members -- unlike Process::Status#==, which reads a subclass by its values. The previous is_a?(Tms) check let a Tms subclass with equal member values compare equal, which Struct itself does not allow.
Process.times's cutime and cstime are POSIX's own count of waited-for terminated children, credited whenever a wait(2)/waitpid(2) call reaps one -- not only when this gem's own Process.wait or Process.waitpid makes that call. mruby-io reaps children of its own (IO.popen(...).close, say), and those show up in the totals too, so the doc comments in process.c and process_hal.h no longer name only the two Ruby-level methods as the source.
<sys/resource.h> was included unconditionally, so a build predefining MRB_PROCESS_HAVE_GETRUSAGE=0 to force the times(2) fallback on a host without getrusage(2) still failed to compile if that host also lacked the header itself. Move the #include inside the same override guard so overriding the macro skips the #include too.
Predefining MRB_PROCESS_HAVE_GETRUSAGE=0 was the only way to skip <sys/resource.h> on a host that lacks it; without that override the unconditional #include broke the build instead of falling back to times(2). Probe the header with __has_include (GCC 5+/Clang/MSVC 19.15+) before including it, so hosts without it fall back on their own; a compiler without __has_include keeps the old unconditional #include, so those hosts still need the predefine.
The child previously ran "exit 0", too little CPU to distinguish real getrusage/times(2) readings from a HAL that always answers 0, and the assertions only checked non-decrease. Spawn a child that spins for a measurable stretch instead, assert cutime/cstime are unchanged while it sits unreaped, and that reaping it makes cutime + cstime increase strictly.
| Back | FazBrowse Home | New Git URL |
Summary
HAL boundary
Following the gem's existing split: the HAL (process_hal.h + the POSIX/Windows ports) answers only the four raw readings; turning them into Process::Tms's Floats — including the MRB_NO_FLOAT fallback — is entirely in the common layer (src/process.c, reusing the existing clock_float_result() helper). Process::Tms (src/tms.c + mrblib/tms.rb) is pure Ruby-value-object territory and touches the HAL not at all.
See the README's updated "HAL boundary", "Process::Tms" and "Design decisions" sections for the detailed reasoning.
Test plan
Generated by Claude Code