# Relibc vs GNU libc — Cross-Reference Assessment **Date:** 2026-05-05 **Reference:** glibc 2.41 (2026-05-05 clone from sourceware.org) **Relibc pinned:** commit 861bbb0 with Red Bear patch chain (26 patches) --- ## 1. eventfd ### glibc reference ```c // sysdeps/unix/sysv/linux/eventfd.c (not cloned yet — syscall wrapper) // bits/eventfd.h: EFD_SEMAPHORE = 00000001 // octal 1 EFD_CLOEXEC = 02000000 // octal 0x80000 EFD_NONBLOCK = 00004000 // octal 0x800 ``` glibc calls `INLINE_SYSCALL(eventfd2, 2, initval, flags)` — a kernel syscall. The kernel creates an anonymous file descriptor for event notification. Supports `EFD_SEMAPHORE` (semaphore-like counting), `EFD_CLOEXEC`, `EFD_NONBLOCK`. ### relibc current state (updated 2026-05-05 — S1-S4 implemented) ```rust // src/header/sys_eventfd/mod.rs — 30 lines // Full eventfd() implementation with EFD_SEMAPHORE/CLOEXEC/NONBLOCK. // Opens scheme:event/eventfd/{initval}/{sem} via Sys::open. ``` **Implementation shipped** ✅ **Kernel support**: `P0-eventfd-kernel.patch` extends event scheme with eventfd path parsing ✅ ### Gaps | Gap | Severity | Detail | |-----|----------|--------| | No `eventfd()` in relibc | Medium | libwayland has its own inline, but relibc should be canonical | | No `eventfd_read()`/`eventfd_write()` | Low | POSIX-adjacent convenience wrappers (glibc provides them) | --- ## 2. signalfd ### glibc reference ```c // sysdeps/unix/sysv/linux/signalfd.c int signalfd(int fd, const sigset_t *mask, int flags) { return INLINE_SYSCALL(signalfd4, 4, fd, mask, __NSIG_BYTES, flags); } // bits/signalfd.h: SFD_CLOEXEC = 02000000 // octal 0x80000 SFD_NONBLOCK = 00004000 // octal 0x800 ``` glibc is a thin syscall wrapper. Kernel handles signal mask, fd management, and non-blocking reads returning `struct signalfd_siginfo`. ### relibc current state ```rust // src/header/signal/signalfd.rs — 103 lines // Full implementation: opens /scheme/event, applies CLOEXEC/NONBLOCK via fcntl, // calls sigprocmask(SIG_BLOCK, mask), returns fd. // signalfd4 supports modifying existing fd's flags. ``` **Flags match glibc** ✅ **signalfd_siginfo struct matches** ✅ **signalfd4 with existing fd** ✅ (fcntl-based flag modification) ### Prowess vs glibc | Aspect | glibc | relibc | |--------|-------|--------| | Implementation | Syscall wrapper (5 lines) | Userspace via `/scheme/event` (100 lines) | | Existing fd support | Kernel handles | fcntl O_CLOEXEC/O_NONBLOCK modification ✅ | | Errno mapping | Kernel errno | Wraps in Errno, proper EINVAL/EFAULT | | Signal blocking | Kernel auto-blocks on read | `sigprocmask(SIG_BLOCK, mask)` called explicitly ✅ | ### Gaps | Gap | Severity | Detail | |-----|----------|--------| | No read path | High | Nothing reads `signalfd_siginfo` from the fd — the `/scheme/event` fd is opened but signals aren't delivered through it | | Signal delivery unverified | High | The `sigprocmask(SIG_BLOCK)` blocks signals but there's no evidence the kernel delivers them via the event fd | | `signalfd_siginfo` read not implemented | Critical | `struct signalfd_siginfo` is defined but never populated via read(2) | --- ## 3. Semaphores ### glibc reference ```c // sysdeps/pthread/sem_open.c — 216 lines // Uses: // __shm_get_name(name) → canonical path in /dev/shm // O_CREAT+O_EXCL path: creates temp file, writes semaphore header, ftruncate to sizeof(sem_t), mmap // Non-create path: open existing, __sem_check_add_mapping(name, fd) → reuse or mmap // pthread_setcancelstate(PTHREAD_CANCEL_DISABLE) — cancellation-safe // va_arg for mode_t when O_CREAT ``` glibc uses a sophisticated named semaphore implementation: 1. **Name canonicalization**: `__shm_get_name` transforms `/name` → `/dev/shm/sem.name` 2. **Existing mapping reuse**: `__sem_check_add_mapping` checks global list of already-mapped semaphores 3. **Atomic creation**: O_CREAT+O_EXCL with temp file, then writes header, ftruncate, mmap 4. **Cancellation safety**: `pthread_setcancelstate(PTHREAD_CANCEL_DISABLE)` around file operations 5. **Proper mode_t**: va_arg for mode when O_CREAT 6. **Reference counting**: `__sem_check_add_mapping` increments refcount, `sem_close` decrements ### relibc current state ```rust // src/header/semaphore/mod.rs — 176 lines // Uses: shm_open(name, O_CREAT|O_EXCL|O_RDWR, mode) → ftruncate → mmap → init // NamedSemaphore struct with RlctSempahore (futex-based) ``` **Core mechanism works** ✅ (shm_open + mmap) **sem_init/destroy/post/wait/trywait/timedwait/clockwait** ✅ **sem_open/close/unlink** ✅ (implemented in P3-semaphore-comprehensive.patch) ### Gaps vs glibc | Gap | Severity | Detail | |-----|----------|--------| | **No name canonicalization** | ~~Medium~~ ✅ FIXED | Names now prefixed with `sem.` before `shm_open`. glibc uses `/dev/shm/sem.NAME` equivalent. | | **No existing mapping reuse** | ~~High~~ ✅ FIXED | Global `BTreeMap` with `AtomicUsize` refcount. `sem_open` reuses existing mappings, increments refcount. | | **No refcounting** | ~~High~~ ✅ FIXED | `sem_close` decrements `AtomicUsize`, munmaps only when zero. | | **No cancellation safety** | Low | No `pthread_setcancelstate` around file ops | | **va_list not parsed** | Medium | `sem_open` hardcodes `value=0` when O_CREAT, ignoring mode and initial value from varargs | | **No `__sem_check_add_mapping` equivalent** | High | Opens named sem every time instead of reusing existing mapping | | **No O_NOFOLLOW** | Low | glibc uses `O_NOFOLLOW` for security | --- ## 4. Cross-Cutting Gaps ### Error Handling | Area | glibc | relibc | |------|-------|--------| | errno thread-safety | TLS errno via kernel | `Cell` per platform ✅ | | errno after close | Preserved (close may overwrite) | `let _ = Sys::close(fd)` — ignores errors ✅ | | EINTR | Handled in syscall wrappers | `Semaphore::wait` returns `Result<(), c_int>`. sem_wait/timedwait loop on EINTR ✅ | | `sem_wait` | AS-safe (futex wait, EINTR) | EINTR retry loop ✅ | | sem_open refcount | Mutex-protected global list | `BTreeMap` with `AtomicUsize` ✅ | | sem_close/sem_unlink | Mutex-protected | `Mutex>>` protects registry ✅ | | signalfd mask | Per-process (kernel) | Per-call sigprocmask ✅ | --- ## 5. Priority Improvement Plan ### Phase S1: Critical Correctness (1-2 weeks) 1. **sem_open refcounting** — Add global `HashMap, AtomicUsize)>` to reuse existing mappings. `sem_close` decrements refcount, munmaps only when zero. 2. **Eventfd implementation** — Implement `eventfd()` via `/scheme/event/eventfd/` using the existing scheme mechanism. Remove libwayland's inline copy. ### Phase S2: Completeness (2-3 weeks) 3. **signalfd read path** — Implement read(2) → `signalfd_siginfo` struct population. The `/scheme/event` fd must deliver signal info formatted as `signalfd_siginfo`. 4. **sem_open va_list** — Parse `mode_t` and `value` from varargs when O_CREAT. Requires `crate::header::stdarg` or manual stack walking. 5. **sem_open name canonicalization** — Prefix names with `/scheme/shm/sem.` for namespace isolation. ### Phase S3: Robustness (3-4 weeks) 6. **EINTR handling** — Wrap futex waits to retry on `EINTR`. 7. **sem_open cancellation safety** — Add `pthread_setcancelstate` around file ops (if pthread cancellation is supported). 8. **eventfd semaphore mode** — Implement `EFD_SEMAPHORE` counting semantics (decrements on read, blocks at 0). ### Phase S4: POSIX Conformance (2-3 weeks) 9. **eventfd_read/eventfd_write** — Convenience wrappers. 10. **sem_open existing-semaphore reopening** — Handle `(oflag & O_CREAT) == 0` path (open existing without O_EXCL). 11. **Signalfd signal delivery verification** — Runtime tests proving signals arrive via signalfd. --- ## 6. Eventfd Kernel Requirement Unlike signalfd and sem_open which can be implemented in userspace via existing schemes (`/scheme/event`, `shm_open`), eventfd currently relies on libwayland's inline implementation that opens `/scheme/event/eventfd/`. A canonical relibc implementation should use the same path. The `/scheme/event` kernel scheme needs: - Support for `eventfd` sub-path - EFD_SEMAPHORE counting semantics in kernel - Non-blocking reads returning `u64` count This is a **kernel change** and should be tracked separately from relibc. --- ## 7. Summary | Component | relibc Status | Matches glibc | Critical Gaps | |-----------|--------------|---------------|---------------| | eventfd | Full implementation | Constants ✅ | eventfd() implemented via /scheme/event/eventfd/ ✅ | | signalfd | 103-line impl | Flags ✅, struct ✅, signalfd4 ✅ | Read path needs kernel signal delivery ⚠️ | | sem_open | 226-line impl with refcount | Core works ✅, shm+mmap ✅ | va_list ✅, refcounting ✅, mapping reuse ✅ | | sem_close | Refcounted munmap | Semantics correct ✅ | Atomic refcount decrement ✅ | | sem_wait/post | Futex-based, EINTR retry | Works ✅ | EINTR loop ✅, errno returned on other errors | **Total estimated effort: 8-12 weeks for all gaps.** **Critical path: eventfd kernal + signalfd read + sem_open refcounting (Phase S1).**