FreeBSD Port: FFM concretes for Memory/Sensors/Network/CPU - #3322
Conversation
First batch of sysctl-only FreeBSD HAL concretes. Each is a mechanical
mirror of its FreeBsd*JNA sibling: same abstract parent in oshi-common,
same overrides, with BsdSysctlUtil swapped for BsdSysctlUtilFFM.
* FreeBsdComputerSystemFFM — kern.hostuuid fallback.
* FreeBsdGlobalMemoryFFM — vm.stats.vm.v_inactive_count, v_free_count,
hw.physmem. createVirtualMemory() returns the FFM sibling.
* FreeBsdVirtualMemoryFFM — vm.swap_total, v_swappgsin, v_swappgsout.
Package-private; constructor takes FreeBsdGlobalMemory like the JNA
sibling.
No tests committed: per the established testing principle, Phase 6's
NativeComparisonTest globalMemory()/virtualMemory()/computerSystem()
cases will cover these transitively through HAL traversal once
SystemInfo wires FreeBSD in. The corresponding GlobalMemoryFFMTest /
VirtualMemoryFFMTest in oshi-core-ffm are also gated to
{LINUX, MAC, WINDOWS} for the same reason — they'll add FREEBSD in
Phase 6.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirror of FreeBsdSensorsJNA using callInArenaDoubleOrDefault + raw FreeBsdLibcFunctions.sysctlbyname (the per-CPU MIB is formatted at each iteration, so going through BsdSysctlUtilFFM would just be extra indirection). Loops dev.cpu.0.temperature, dev.cpu.1.temperature, … until sysctlbyname fails, then returns the average in Celsius — or NaN if the coretemp kld module isn't loaded. Fan speeds and CPU voltage have no FreeBSD-supported source and stay on the inherited FreeBsdSensors defaults, matching JNA behavior. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extends FreeBsdLibcFunctions with the libc surface FreeBsdNetworkParams needs: gethostname, getaddrinfo, freeaddrinfo, gai_strerror, plus an ADDRINFO_LAYOUT and addrinfoCanonname / gaiStrerror accessors. Mirrors LinuxLibcFunctions but with FreeBSD's actual struct addrinfo layout (ai_canonname comes BEFORE ai_addr on FreeBSD, the opposite of glibc). FreeBsdNetworkParamsFFM is the mirror of FreeBsdNetworkParamsJNA: same abstract parent in oshi-common, same two overrides (queryDomainName, queryHostName), going through the new FFM bindings instead of JNA. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors FreeBsdCentralProcessorJNA. Overrides queryProcessorId, initProcessorCounts, querySystemCpuLoadTicks, queryCurrentFreq, queryMaxFreq, getSystemLoadAverage, queryProcessorCpuLoadTicks, queryContextSwitches, queryInterrupts. Native reads all go through BsdSysctlUtilFFM (sysctl/sysctlbyname) or FreeBsdLibcFunctions.getloadavg — both already bound: * kern.cp_time → 40-byte MemorySegment via BsdSysctlUtilFFM.sysctl(name, segment) * kern.cp_times → variable-sized buffer via BsdSysctlUtilFFM.sysctl(name) reads N×40 bytes for N logical CPUs, indexed by CP_USER/CP_NICE/ CP_SYS/CP_INTR/CP_IDLE. * hw.model, hw.clockrate, dev.cpu.0.freq, dev.cpu.0.freq_levels, machdep.tsc_freq, kern.sched.topology_spec → BsdSysctlUtilFFM variants * vm.stats.sys.v_swtch, vm.stats.sys.v_intr → sysctl int + ParseUtil.unsignedIntToLong * getloadavg → arena-allocated double[] segment, FreeBsdLibcFunctions Private parsing helpers (parseTopology, matchBitmasks, getMatchingBitmask, getCacheInfoFromLscpu, getProcessorIDfromDmiDecode) are duplicated from the JNA sibling. They could be hoisted to oshi-common FreeBsdCentralProcessor in a follow-up but Phase 2 explicitly deferred this class's abstract API design, and the duplication keeps Phase 4 scope tight. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
🚧 Files skipped from review as they are similar to previous changes (2)
📜 Recent review details⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
🧰 Additional context used🧠 Learnings (5)📚 Learning: 2026-05-31T04:49:16.646ZApplied to files:
📚 Learning: 2026-04-17T23:43:35.860ZApplied to files:
📚 Learning: 2026-04-20T03:07:05.660ZApplied to files:
📚 Learning: 2026-03-29T20:01:06.452ZApplied to files:
📚 Learning: 2026-04-06T04:45:47.644ZApplied to files:
🔇 Additional comments (2)
📝 WalkthroughWalkthroughAdds FreeBSD FFM libc bindings for hostname/address resolution and implements FFM-backed FreeBSD classes for CPU, memory, virtual memory, sensors, network parameters, and computer-system host UUID lookups. ChangesFreeBSD FFM Hardware and System APIs
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report❌ Patch coverage is ❌ Your patch check has failed because the patch coverage (0.83%) is below the target coverage (70.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## master #3322 +/- ##
============================================
- Coverage 75.96% 74.89% -1.07%
Complexity 76 76
============================================
Files 449 455 +6
Lines 17255 17492 +237
Branches 2824 2872 +48
============================================
- Hits 13107 13101 -6
- Misses 2550 2790 +240
- Partials 1598 1601 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@oshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdCentralProcessorFFM.java`:
- Around line 337-346: The dmidecode probe in
FreeBsdCentralProcessorFFM.getProcessorIDfromDmiDecode is querying the wrong
table ("dmidecode -t system") so the loop using marker/procInfo never sees the
"Processor Information" / "ID:" lines; change the ExecutingCommand.runNative
call to use "dmidecode -t processor" (Type 4) or alternatively keep the command
but update the marker strings to match the selected table, ensuring the loop can
set procInfo when it sees "Processor Information" and then return the "ID:"
value.
In
`@oshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdGlobalMemoryFFM.java`:
- Around line 22-24: The sum of the page counters is done in 32-bit int and can
overflow before multiplying by getPageSize(); change the calculation in the
FreeBsdGlobalMemoryFFM method that currently uses int inactive and int free
(fetched via BsdSysctlUtilFFM.sysctl) so you cast at least one operand to long
before adding (or cast the result) and perform the multiplication in long,
returning a long total bytes value; update any local variable types involved
(e.g., inactive, free or the interim sum) so the addition and multiplication use
64-bit arithmetic and avoid integer overflow while still calling getPageSize().
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: d0749a5e-4b36-4777-8bed-80a078362b55
📒 Files selected for processing (7)
oshi-core-ffm/src/main/java/oshi/ffm/unix/freebsd/FreeBsdLibcFunctions.javaoshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdCentralProcessorFFM.javaoshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdComputerSystemFFM.javaoshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdGlobalMemoryFFM.javaoshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdSensorsFFM.javaoshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdVirtualMemoryFFM.javaoshi-core-ffm/src/main/java/oshi/software/os/unix/freebsd/FreeBsdNetworkParamsFFM.java
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
- GitHub Check: Codacy Static Code Analysis
- GitHub Check: Test JDK 25, macos-latest (+ JNA==FFM)
- GitHub Check: Test JDK 26, windows-latest
- GitHub Check: Test JDK 26, macos-latest
- GitHub Check: Test JDK 21, macos-latest
- GitHub Check: Test JDK 25, windows-latest (+ JNA==FFM)
- GitHub Check: Test JDK 21, windows-latest
- GitHub Check: Analyze (java)
- GitHub Check: JMH Benchmarks, ubuntu-latest
- GitHub Check: JMH Benchmarks, windows-latest
- GitHub Check: Lint (Spotless, Checkstyle, ForbiddenAPIs, Javadoc)
- GitHub Check: JMH Benchmarks, macos-latest
- GitHub Check: Test JDK 25, FreeBSD (+ JNA==FFM)
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2026-03-29T20:01:06.452Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3014
File: oshi-core-java11/src/main/java/module-info.java:10-17
Timestamp: 2026-03-29T20:01:06.452Z
Learning: In the oshi project, `oshi-core-java25/src/main/java/module-info.java` intentionally does NOT export `oshi.util.platform.unix.freebsd`, `oshi.util.platform.unix.openbsd`, or `oshi.util.platform.unix.solaris`, because the FFM (Foreign Function & Memory) implementation only supports Windows, macOS, and Linux. This differs from `oshi-core-java11/src/main/java/module-info.java` which exports all Unix platform packages. The asymmetry is by design.
Applied to files:
oshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdComputerSystemFFM.javaoshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdGlobalMemoryFFM.javaoshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdVirtualMemoryFFM.javaoshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdSensorsFFM.javaoshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdCentralProcessorFFM.java
📚 Learning: 2026-04-03T18:44:48.200Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3112
File: oshi-core/src/main/java/oshi/PlatformEnum.java:63-66
Timestamp: 2026-04-03T18:44:48.200Z
Learning: In oshi/oshi PlatformEnum.java, the DRAGONFLYBSD enum constant is intentionally added for platform detection only (no implementation classes exist yet). It allows UnsupportedOperationException messages to say "DragonFly BSD" rather than "Unknown". Full DragonFly BSD support is tracked in issue `#2583`. Do not flag the missing switch-case implementations as a bug.
Applied to files:
oshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdComputerSystemFFM.javaoshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdCentralProcessorFFM.java
📚 Learning: 2026-05-31T04:49:16.646Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3310
File: oshi-core/src/main/java/oshi/software/os/unix/netbsd/NetBsdOperatingSystem.java:164-166
Timestamp: 2026-05-31T04:49:16.646Z
Learning: In the oshi/oshi project, the NetBSD platform intentionally removes all JNA/native library dependencies (PR `#3310`). `NetBsdOperatingSystem.getThreadId()` uses `(int) Thread.currentThread().getId()` rather than `NetBsdLibc._lwp_self()` because the JNA native library is not bundled with the Maven dependency for the NetBSD platform. The mismatch between Java thread ids and kernel LWP ids is an accepted trade-off. Do not suggest reintroducing JNA-based calls (such as `NetBsdLibc._lwp_self()`) in NetBSD platform code.
Applied to files:
oshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdGlobalMemoryFFM.javaoshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdCentralProcessorFFM.java
📚 Learning: 2026-04-20T03:07:05.660Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3176
File: oshi-core-java25/src/main/java/oshi/hardware/platform/windows/WindowsVirtualMemoryFFM.java:53-60
Timestamp: 2026-04-20T03:07:05.660Z
Learning: In OSHI's Windows FFM paging file implementation (`oshi-core-java25/src/main/java/oshi/hardware/platform/windows/WindowsVirtualMemoryFFM.java`), the `querySwapUsed()` method uses the Windows PDH raw counter for "% Usage" on the paging file. Despite its name, this raw counter returns page counts: `FirstValue` is the number of pages currently used and `SecondValue` is the total number of pages in the swap file. The formatted counter performs the division and multiplies by 100% to yield a true percentage. Therefore, computing swap used bytes as `pageSize * used.get()` (pages × page size) is correct — do not treat the return value as a percentage.
Applied to files:
oshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdGlobalMemoryFFM.javaoshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdVirtualMemoryFFM.java
📚 Learning: 2026-04-10T22:44:36.786Z
Learnt from: dbwiddis
Repo: oshi/oshi PR: 3136
File: oshi-core-java25/src/main/java/oshi/software/os/linux/LinuxOperatingSystemFFM.java:46-53
Timestamp: 2026-04-10T22:44:36.786Z
Learning: In OSHI's `AuxvFFM.queryAuxv()` (oshi-core-java25/src/main/java/oshi/driver/linux/proc/AuxvFFM.java), the do-while loop is safe even when `/proc/self/auxv` cannot be read: `FileUtil.readAllBytesAsBuffer` returns an empty ByteBuffer on failure, and `FileUtil.readLongFromBuffer`/`readIntFromBuffer` return 0L when reading past the buffer limit. This 0L equals AT_NULL, causing the loop to exit immediately with an empty map, which triggers the `getconf`/hardcoded-default fallback in callers like `LinuxOperatingSystemFFM`. Do not flag this do-while loop or the static initializer that calls `AuxvFFM.queryAuxv()` as unsafe.
Applied to files:
oshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdCentralProcessorFFM.java
🔇 Additional comments (8)
oshi-core-ffm/src/main/java/oshi/ffm/unix/freebsd/FreeBsdLibcFunctions.java (3)
316-324: LGTM!
243-307: LGTM!
41-66: FreeBSD addrinfo/layout bindings need header-backed constants and sizing
ADDRINFO_LAYOUTencodesai_canonnamebeforeai_addr, but the gathered evidence doesn’t include FreeBSD header definitions to support the specificsocklen_tsizing, padding/byte offsets, or the assertedtotal = 48 bytes.AI_CANONNAME = 2andHOST_NAME_MAX = 255aren’t backed by any FreeBSD header content in the gathered results (repo search found no localnetdb.h/FreeBSD headers to cite).oshi-core-ffm/src/main/java/oshi/software/os/unix/freebsd/FreeBsdNetworkParamsFFM.java (2)
34-59: LGTM!
62-70: LGTM!oshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdVirtualMemoryFFM.java (1)
19-35: LGTM!oshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdSensorsFFM.java (1)
33-59: LGTM!oshi-core-ffm/src/main/java/oshi/hardware/platform/unix/freebsd/FreeBsdComputerSystemFFM.java (1)
19-22: LGTM!
| String csvMatch = m.group(1); | ||
| String[] csvTokens = csvMatch.split(","); | ||
| String firstVal = csvTokens[0]; | ||
| long parsedVal = ParseUtil.hexStringToLong(firstVal, 0); | ||
| switch (groupLevel) { | ||
| case 1: | ||
| group1 = parsedVal; | ||
| break; | ||
| case 2: | ||
| group2.add(parsedVal); | ||
| break; | ||
| case 3: | ||
| group3.add(parsedVal); | ||
| break; | ||
| default: | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return matchBitmasks(group1, group2, group3); |
There was a problem hiding this comment.
Parse the full CPU mask instead of only the first 64 bits.
Using csvTokens[0] throws away every mask word after the first one, so kern.sched.topology_spec gets truncated on FreeBSD hosts with more than 64 logical CPUs. That undercounts processors and cascades into incorrect core/package grouping and per-CPU telemetry sizing.
Also applies to: 210-223
CodeRabbit flagged two bugs in the new FFM concretes. Both are
identical to the long-standing JNA siblings — fixing only the FFM
copies would introduce a behavioral divergence that breaks Phase 6
NativeComparisonTest parity, so both pairs are updated in lockstep
(per the project convention of fixing pre-existing JNA bugs flagged
during the FFM port).
1. getProcessorIDfromDmiDecode used "dmidecode -t system", which
filters to DMI type 1 (System Information) only. The "Processor
Information" marker the loop scans for is DMI type 4. Result: the
loop never matched, the fallback ("%016X" formatting of the
dmesg.boot-derived bits) always ran. Switched both copies to
"dmidecode -t processor".
2. queryVmStats summed two uint32 page counters as Java ints
(BsdSysctlUtil.sysctl returns signed int). For counters > 2^31 the
addition would sign-extend incorrectly and the subsequent multiply
by getPageSize() could truncate. Switched both copies to
Integer.toUnsignedLong on each counter and perform the add and
multiply in long.
Each fix is one line per file. No other behavior changes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
FreeBsdFileSystemFFM mirrors FreeBsdFileSystemJNA — two trivial overrides for kern.openfiles / kern.maxfiles via BsdSysctlUtilFFM. Folds in three Sonar findings from PR oshi#3322: * FreeBsdNetworkParamsFFM (S2184): widen HOST_NAME_MAX + 1 to long for the arena allocate call to match the gethostname argument on the next line, keeping both arithmetic paths in 64-bit math. * DisklabelTest x2 (S2153): drop the unnecessary .longValue() unboxing from assertThat(diskdata.getC()…) in the OpenBSD and NetBSD live smoke tests — Hamcrest's greaterThanOrEqualTo(0L) works on the Long directly, the unbox-then-rebox roundtrip is wasted work. The CPUMASK regex S5998 finding in FreeBsdCentralProcessorFFM (and its JNA sibling) was reviewed and marked false positive: the comma anchor between alternatives prevents catastrophic backtracking, and input is bounded kernel-controlled sysctl output. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Phase 5 commit 1: FreeBsdFileSystemFFM + Sonar fixes FreeBsdFileSystemFFM mirrors FreeBsdFileSystemJNA — two trivial overrides for kern.openfiles / kern.maxfiles via BsdSysctlUtilFFM. Folds in three Sonar findings from PR #3322: * FreeBsdNetworkParamsFFM (S2184): widen HOST_NAME_MAX + 1 to long for the arena allocate call to match the gethostname argument on the next line, keeping both arithmetic paths in 64-bit math. * DisklabelTest x2 (S2153): drop the unnecessary .longValue() unboxing from assertThat(diskdata.getC()…) in the OpenBSD and NetBSD live smoke tests — Hamcrest's greaterThanOrEqualTo(0L) works on the Long directly, the unbox-then-rebox roundtrip is wasted work. The CPUMASK regex S5998 finding in FreeBsdCentralProcessorFFM (and its JNA sibling) was reviewed and marked false positive: the comma anchor between alternatives prevents catastrophic backtracking, and input is bounded kernel-controlled sysctl output. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Phase 5 commit 2: FreeBsdInternetProtocolStatsFFM Mirror of FreeBsdInternetProtocolStatsJNA. Reads net.inet.tcp.stats and net.inet.udp.stats via BsdSysctlUtilFFM.sysctl(name), returning the auto-arena MemorySegment, then memoizes the segment itself (instead of an intermediate BsdTcpstat / BsdUdpstat struct as the JNA sibling does — FFM lets us pull fields out at offset on demand, so the extra holder type isn't needed). Established-connection counts continue to come from the shared NetStat command-line driver. Field offsets and the ParseUtil.unsignedIntToLong widening match the JNA layout exactly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Phase 5 commit 3: FreeBsdPowerSourceFFM Mirror of FreeBsdPowerSourceJNA — three hw.acpi.battery.* sysctl reads (state/time/life) via BsdSysctlUtilFFM, then acpiconf -i 0 parsing for the richer device fields. Constructor signature and the heavy-but- straightforward command-output parsing are byte-identical to the JNA sibling. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Phase 5 commit 4: FreeBsdHWDiskStoreFFM Mirror of FreeBsdHWDiskStoreJNA. One native read (kern.disks via BsdSysctlUtilFFM); everything else is pure-Java parsing of iostat -Ix plus the GeomDiskList / GeomPartList drivers in oshi-common (hoisted in Phase 2). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Phase 5 commit 5: FreeBsdOperatingSystemFFM + FreeBsdOSProcessFFM The two classes are circularly dependent (OS constructs OSProcess, OSProcess holds the OS reference for the rlimit-of-self path), so they land together with all the libc bindings they share. * FreeBsdLibcFunctions gains: getpid, thr_self, sysctl (int-MIB form with errno capture), getrlimit + RLIMIT_LAYOUT (two longs, matching FreeBSD's struct rlimit) + RLIMIT_NOFILE = 8 (FreeBSD's value, not Linux's 7). rlimitCur/rlimitMax accessor helpers. * FreeBsdOSProcessFFM mirrors FreeBsdOSProcessJNA. Static ARGMAX read via BsdSysctlUtilFFM at class init; queryArguments / queryEnvironmentVariables / queryBitness via sysctl int-MIB (CTL_KERN=1, KERN_PROC=14, with KERN_PROC_ARGS=7 / KERN_PROC_ENV=35 / KERN_PROC_SV_NAME=9 leaves); getSoftOpenFileLimit / getHardOpenFileLimit via getrlimit(RLIMIT_NOFILE) for the calling process, falling back to /proc/<pid>/limits parsing for others (same as JNA). * FreeBsdOperatingSystemFFM mirrors FreeBsdOperatingSystemJNA. Wires the FFM siblings (FreeBsdFileSystemFFM, FreeBsdInternetProtocolStatsFFM, FreeBsdNetworkParamsFFM, FreeBsdOSProcessFFM); sessions go through WhoFFM.queryUtxent() (Phase 3); getProcessId / getThreadId use the new getpid / thr_self bindings; querySystemBootTime reads kern.boottime as a 16-byte struct via BsdSysctlUtilFFM.sysctl(name, segment), parsing the tv_sec long out of the result. * Hoists ProcstatUtil (oshi-core/oshi.util.platform.unix.freebsd) to oshi-common (oshi.util.common.platform.unix.freebsd) per the Phase 2 pattern, since both JNA OSProcess and the new FFM OSProcess need it and the original package is split (it also contains BsdSysctlUtil which is JNA-tied). FreeBsdOSProcessJNA import updated; the pure- parsing tests come along, and the live test now derives the current PID from ManagementFactory rather than oshi.SystemInfo (which lives in the JNA module and isn't visible from oshi-common). Module-info exports + add-opens updated to match. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Phase 5 commit 6: FreeBsdHardwareAbstractionLayerFFM (bookend) Aggregate FFM HAL. Wires the FreeBsd*FFM concretes from Phases 4–5 (ComputerSystem, GlobalMemory, CentralProcessor, Sensors, PowerSource, HWDiskStore, Cups printer) and reuses the pure-Java BSD-shared classes (UnixDisplay, BsdNetworkIF, FreeBsdGraphicsCard / SoundCard / UsbDevice) that already live in oshi-common. Hoists BsdNetworkIF (oshi-core/oshi.hardware.platform.unix) to oshi-common (oshi.hardware.common.platform.unix), mirroring the Phase 2 treatment of FreeBsdGraphicsCard / SoundCard / UsbDevice etc. The class is pure-Java already (just ExecutingCommand + netstat parsing); it was just stranded in the JNA module because Phase 2 didn't touch the BSD network path. Both DragonFlyBsdHardwareAbstractionLayer and FreeBsdHardwareAbstractionLayerJNA pick up the new import path; no behavior change. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Phase 5 commit 7: fix two CodeRabbit findings on PR #3328 Both findings verified against current code; both still valid. 1. ProcstatUtilTest live-test PID parse defaulted to 0 on failure, which would silently pass 0 to ProcstatUtil.getOpenFiles and let the rest of the live assertions run against a meaningless PID. Switched the default to -1 and added an upfront assertThat(pid, is(greaterThan(0))) so a platform that doesn't follow RuntimeMXBean#getName()'s "pid@host" convention fails fast with a clear message instead of producing confusing downstream failures. 2. FreeBsdPowerSourceFFM/JNA: hw.acpi.battery.life uses -1 as the sysctl-failure sentinel and the kernel returns 0–100 for a real reading. The "life > 0" check left psRemainingCapacityPercent at its default 1.0 when life was a legitimate 0 (battery flat), reporting a discharged battery as fully charged. Both FFM and JNA copies switch to ">= 0" so genuine 0 readings drive the percent to 0.0; -1 still falls through and keeps the 1.0 default. Lockstep fix on the JNA sibling because Phase 6's NativeComparisonTest will compare the two implementations and any divergence would fail parity. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Phase 5 commit 8: strip trailing newlines in unix.yaml (post-merge) Upstream 8f3f018 removed the NetBSD GCC farm CI job but left two trailing blank lines at the end of unix.yaml that Spotless flags. The new upstream master is otherwise unchanged for the FreeBSD port, so this is just a one-line cleanup after the merge into freebsd-ffm. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds PlatformEnum.FREEBSD to SUPPORTED_PLATFORMS, dispatches to FreeBsdOperatingSystemFFM / FreeBsdHardwareAbstractionLayerFFM (shipped in PRs oshi#3322 and oshi#3328), and updates the class-level Javadoc that previously listed only Windows/macOS/Linux. FreeBSD is dropped from the "use oshi.SystemInfo (JNA) instead" call-out since the FFM path now covers it; OpenBSD, Solaris, AIX still need the JNA entry point. This is the last load-bearing change of the FreeBSD FFM port — after this, oshi.ffm.SystemInfo.isAvailable() returns true on FreeBSD and the public API works end-to-end. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Phase 6 commit 1: wire FreeBSD into oshi.ffm.SystemInfo Adds PlatformEnum.FREEBSD to SUPPORTED_PLATFORMS, dispatches to FreeBsdOperatingSystemFFM / FreeBsdHardwareAbstractionLayerFFM (shipped in PRs #3322 and #3328), and updates the class-level Javadoc that previously listed only Windows/macOS/Linux. FreeBSD is dropped from the "use oshi.SystemInfo (JNA) instead" call-out since the FFM path now covers it; OpenBSD, Solaris, AIX still need the JNA entry point. This is the last load-bearing change of the FreeBSD FFM port — after this, oshi.ffm.SystemInfo.isAvailable() returns true on FreeBSD and the public API works end-to-end. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Phase 6 commit 2: enable FreeBSD across FFM tests Now that oshi.ffm.SystemInfo dispatches to FreeBSD (Phase 6 commit 1), all six FFM tests previously gated to {LINUX, MAC, WINDOWS} need FreeBSD added so they exercise the new wiring on the FreeBSD CI: * oshi-core-ffm: SystemInfoTest, GlobalMemoryFFMTest, VirtualMemoryFFMTest, OperatingSystemFFMTest, ForeignFunctionsTest * oshi-benchmark: NativeComparisonTest (the big JNA-vs-FFM HAL/OS parity test that retires the per-piece comparison tests we explicitly skipped during Phases 3–5) No assertion changes — the test bodies already cover the FreeBSD-relevant surface generically through the public OSHI API. Mac CI continues to see the same 39 successful / 53 skipped split. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Phase 6 commit 3: handle FreeBSD-specific NativeComparisonTest parity gaps Three failures surfaced when Phase 6 commit 2 enabled NativeComparisonTest on FreeBSD. None are real parity bugs; all are structural differences between FreeBSD's process/sensor model and the other platforms. * ComparisonAssertions.assertWithinRatio now treats both-NaN as equal. CPU temperature comes back NaN on the FreeBSD CI VM (no coretemp kld module loaded) from both JNA and FFM, which is correct parity, but NaN/NaN arithmetic made the ratio check fail. * assertStartTimeMatches helper added to NativeComparisonTest. On Linux/Mac/Windows OSProcess#getStartTime() exposes the kernel's exact start time and strict equality holds. On FreeBSD startTime is derived as (now - elapsedTime) where elapsedTime is the seconds-resolution `ps -o etimes` value; JNA and FFM each capture `now` at slightly different timestamps so the derived values drift by tens of milliseconds. Switched the two startTime assertions (currentProcess() and processListStructure()) to a 2000ms tolerance on FreeBSD; other platforms keep strict equality. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Phase 6 commit 4: more FreeBSD parity gaps surfaced by NativeComparisonTest Two more failures appeared once Phase 6 commit 3's startTime and NaN fixes cleared the way; both are real and fixed in this commit. 1. process.softOpenFileLimit — JNA returned 10328, FFM returned 175554 (real open-files limit). Pre-existing JNA-on-FreeBSD bug: Resource.RLIMIT_NOFILE in the JNA platform module is the Linux value 7, but on FreeBSD RLIMIT_NOFILE = 8 (7 is RLIMIT_NPROC). So FreeBsdOSProcessJNA was calling getrlimit on the wrong resource — returning the max-processes limit instead of open-files. Added an explicit `int RLIMIT_NOFILE = 8;` to FreeBsdLibc that shadows the inherited Linux constant so the existing call site picks up the correct value with no code change at the caller. FFM was already using 8 (added in Phase 5 commit 5). 2. fileStoreUpdateAttributes totalSpace — JNA and FFM call updateAttributes() back-to-back, but on a live filesystem total space can drift by a few blocks while the test is itself writing (the observed delta was exactly 3×4KB = 12 KB out of 208 GB). Relaxed the strict equality to assertWithinRatio with a 0.1% tolerance, the same pattern this file already uses for other drift-prone counters. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Phase 6 commit 5: remove temporary FreeBSD FFM CI workflow freebsd-ffm.yaml was the push-triggered FreeBSD VM job introduced in Phase 1 (PR #3316) so in-progress FFM work got FreeBSD coverage between PR submissions. With the port complete and the permanent testfreebsd job in pr.yaml + unix.yaml exercising every change, the temp workflow is no longer needed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Follow-up to the five FreeBSD FFM port PRs (#3316, #3319, #3322, #3328, #3330) covering loose ends that don't fit any individual port commit. JaCoCo agent excludes: * Remove `**/unix/BsdNetworkIF*` and `**/unix/UnixBaseboard*`. Both classes were hoisted to oshi-common during the port (#3316 and #3328 respectively) and are now exercised on the permanent FreeBSD CI job through `NativeComparisonTest.networkInterfaces()` and `ComputerSystem.getBaseboard()`; the excludes were silently dropping that coverage from the `freebsd` codecov flag. * Add `**/FreeBsdPowerSource*` alongside the existing `**/{Mac,Windows,Linux}PowerSource*` entries. No battery on the FreeBSD CI VM, same hardware-conditional pattern. Documentation: * Update the supported-platforms statement in README.md, FAQ.md, PERFORMANCE.md, src/site/markdown/index.md, oshi-core-ffm module-info Javadoc, oshi-core SystemInfo Javadoc, and oshi-core package-info Javadoc from "Windows, macOS, and Linux" to "Windows, macOS, Linux, and FreeBSD". CHANGELOG.md gains a New Features bullet linking all five FreeBSD FFM port PRs. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Phase 4 of the FreeBSD FFM port (tracking #3315). Ports the
sysctl-friendly FreeBSD HAL/OS concretes onto the Phase 3 bindings:
six new
FreeBsd*FFMsiblings (ComputerSystem, GlobalMemory,VirtualMemory, Sensors, NetworkParams, CentralProcessor) plus the
libc surface NetworkParams needs (
gethostname,getaddrinfofamily).FFM
SystemInfostill reports FreeBSD as unsupported — wiring staysfor Phase 6 so we never expose half-built state.
Per-commit walk
FreeBsdComputerSystemFFM,FreeBsdGlobalMemoryFFM,FreeBsdVirtualMemoryFFM. Each is amechanical mirror of its
*JNAsibling: same abstract parent inoshi-common, same overrides,BsdSysctlUtilswapped forBsdSysctlUtilFFM. ~100 lines total.FreeBsdSensorsFFM. Per-CPUdev.cpu.%d.temperatureloop via rawFreeBsdLibcFunctions.sysctlbyname(the MIB is formatted at eachiteration so going through the util would just add indirection).
Uses
callInArenaDoubleOrDefaultto scope the arena.FreeBsdNetworkParamsFFMplus the libcsurface it needs. Extends
FreeBsdLibcFunctionswithgethostname,getaddrinfo,freeaddrinfo,gai_strerror—mirroring
LinuxLibcFunctionsbut with FreeBSD's actualstruct addrinfolayout (ai_canonnamecomes BEFOREai_addronFreeBSD, the opposite of glibc).
FreeBsdCentralProcessorFFM. Largest ofthe batch. Native reads all go through
BsdSysctlUtilFFM(sysctl,sysctlbyname struct/raw variants) or
FreeBsdLibcFunctions.getloadavg:kern.cp_time→ 40-byte segment;kern.cp_times→ variable-sizedbuffer indexed by
CP_USER/CP_NICE/CP_SYS/CP_INTR/CP_IDLE;hw.model,hw.clockrate,dev.cpu.0.freq*,machdep.tsc_freq,kern.sched.topology_specvia the util;vm.stats.sys.v_swtch/v_intrvia int sysctl +ParseUtil.unsignedIntToLong. Privateparsing helpers (
parseTopology,matchBitmasks,getCacheInfoFromLscpu,getProcessorIDfromDmiDecode) areduplicated from the JNA sibling — Phase 2 explicitly deferred this
class's abstract API design, and the duplication keeps Phase 4
scope tight.
Intentionally deferred
SystemInfofactory wiring — Phase 6, soisAvailable()doesn't return true while the rest of the HAL/OS is still being
built.
NativeComparisonTeststays gated to{LINUX, MAC, WINDOWS}.FreeBsd*FFMconcretes —PowerSource,InternetProtocolStats,HWDiskStore,OSProcess,OperatingSystem. These are the Phase 2 deferrals (too JNA-heavy /struct-tangled to pre-design the abstract API at hoist time). They
land in Phase 5 alongside the libc bindings they need
(
sysctl(int*…)for kproc info,getpid,thr_self,getrlimit).oshi-common—parseTopology/matchBitmasks/getProcessorIDfromDmiDecodecould move to the abstract super and be shared by both JNA and FFM
siblings. Doing it now would require redesigning the abstract API
Phase 2 deferred; leaving the duplication keeps this PR small and
reviewable.
pattern established in FreeBSD Port: FFM libc bindings + sysctl util + WhoFFM driver #3319 commit 3, Phase 6's
NativeComparisonTestHAL/OS traversal will cover themtransitively. The existing
GlobalMemoryFFMTest/VirtualMemoryFFMTestetc. inoshi-core-ffmare likewise gatedto
{LINUX, MAC, WINDOWS}until then.Test plan
./mvnw -pl oshi-core-ffm compileclean on each commit./mvnw -pl oshi-core-ffm test— 68 successful on Mac (theFreeBSD-only Phase 3 smoke tests skip as expected)
./mvnw spotless:check checkstyle:check -pl oshi-core-ffmcleantestfreebsdjob inpr.yamlwill exercisethe codebase under
flags: freebsdTracks #3315.
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes