FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

mruby-process: add Process.times and Process::Tms by takumin · Pull Request #353 · takumin/mruby · GitHub

/ mruby Public
forked from mruby/mruby

mruby-process: add Process.times and Process::Tms - #353

Draft
takumin wants to merge 11 commits into
masterfrom
claude/process-times-tms-impl-ag10bv
Draft

mruby-process: add Process.times and Process::Tms#353
takumin wants to merge 11 commits into
masterfrom
claude/process-times-tms-impl-ag10bv

Conversation

takumin commented Aug 29, 2026

Copy link
Copy Markdown
Owner

Summary

  • Add Process.times, backed by a new HAL primitive mrb_hal_process_times() that reports the four CPU time totals (utime, stime, cutime, cstime) as mrb_process_clock_time readings, on the same seconds+nanoseconds terms an existing clock reading crosses the HAL — no platform type (clock_t, FILETIME) or unit conversion crosses into the common layer.
  • Add Process::Tms, the value Process.times returns. Unlike Process::Status, it has nothing left to decode once built: it just stores the four values #initialize is given and hands each back, the way CRuby's own Struct.new(:utime, :stime, :cutime, :cstime) does.
  • POSIX reads times(2) scaled by sysconf(_SC_CLK_TCK). Windows reads GetProcessTimes() and answers 0 for cutime/cstime, there being no Win32 call that reports a reaped child's CPU time and no children this port creates yet in any case (matches CRuby's own Windows build).
  • Process.times needs a build with Float (CRuby always answers in Float seconds, with no unit argument to fall back to an Integer by) and raises NotImplementedError under MRB_NO_FLOAT, following the same pattern already used for Process.clock_gettime's float units. Process::Tms itself needs no such guard — it stores whatever it is given.

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

  • rake test MRUBY_CONFIG=default — 0 KO / 0 Crash (includes new Process.times / Process::Tms assertions)
  • rake test MRUBY_CONFIG=host-nofloat — 0 KO / 0 Crash (exercises the NotImplementedError path and confirms Process::Tms itself needs no Float)
  • Manual smoke test via bin/mruby -e 'p Process.times'
  • Windows port compiled only by inspection (no cross-compiler available in this environment); mirrors the existing GetProcessTimes()/FILETIME patterns already used elsewhere in ports/win/process_hal.c

Generated by Claude Code

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.
github-actions Bot added the mrbgems Inside mrbgems, outside the core label Aug 29, 2026
claude added 10 commits August 29, 2026 16:18
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mrbgems Inside mrbgems, outside the core

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants


Back | FazBrowse Home | New Git URL