Skip to content

Remove Mono.Unix dependency#223

Merged
atanzu merged 19 commits into
masterfrom
lpimentel/remove-mono-unix-alt
Jun 4, 2026
Merged

Remove Mono.Unix dependency#223
atanzu merged 19 commits into
masterfrom
lpimentel/remove-mono-unix-alt

Conversation

@lucaspimentel

@lucaspimentel lucaspimentel commented Nov 26, 2025

Copy link
Copy Markdown
Member

Summary

Removes the Mono.Unix NuGet dependency, which was incompatible with some target runtimes (e.g. .NET Framework 4.6.1) and blocked customers from upgrading the client (#220).

Only two pieces of Mono.Unix were actually used, and both are replaced with self-contained alternatives:

  • UnixEndPoint (Unix domain socket transport): vendored directly into the repo as src/StatsdClient/UnixEndPoint.cs, copied from the Mono source under its MIT license. The public API and namespace (Mono.Unix) are preserved, so transport code is unchanged.
  • Syscall.stat (inode lookup for cgroup/container origin detection on Linux): replaced with a direct statx system call via P/Invoke in src/StatsdClient/NativeMethods.cs. struct statx has a fixed, architecture-independent layout defined by the kernel, so a single managed struct definition works across x64/arm64 and glibc/musl. No native binaries are shipped, and the package now has no native assets or third-party runtime dependencies.

FileSystem.TryStat is narrowed from any Unix platform to Linux only (the sole consumer, cgroup origin detection, reads Linux-only /proc paths) and delegates the platform check to NativeMethods.TryGetInode. Inode lookup is compiled out on .NET Framework (#if !NETFRAMEWORK), which always runs on Windows.

Changes

  • Remove the Mono.Unix PackageReference from StatsdClient.csproj.
  • Add src/StatsdClient/UnixEndPoint.cs (vendored, MIT).
  • Add src/StatsdClient/NativeMethods.cs (statx P/Invoke wrapper).
  • Update src/StatsdClient/IFileSystem.cs to use the new inode lookup.
  • Add tests/StatsdClient.Tests/NativeLibraryTests.cs exercising the real statx call on Linux.
  • Add BUILD.md and CLAUDE.md developer docs.
  • Add .gitattributes to force LF line endings on shell scripts.

Testing

  • Built the library across all four target frameworks (net461, netstandard2.0, netcoreapp3.1, net6.0); the net461 build exercises the #if NETFRAMEWORK fallback path.
  • NativeLibraryTests exercises the real statx syscall on Linux (inode for files, directories, symlinks, the cgroup namespace link, and non-existent-file failure) and verifies the non-Linux path returns false.

Compatibility

  • No public API changes.
  • No native assets in the package; no third-party runtime dependencies.

"Turns out the best way to depend on Mono.Unix is to not." — Claude 🤖


EDIT 2026-06-04. Summary from 🤖:

Why Mono.Unix is there at all: it's only used to call stat() and read the inode number for origin detection (OriginDetection.cs) — specifically the host cgroup-namespace check (/proc/self/ns/cgroup, line 104) and the cgroup-inode container-ID fallback GetCgroupInode, line 168). That's it.

This PR initially replaced Mono.Unix with a tiny native C library that wraps stat(), called via P/Invoke. It shiped a .so for 4 RIDs (linux-x64, linux-musl-x64, linux-arm64, linux-musl-arm64), with Docker cross-builds, CI changes, and NuGet packaging work.

Why not P/Invoke libc's stat() directly? Because struct stat's layout varies by architecture (x86_64 vs arm64) and libc (glibc vs musl), so a single C# struct definition can't safely marshal it — which is why we were wrapping it in C in early commits in this PR.

@atanzu suggested using statx instead. That's a genuinely good idea, and it sidesteps the whole problem:

  • struct statx has a fixed, architecture-independent layout defined by the kernel (fixed-width fields + explicit padding, 256 bytes). One C# struct works everywhere — no per-arch/per-libc variants.
  • statx(2) is a Linux syscall since kernel 4.11 (2017); the glibc wrapper exists since glibc 2.28 and musl since 1.1.20. You can P/Invoke [LibraryImport("libc")] statx(...) directly, request only STATX_INO, and read stx_ino.
  • This eliminates the entire native library: no C code, no CMake, no Docker cross-builds, no 4-RID packaging, no arm64 test flakiness, no NuGet native-asset plumbing. It's pure managed P/Invoke, like the old Mono.Unix path but with zero external dependency.

The one tradeoff: kernels older than 4.11 (e.g. CentOS 7 / kernel 3.10) lack statx. But origin detection already degrades gracefully (returns empty / false), so on those hosts you'd just lose container-ID-by-inode fallback — the same as today on any unsupported platform. For containerized workloads (the only place this matters) 4.11+ is essentially universal in 2026.

@lucaspimentel lucaspimentel force-pushed the lpimentel/remove-mono-unix-alt branch 4 times, most recently from fe42102 to 30e7810 Compare November 27, 2025 03:10
@lucaspimentel lucaspimentel changed the base branch from master to lpimentel/misc-clean-up December 1, 2025 16:23
@lucaspimentel lucaspimentel changed the title Lpimentel/remove mono unix (alt) Remove Mono.Unix dependency Dec 1, 2025
@lucaspimentel lucaspimentel force-pushed the lpimentel/remove-mono-unix-alt branch 19 times, most recently from 1bea90d to 368b0f2 Compare December 2, 2025 02:16
@lucaspimentel lucaspimentel force-pushed the lpimentel/misc-clean-up branch from 1115c35 to c422e70 Compare December 8, 2025 15:57
@lucaspimentel lucaspimentel force-pushed the lpimentel/remove-mono-unix-alt branch 2 times, most recently from e869628 to 5816bd1 Compare December 10, 2025 19:40
Base automatically changed from lpimentel/misc-clean-up to master January 13, 2026 23:02
@lucaspimentel lucaspimentel force-pushed the lpimentel/remove-mono-unix-alt branch from 5816bd1 to 73aa5a2 Compare January 13, 2026 23:17
Origin detection reads file inode numbers on Linux. This replaces the
bundled native libfs.so with a direct statx system call via P/Invoke.
struct statx has a fixed, architecture-independent layout, so a single
managed definition works across x64/arm64 and glibc/musl without shipping
any native binaries.

Removes the C library, its Docker cross-build, the CI native-build job, and
the per-RID NuGet packaging. The package now has no native assets and no
runtime dependencies.

🤖
Correct the NuGet pack output path to the artifacts/ layout, fix clean
instructions, and clarify that the wider framework list applies to the test
project while the library targets net461/netstandard2.0/netcoreapp3.1/net6.0.

🤖
Comment thread src/StatsdClient/IFileSystem.cs Outdated
@atanzu atanzu marked this pull request as ready for review June 3, 2026 06:03
@atanzu atanzu requested a review from a team as a code owner June 3, 2026 06:03
atanzu
atanzu previously approved these changes Jun 3, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5fde5531b9

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread build-and-test.sh Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR removes the external Mono.Unix NuGet dependency by vendoring the required UnixEndPoint implementation and replacing inode lookup based on Mono.Unix.Native.Syscall.stat with a Linux statx P/Invoke helper, plus adds documentation and integration tests around inode lookup.

Changes:

  • Removed Mono.Unix package reference and added an in-repo Mono.Unix.UnixEndPoint implementation.
  • Introduced NativeMethods (statx P/Invoke) and updated FileSystem.TryStat to use it on Linux (non-NETFRAMEWORK builds).
  • Added Linux integration tests for inode lookup and new build/testing guidance docs.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/StatsdClient.Tests/NativeLibraryTests.cs Adds Linux-only integration tests validating inode lookup behavior.
src/StatsdClient/UnixEndPoint.cs Vendors UnixEndPoint to avoid relying on the Mono.Unix package.
src/StatsdClient/StatsdClient.csproj Removes the Mono.Unix package reference from the library project.
src/StatsdClient/NativeMethods.cs Adds statx-based inode lookup via P/Invoke on Linux.
src/StatsdClient/IFileSystem.cs Switches TryStat implementation to use the new inode lookup on Linux.
CLAUDE.md Adds repository build/test guidance for agent-based workflows.
BUILD.md Adds general build and test instructions (including framework selection guidance).
.gitattributes Normalizes line endings and enforces LF for shell scripts.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/StatsdClient/NativeMethods.cs
Comment thread src/StatsdClient/IFileSystem.cs Outdated
Delegate the Linux platform check to NativeMethods.TryGetInode instead
of duplicating it in TryStat, and drop the now-unused usings.

🤖
lucaspimentel and others added 2 commits June 3, 2026 13:59
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Reference BUILD.md for build/test commands instead of duplicating them,
and drop stale file listings the agent can discover by grepping.

🤖
@lucaspimentel lucaspimentel linked an issue Jun 3, 2026 that may be closed by this pull request

@zacharycmontoya zacharycmontoya left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@andrewlock andrewlock left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - I think we should mention somewhere th as t this is incompatible with a bunch of glibc versions and musk - maybe in the PR and in the source code (so anyone wondering "why doesn't this work" has an easy answer)

@atanzu atanzu merged commit a62cd83 into master Jun 4, 2026
27 of 28 checks passed
@atanzu atanzu deleted the lpimentel/remove-mono-unix-alt branch June 4, 2026 12:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dependency on Mono.Unix breaks .NET Framework 4.6.1 support

5 participants