GCC <cstdlib> needs ::strtold declared. Qt's include chain pulls in
<cstdlib> before stdlib.h. Adding #include <stdlib.h> at the top of
common_helpers_p.h fixes the 'strtold has not been declared in ::'
error. Reverted -U_GLIBCXX_USE_C99_STDLIB toolchain breakage.
Updates the local/sources/base submodule pointer to pick up the
PIIX4 IDE BAR quirk + vgaarb logging + archiso loop_mnt, and
updates the base-initfs recipe to cross-compile loop_mnt before
the redox-initfs-ar archive step.
See local/sources/base commit 2055dcd for the individual
changes.
GCC <cstdlib> uses C99 stdlib wrappers (strtold etc.) gated by this macro.
relibc declares but doesn't implement strtold. Undef at toolchain level
prevents 'using ::strtold' errors in KF6/Qt C++ builds.
GCC <cstdlib> needs ::strtold declared. relibc stdlib.h provides it,
but Qt include chains can pull in <cstdlib> before stdlib.h.
Adding -include stdlib.h at the toolchain level fixes all Qt/KF6 recipes.
Reference analysis for Red Bear OS integration based on running the
latest CachyOS desktop ISO (28 Jun 2026) under QEMU/KVM. Documents
the hardware-enumeration and kernel-init sequences a reference Linux
distro produces on the i440FX + PIIX machine type that Red Bear OS
also targets, with line-by-line mapping to Red Bear OS subsystems
(pcid, ided, e1000d, vesad, xhcid, hwd/acpid).
- local/docs/CACHYOS-INTEGRATION.md: Cross-cutting analysis
(executive summary, hardware inventory, ACPI table coverage,
PCI quirks, boot-phase ordering, init system comparison, action
items).
- local/docs/boot-logs/cachyos-kernel-20260629-0520.log: Captured
441-line dmesg-grade log from the CachyOS kernel boot (SeaBIOS
handover through ACPI, PCI, USB, ATA, network enumeration and
up to a rootfs shell prompt).
- local/docs/boot-logs/cachyos-boot-20260629-0520.md: Pointer
document with the capture command and the rationale for the
indirect-kernel invocation (the QEMU + CachyOS + KVM boot stalled
at the ISOLINUX EDD probe when run from CD; bypassing with
-kernel/-initrd and an explicit console=ttyS0 earlyprintk command
line recovered the full log).
Sources used: https://cachyos.org/ (release info) and the on-disk
ISOLINUX + archiso boot path extracted from
cachyos-desktop-linux-260628.iso.
GCC <cstdlib> does 'using ::strtold;' which requires strtold declared in
global namespace. relibc declares it correctly in stdlib.h, but Qt's
include chain (qchar.h → qglobal.h → ... → cstdlib) pulls in cstdlib
before stdlib.h is fully processed. Adding -include stdlib.h ensures
the C stdlib declarations are in scope before any C++ header.
Old patch had @@ -3,5 — missing trailing context line
'add_subdirectory(qmllint)' that diff -u includes.
Regenerated from actual source.tmp to match fetched tarball.
The previous commit changed the existence probe from is_dir/exists
(read_dir uses stat) to read_dir.is_ok(), but the second and subsequent
calls to read_dir for /scheme/acpi/thermal still return Err at runtime.
The first discover_zone_dirs call at startup succeeds (it sees 0 zones,
matching the acpid scheme's empty Thermal directory). The periodic
monitor_loop recheck then fails with 'unavailable' even though the
path is in fact present.
The real reason is not fully understood yet, but may relate to
scheme-namespace state after userland init, fd table churn, or
Redox-specific read_dir semantics on empty scheme directories.
The warn-once check is redundant: discover_zone_dirs already runs at
startup, and update_policy() sees the empty state every poll cycle and
re-renders the TUI accordingly. Drop the periodic recheck so the
already-diagnosed empty surface no longer logs a false alarm.
- acpid scheme: add Thermal and Power as new HandleKind variants,
register them in the openat match, and add entries to the TopLevel
getdents list. thermald and redbear-upower probe /scheme/acpi/thermal
and /scheme/acpi/power via read_dir; an empty directory is the
correct fallback for desktops and QEMU where there is no ACPI
_TZ/_PR data to enumerate.
- acpid scheme: also handle getdents on the new Thermal and Power
variants. Without this, the scheme returned EIO which std::fs::read_dir
treats as 'the path is not a directory or doesn't exist', and thermald
emits a false 'thermal surface unavailable' warning every poll cycle.
Both daemons previously checked /scheme/acpi/thermal (thermald) and
/scheme/acpi/power (redbear-upower) existence with Path::exists or
is_dir, which use stat/lstat. On Redox these syscalls can return
errors for scheme paths even when the scheme IS registered, leading
to false 'unavailable' warnings even after the new acpid thermal/
power directories were added.
Use fs::read_dir (which already worked for actual zone enumeration)
as the existence probe instead. The match expression intentionally
calls read_dir to discard the iterator and keep only the Result;
using ? here would break the warn-once pattern.
- app.rs: rapl_status field shows 'n/a (run as root)' or
'n/a (unsupported)' or 'sampling...' depending on state
- render.rs: header PkgW shows rapl_status when unavailable;
removed per-CPU PkgW column (package power is socket-wide)
- acpi.rs: fallback creates 6 evenly-spaced P-states from
cpuinfo_min_freq / cpuinfo_max_freq when scaling_available_frequencies
is absent (intel_pstate, amd-pstate drivers)
- platform.rs: probe accepts cpuinfo_max_freq as valid PSS source
- app.rs: match current frequency against synthetic P-state table
to compute current_idx without MSR access
- pss_source label: 'sysfs (cpuinfo min-max)' for intel_pstate
- msr.rs: add all Intel RAPL MSR addresses (0x606-0x64D) and AMD Zen
equivalents (0xC0010299-0xC001029B), RaplUnit struct for unit register
parsing with energy_to_uj/power_to_w conversion, read_rapl_energy()
and read_rapl_energy_uj() functions
- acpi.rs: read_rapl_package_energy() now tries MSR first (Intel then
AMD PKG energy MSRs) with unit-based µJ conversion, falls back to
Linux powercap sysfs
- local/docs/RAPL-IMPLEMENTATION-PLAN.md: comprehensive 3-phase plan
based on Linux 7.1 kernel analysis, Intel SDM, Fuchsia RFC-0203
patterns. Documents P0 blocker: /scheme/sys/msr/ not implemented
in kernel
On Redox the kernel's sys:cpu scheme is a single file (kernel/src/scheme/
sys/cpu.rs) whose contents start with 'CPUs: N\n', not a per-CPU directory.
The kernel does not create /dev/cpu/ at all, so the prior read_dir-based
enumeration always fell through to the single-CPU fallback on Redox —
hiding the fact that the kernel had successfully brought up the APs and
reporting only CPU 0 to the governor / power TUI.
Read /scheme/sys/cpu and parse the 'CPUs:' line first; fall back to
/dev/cpu/ for Linux hosts.
The local init fork's Service struct does not have a 'before' field
(it supports cmd, args, envs, inherit_envs, type only), and the
deny_unknown_fields attribute makes init panic at boot when it parses
'before':
init: /etc/init.d/12_dbus.service: unknown field 'before', expected
one of 'cmd', 'args', 'envs', 'inherit_envs', 'type' in 'service'
The 'before = [13_redbear-sessiond.service]' line was redundant
anyway: 13_redbear-sessiond.service already declares
requires_weak = ['12_dbus.service'], which orders it after dbus.
Fix both redbear-mini.toml and redbear-full.toml.
After cooking relibc, copy the freshly built libc.a and libc.so to both
the prefix toolchain and the redoxer toolchain (the latter is what
'make live' actually consumes for cross-recipe builds).
Without this, recipes that link against the dynamic libc.so see a stale
copy (no eventfd, no __fseterr, ...) and fail with 'undefined reference'
at link time. 'make prefix' does this sync via its sysroot rule, but
'make r.relibc' alone does not — covering both paths prevents the
first recipe that needs a new symbol from breaking the build.
- gettext: use -I${COOKBOOK_HOST_SYSROOT}/share/aclocal instead of
/usr/share/aclocal so autoreconf picks up the Redox-patched libtool 2.5.4
macros instead of the host system's libtool 2.6.1, fixing version mismatch
at build time
- libxau: add ACLOCAL=true AUTOMAKE=true AUTOHEADER=true to make invocations
to prevent automake regeneration when host autotools version differs from
what the source expects
- build-redbear.sh: make pre-cook failures non-fatal (warn only) and run with
COOKBOOK_OFFLINE=false so packages that need source fetching can succeed
- redox-drm: restore source from git history (was deleted in dc6805430);
update Cargo.toml version 0.1.0 -> 0.2.4 and dependency constraints to
match current project version
- recipes/dev/python312/recipe.toml: use COOKBOOK_TOOLCHAIN for
--with-build-python instead of /tmp/python312, which the build system
never stages. Add [ -x ] guard for clear failure on missing dev-dep.
- recipes/core/userutils/recipe.toml: switch from upstream git URL to
local fork (local/sources/userutils/) per the local fork model. The
upstream source opens /scheme/pty/ptmx which the ptyd scheme does not
recognize; the local fork opens /scheme/pty correctly and avoids the
getty PTY panic.
- local/scripts/build-preflight.sh: warn when a recipe build script
references /tmp/<known-package>/, since the cookbook does not stage
host dev-deps under /tmp/<name>. Points authors at COOKBOOK_TOOLCHAIN.
- local/scripts/build-redbear.sh: replace 'tail -1 || true' on pre-cook
failures with proper error capture, last-50-lines tail on failure, and
exit-1. Verify the pkgar exists after a successful cook.
The tab keys (1-9 jump directly, T cycles next) were
always wired in main.rs but not documented anywhere
visible. Operators could not discover how to switch
between the 9 data tabs (Per-CPU / System / Info /
Motherboard / Battery / Sensors / Network / Storage
/ Process) without reading the source.
Two surfaces now surface the tab keys as the FIRST
entries, ahead of governor / P-state / throttle
controls:
1. Controls panel (visible at the bottom of every
TUI frame): adds a 'Tabs:' line listing the 9
direct-jump keys with abbreviated tab names, plus
a [T] cycle line. Implemented in
render_controls().
2. --help output (HELP_TEXT constant, shown via
'redbear-power --help' and the in-TUI [?] help
overlay): adds a TABS: section at the top of the
INTERACTIVE CONTROLS block, listing all 9 tabs in
3-row grid + the [T] cycle key.
The keys themselves are unchanged: '1'-'9' for
direct tab jump, 'T' for cycle. No new keybindings
or behaviors added.
Discovered during interactive smoke-testing on the
Linux host: the binary worked perfectly but tab
navigation was a discoverability hole. Fix-only,
no semantic change.
186/186 tests still pass (the controls panel
render is covered by the existing snapshot tests).
Adds §68 (v1.44 plan) and revises §67.7 (v1.43
deferred list) to reflect the v1.43 audit findings.
Key corrections captured in the doc:
- The Redox kernel ALREADY implements
sched_setaffinity and sched_getaffinity
(local/sources/kernel/src/syscall/process.rs:322-382).
Only the relibc POSIX <sched.h> wrapper is missing.
- The existing P7-pthread-affinity relibc patch
provides cpu_set_t, cpuset_to_u64, copy_u64_to_cpuset
— v1.44 can reuse these instead of duplicating.
- Kernel pid=0 limitation is documented at
kernel/src/syscall/process.rs:336-338 as a TODO;
v1.44's UX is honest about this ('pin redbear-power's
own TUI to this process's CPU list, not the
highlighted process's').
- Per-thread CPU% is REJECTED for v1.44 because the
Redox proc scheme doesn't expose /proc/<pid>/task/<tid>/stat.
Same trap as v1.41 read_thread_io. Tracked as a kernel
follow-up, not a redbear-power feature.
- disk_history cap is REJECTED for v1.44 because the
natural bound on block device count (~4-8 typical)
makes the cap moot. Drive-by include it elsewhere.
Implementation plan documented:
1. relibc patch P12-sched-setaffinity.patch (~110 LoC,
reusing P7 helpers)
2. redbear-power affinity.rs module (~30 minutes)
3. main.rs key binding (capital A) + PID detail
popup integration (~1.5 hours)
4. 5-7 tests (round-trip, pid=0 limitation, parse/format,
integration against /proc/self/status)
5. Doc update §69 on what shipped
Effort estimate: ~1 working day, end-to-end. The
relibc patch alone is <3 hours given P7 reuse.
Downstream recipe impact audited (LOW):
- Mesa and xz both wrap sched_getaffinity in
defensive probes — they go from ENOSYS to
'current process mask works' (strict improvement,
no break).
No code changes — planning-only commit.
Add local/scripts/cleanup-build.sh - a git-aware cleanup script that
uses 'git ls-files' to whitelist tracked files before deletion.
Prevents the class of cleanup disasters that deleted local recipe
sources and local fork sources.
Update AGENTS.md with the new safe cleanup procedure.
Update CONSOLE-TO-KDE-DESKTOP-PLAN.md to v5.8 with the qtdeclarative
qfeatures.h fix and the new safe cleanup script.
The qtquick-config.h file was being generated empty by the cmake
build, causing 'division by zero in #if' errors in downstream
consumers (SDDM, KWin) because QT_CONFIG(quick_shadereffect) and
QT_CONFIG(quick_draganddrop) were undefined.
Two fixes:
1. Explicitly enable QT_FEATURE_quick_shadereffect and
QT_FEATURE_quick_draganddrop in the cmake configuration.
2. Add a safety net that regenerates qtquick-config.h with the
required feature definitions if cmake produces an empty file.
The first item from the v1.42 deferred list: a
configurable LRU cap on the per-PID history maps.
On long uptimes with thousands of short-lived procs
(build servers, CI runners), the maps would grow
without bound, eventually consuming significant
memory. v1.43 caps the maps at 500 PIDs by default
and evicts the LRU entry on overflow.
The cap
- App::max_history_pids: usize (default 500)
- 0 = disable (reaper still prunes exited PIDs)
- Shared across the 3 per-PID maps (io_history,
cpu_history, rss_history). They are always
populated in lockstep so a per-PID CPU history
without the corresponding IO history would be
a 'ghost' entry that confuses the renderer.
- disk_history is NOT capped (keyed by disk name,
natural bound on block device count).
LRU tagging
- New App::pid_last_seen: BTreeMap<u32, u64>
- New App::refresh_tick: u64 (incremented on every
update_io_history call)
- We use a refresh counter, not Frame::count(),
because the history update happens during
refresh (not during render). Frame::count would
tag currently-visible PIDs rather than
recently-updated PIDs — a different (and
incorrect) notion.
Eviction algorithm
1. Increment refresh_tick
2. Reap exited PIDs from all 3 maps and
pid_last_seen
3. If pid_last_seen.len() > cap: sort by tick
ascending, take the first overflow entries,
remove from all 3 maps + pid_last_seen
4. Continue with the existing pipeline
Cost: O(n log n) per refresh, n bounded by 500.
At 500 PIDs: ~4500 comparisons per refresh,
<100µs. Memory budget: ~28 KB at cap, vs
unbounded growth without the cap (~5.5 MB at
100k PIDs).
Tests
- 3 new tests (eviction removes oldest, cap=0
disables, no-op under cap).
- 186/186 tests pass (was 183 in v1.42).
The improvement plan doc is also updated with §67
covering the v1.43 architecture, the cap policy,
the LRU tagging, the eviction algorithm, the
memory budget, and the v1.44 deferred list.
The next item from the v1.41 deferred list: read
/proc/<pid>/status:Cpus_allowed_list and display it as
both a single-char row indicator and a full expanded
list in the PID detail popup. htop parity.
Kernel format
The kernel emits the list as comma-separated ranges:
"0-3,5,7-11" means CPUs 0, 1, 2, 3, 5, 7, 8, 9,
10, 11
Cpus_allowed_list is the HARD affinity mask (settable
via sched_setaffinity(2)). v1.42 reads it because it
matches what an operator sees with 'taskset'.
New functions
- read_cpu_affinity(pid): parses the kernel string
- parse_cpu_list(s): public, testable parser
- format_cpu_list(ids): inverse of parse_cpu_list
- read_cpu_affinity_for_pid(pid): pub wrapper for the
PID detail popup
Two display modes
- Process panel row: '*' (subset), ' ' (all CPUs),
'?' (unknown). Single char so COMM stays visible.
- PID detail popup: full range string + expanded
Vec (truncated to 8 items on large machines).
New field on ProcessInfo
- cpu_affinity: Option<Vec<u32>>
Robustness
- Whitespace tolerated
- Out-of-order or duplicate IDs deduped and sorted
- Non-numeric chunks silently dropped
- Reversed ranges (start > end) silently dropped
- Empty input returns empty Vec (popup distinguishes
'no data' / None vs 'explicitly empty' / Some(empty))
Tests
- 13 new tests (11 in process.rs for parse/format/
read, 1 self-affinity test, 1 missing-pid test).
- 183/183 tests pass (was 170 in v1.41).
The improvement plan doc is also updated with §66
covering the v1.42 architecture, kernel format, the
two display modes, the parse/format inverse pair, and
the v1.43 deferred list.
The qtdeclarative recipe manually copied include files, which missed
the build-time generated qfeatures.h. Without it, downstream consumers
(SDDM, KWin, etc.) hit 'division by zero in #if' errors in qquickitem.h
because QT_CONFIG(quick_shadereffect) and QT_CONFIG(quick_draganddrop)
were undefined, triggering the deliberate 1/0 preprocessor trap.
Fix: use cmake --install to properly install all files, and add a safety
net that copies qfeatures.h from the build tree if cmake --install
does not place it in the install prefix.
The next item from the v1.40 deferred list: walk
/proc/<pid>/task/*/io for every process and sum
read_bytes and write_bytes across all TIDs. Surfaces
'is one thread of this 32-thread process hammering
disk?' which the process total hides.
Linux kernel attribution quirk
/proc/<pid>/io:read_bytes is the process total,
NOT the per-thread sum — the kernel attributes all
IO to the process even when threads initiate it.
So the two surfaces can match, diverge, or be
independently None depending on kernel version and
permission model. We never compare or subtract them.
New fields on ProcessInfo
- thread_io_read_kb, thread_io_write_kb (summed bytes)
- thread_io_read_rate_kbs, thread_io_write_rate_kbs
(delta-based rate via the same compute_rate_kbs
helper used for the process-total rates)
New sort modes
- ThreadIo: read+write total
- ThreadIoR: read only
- ThreadIoW: write only
The cycle reaches all 3 via a back-door arm of next()
that returns to Rss (not Name) to avoid breaking the
main loop.
New column in Process panel
T-IO between the per-thread rate and the MEM column.
Now 12 columns total. PID detail popup gets a
[thread_io] section that re-reads the task dir on
open for a current value.
Tests
- 6 new tests (3 in process.rs for read_thread_io,
3 for the sort modes + cycle).
- 170/170 tests pass (was 164 in v1.40).
The improvement plan doc is also updated with §65
covering the v1.41 architecture, the Linux kernel
attribution quirk, the new fields, the sort cycle
back-door, the cost analysis (~500 reads/sec at
typical desktop loads, ~7500 at 128-thread server
loads — well within budget), and the v1.42
deferred list.
The first item from the v1.39 deferred list: the user's
tab, sort mode, sort direction, tree mode, filter, and
fold set now survive a restart of redbear-power.
Architecture
- New module session.rs (separate from config.rs which
is read-only system-wide config).
- config.rs: behavior config (refresh interval, theme,
keybindings) — read once at startup, never written.
- session.rs: mutable per-user runtime state — read at
startup AND written on every tab change and on quit.
Storage
- $XDG_CONFIG_HOME/redbear-power/session.toml (preferred)
- ~/.config/redbear-power/session.toml (fallback)
- Writes are atomic: temp file + rename(). A crash
between write and rename leaves the prior session
intact.
Save hooks
- Every set_tab() call: tab is the high-signal event
the user explicitly opted into.
- On graceful quit (q/Esc): captures the final sort,
filter, and fold set.
Failure modes
- load() never errors. Missing file = defaults.
Corrupt file = defaults + one-line warning.
- save() never errors. Permission denied = eprintln!
warning. The next launch reads the prior session
(or defaults) and starts from there.
Tests
- 6 new tests in session.rs (round-trip, missing-file,
malformed-toml, atomic-save, default-state, end-to-end
via App::save_session()).
- 164/164 tests pass (was 158 in v1.39).
The improvement plan doc is also updated with §64
covering the v1.40 architecture, storage paths, save
policy, failure modes, and the v1.41 deferred list.
v1.39 lands three htop/btop parity features plus the
audit-fix discipline introduced in v1.37/v1.38:
1. Cursor preservation across sort
o and i keypresses no longer reset the cursor to row 0.
The cursor follows the currently-selected PID through the
re-sort. Implemented as App::remember_and_restore_cursor()
which walks the post-filter visible list. Three regression
tests: follows PID, respects filter, falls back when PID
exits.
2. Per-thread IO rate (T-IO column)
New ProcessInfo::io_per_thread_rate_kbs() returns the
aggregate IO rate divided by num_threads, surfacing
thread-pool pressure that's hidden in the aggregate. A
32-thread process at 320 KiB/s is the same as a 1-thread
process at 10 KiB/s in aggregate, but very different
in operator-relevant 'IO per worker' terms. Returns None
when num_threads <= 0 (data error, not '0 KiB/s per
thread' which would mislead the operator). Three unit
tests cover the divide, the missing-total case, and the
zero-threads case.
3. Process environ in PID detail
/proc/<pid>/environ read as NUL-separated KEY=VALUE
pairs, sorted by key for stable popup rendering.
Rendered as the first 8 vars in the PID detail popup
with a '(N variables)' header. htop F7 parity. Three
unit tests: parse self environ, missing PID, value
containing '=' (must split on FIRST '=' only).
The improvement plan doc is also updated with sections
56-63 covering v1.32 (sparklines) through v1.39
(per-thread IO + environ) since the doc previously
stopped at v1.31.
Test count: 158/158 pass (was 149 in v1.38.1).
v1.38 review found a HIGH severity bug in the v1.38 io_priority reader: it read fields[44] (overall field 47) which on modern Linux kernels (~52 fields total) is a memory address (~9x10^13) that overflows u32 and silently returns None for every process. The PID detail popup shows 'IO priority: ?' on every process, on every Linux kernel released in the last ~5 years.
Fix: change fields[44] to fields[15] (post-comm field 15 = overall field 18 = priority per the /proc/[pid]/stat layout). The doc comment now spells out the per-field index map 0-15 so a future maintainer can verify the indexing.
Strengthened the regression test: the v1.38 test did 'let _ = ...' which passed even when the reader was broken. The new test reads /proc/self/stat directly (bypassing the function), parses the priority field at vec[15] itself, and asserts the function returns the same value. A 'sanity' assertion (value < 1_000_000_000) catches the 'reading a memory address' failure mode specifically — a value > 10^9 means we're reading the wrong field again.
This is exactly the kind of bug the v1.37 audit warned about: 'the existing 4 tests that exist for update_io_history all assert the post-normalize storage value, not what the renderer actually draws. A simple integration test that renders and reads back would have caught it.' The v1.38 test for io_priority had the same shape — 'let _ = ...' passes silently. The v1.38.1 test now reads the actual value back.
Test count 149 -> 149 (strengthened one test in place; no new test count).
Redox stripped binary: 4,348,776 bytes (unchanged; the field index is 1 character).
v1.37 audit found 2 new bugs + recommended 5 v1.38 htop/btop-parity features. This release fixes both bugs and ships all 5 features.
v1.37-0 (HIGH): set_tab() clears last_clicked_cpu
The v1.37 re-click-to-expand feature set last_clicked_cpu on click but never reset it on tab switch. A user who clicked Per-CPU row 5, switched tabs, and came back would unexpectedly toggle expand. Fix: add App::set_tab(TabId) helper that resets both last_clicked_cpu and expanded_cpu, and route all 9 tab keys (1-9) + T through it.
v1.37-1 (MEDIUM): mouse click respects filter
The Process tab mouse click set process_cursor from the raw screen row, ignoring the active filter. With a filter active, the cursor highlight wouldn't align with the click, and right-click opened the wrong PID detail. Fix: new App::process_cursor_at_y(y, first_data_y) that walks the post-filter visible list and clamps to the last visible row. Wired into both left-click and right-click in handle_mouse.
v1.38-2: SortDir + i key for direction toggle
htop parity for the 'i' key. New App.sort_ascending: bool. The SortMode enum gets a new sort_ascending(procs, true) method (the existing sort() now delegates to sort_ascending(procs, false) for backward compat). On each refresh, if sort_ascending is true, the processes are re-sorted after the default descending pass. Press 'i' to flip; the status flash includes the current direction.
v1.38-3: cmdline + io_priority in PID detail
htop parity. New PidDetail.cmdline reads /proc/[pid]/cmdline, replaces NUL with space, strips trailing NULs. Rendered in the PID detail popup (truncated to 120 chars). New PidDetail.io_priority reads /proc/[pid]/stat field 47. Both are tolerant of missing files.
v1.38-4: per-disk I/O throughput sparkline
btop parity. New App.disk_history: BTreeMap<String, VecDeque<u8>> keyed by disk name. Mirrors the io_history pattern: each storage refresh collects raw kbps samples, normalizes per-disk against its own max, writes u8 to the public history. Rendered in the Storage tab as a 12-char sparkline next to each disk name. Reaps disks that have disappeared.
Test count 140 -> 149 (+9):
- set_tab_clears_last_clicked_cpu_and_expanded_cpu
- process_cursor_at_y_respects_filter
- process_cursor_at_y_clamps_to_last_visible
- sort_ascending_flips_rss_order
- read_cmdline_replaces_nul_with_space
- read_cmdline_handles_missing_pid
- read_io_priority_handles_self
- read_io_priority_handles_missing_pid
- update_disk_history_reaps_exited_disks
Redox stripped binary: 4,348,776 bytes (+106 KiB from v1.37).
Compile warnings: 56 (unchanged; all pre-existing).
The 18c3f2ad32 'cleanup script to free 58GB of build artifacts' commit
erroneously deleted local/patches/tokio/vendored/src/runtime/task/core.rs,
which is a tracked source file (not a build artifact). mod.rs:181 declares
'mod core;' and imports Cell + Header from it, so the vendored tokio 1.52.3
tree fails to compile with E0583 'file not found for module core'.
Restored byte-identically from 18c3f2ad32^ (= 04b7641e85, the original
vendoring commit) so pkgutils/installer transitive tokio-rustls builds
succeed again.
v1.32-v1.36 audit (shipped 5 features in one batch) had 4
real bugs the test suite missed, plus 2 htop/btop-parity
gaps. This release fixes all 4 bugs and adds the 2 parity
features, with regression tests for each.
P0-1 (CRITICAL) Bug 1: Sparkline type confusion
The v1.32 algorithm stored raw f64 bits in u64 cells, then
normalize_history overwrote them with integer-as-u64
(0..=255 cast to u64). The renderer's
f64::from_bits() interpreted these as f64 bits, producing
subnormal ~6e-324, then .max(0.0).min(255.0) as u8 -> 0.
Every sparkline cell rendered as blank after the first
refresh. The v1.31 IO-RATE sparkline worked ONCE then
degraded; the v1.32 CPU% and RSS sparklines never worked.
Fix: change the three history maps from VecDeque<u64> to
VecDeque<u8>. update_io_history now uses a two-phase
algorithm: (1) collect raw f64 samples into per-PID
pending Vecs, (2) write normalized u8 to the public
history. The renderer reads u8 directly with no f64
round-trip. Side effect: the per-refresh overwrite
replaces the v1.31 sliding window. 12 samples of
in-flight history is the same time window in practice
(12 * 6.5s = 78s) as 12 refreshes of windowed history
under the same refresh cadence.
P0-2 Bug 1 regression test: tests assert the io_history
cells are non-zero after update with a non-zero rate.
v1.32 would have left them at 0 (subnormal); v1.37
produces true u8 1..=255.
P0-3 (HIGH) Bug 2: Tree prefix bar continuation
The v1.34 ancestor_active_in_next check walked the next
row's chain only 0..=d steps. For a tree 1->{2->3, 4}
at row pid=2, the bar at depth 0 (above pid=2) checked
only one step of the next row's chain and missed
ancestor=1 in the chain. Result: bar showed ' ' instead
of '| ' for trees deeper than 1. v1.37 walks the full
chain to the root.
P0-4 Bug 2 regression test: 8 tree_prefix tests covering
single root, two-level fan-out, three-level chain,
sibling-after-deep, fold marker on/off, and the leaf
case. None existed before; would have caught Bug 2.
P0-5 (MEDIUM) Bug 3: Mouse y-offset
The Process tab render layout is: line 0 = title,
line 1 = blank, line 2 = column header, lines 3+ = rows.
The mouse handler subtracted table.y + 2 (one too high).
Clicking the column header mapped to process_cursor = 0
(first data row), and every row was off by one. v1.37:
table.y + 3.
P0-6 (LOW) Bug 4: Right-click filter
Re-verified: selected_pid() already uses
visible_processes() (post-filter list), so the audit's
bug report was incorrect. Added a regression test
instead that asserts selected_pid returns the right PID
with an active filter.
P1-1 htop parity: Re-click to expand
Mirrors htop's KEY_RECLICK handling. A second left-click
on the same CPU row toggles expand; a click on a different
row just selects. New App::last_clicked_cpu: Option<u32>
tracks the last click.
P1-2 htop parity: PageUp/PageDown
Already wired in v1.35 via page_selection(tab-aware).
Added a regression test that asserts the Process-tab
PageDown moves the cursor by ROWS_PER_PAGE (8) rows and
clamps at the last visible row.
Test count 127 -> 140 (+13):
- 2 new update_io_history tests (Bug 1 regression)
- 1 new io_history no-rate test
- 8 new tree_prefix tests (Bug 2 regression)
- 1 new selected_pid filter test (Bug 4 regression)
- 1 new page_selection test (P1-2)
Redox stripped binary: 4,242,280 bytes (-8 KiB from v1.36;
the new methods' bodies are tiny and the linker dedup'd
shared code).
Compile warnings: 56 (unchanged; pre-existing).
OpenSSL 3.5.3 tarball is missing include/openssl/core.h and
include/internal/core.h headers. Instead of using a patch (which
fails due to atomic patch application when files already exist),
inline the header creation directly into the build script.
This approach is more robust because:
- It always creates the headers before configure, regardless of
whether the source tree was previously patched or not
- It avoids the atomic patch rollback issue when files exist
- It survives make clean / distclean without issues
Fixes build failure:
fatal error: openssl/core.h: No such file or directory
OpenSSL 3.5.3 tarball is missing include/openssl/core.h and
include/internal/core.h headers. These are standard OpenSSL 3.x
headers that are referenced by multiple source files.
- Add P0-add-missing-core-headers.patch with both missing headers
- Update recipe.toml to apply the patch
- Headers sourced from official OpenSSL 3.5.3 branch on GitHub
Fixes build failure:
fatal error: openssl/core.h: No such file or directory