code wiki / (root) / nx_eventfd.nx

nx_eventfd.nx source

↩ module page · 105 lines · 3297 B

1// nx_eventfd.nx -- Linux eventfd(2) wrapper. 2// 3// eventfd creates a file descriptor backed by a kernel-managed 4// 64-bit counter. Useful for: 5// - Lightweight thread / coroutine signaling 6// - Adding a "wake up the poll loop" channel to a poll/epoll set 7// - Cross-process counters that don't need shared memory 8// 9// Read returns the counter and resets it to 0 (or decrements by 1 10// if SEMAPHORE flag was set). Write adds the value to the counter 11// (saturating at 0xFFFFFFFFFFFFFFFE). 12// 13// Linux RV64 syscall: 19 (eventfd2). 14// Flags: NX_EFD_SEMAPHORE / NX_EFD_NONBLOCK / NX_EFD_CLOEXEC. 15 16// nx_safety_envelope: 17// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 18// sil_target: SIL1 19// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 20// verdict: NOT_YET_EVALUATED 21 22import "syscalls.nx" 23 24const NX_SYS_EVENTFD2: i64 = 19 25 26const NX_EFD_SEMAPHORE: i64 = 1 27const NX_EFD_NONBLOCK: i64 = 0x800 28const NX_EFD_CLOEXEC: i64 = 0x80000 29 30// Create an eventfd with initial counter value `init` and flag 31// mask `flags`. Returns fd >= 0 on success or -errno. 32func nx_eventfd_new(init: i64, flags: i64) -> i64 { 33 return __syscall(NX_SYS_EVENTFD2, init, flags, 0, 0, 0, 0) 34} 35 36// Read the counter into `out`. Returns 8 on success, negative on 37// error (in particular -EAGAIN if NONBLOCK and counter == 0). 38func nx_eventfd_read(fd: i64, out: *i64) -> i64 { 39 return sys_read(fd, out as *u8, 8) 40} 41 42// Add `v` to the counter. Returns 8 on success or negative on error. 43func nx_eventfd_write(fd: i64, v: i64) -> i64 { 44 let buf_raw: *u8 = sys_mmap(16) 45 let buf: *i64 = buf_raw as *i64 46 *buf = v 47 return sys_write(fd, buf_raw, 8) 48} 49 50// Convenience: signal a single wakeup (write 1). 51func nx_eventfd_signal(fd: i64) -> i64 { 52 return nx_eventfd_write(fd, 1) 53} 54 55// ---- self-test --------------------------------------------------- 56 57func main() -> i64 { 58 if NX_EFD_SEMAPHORE != 1 { return __syscall(93, 1, 0, 0, 0, 0, 0) } 59 if NX_EFD_CLOEXEC != 0x80000 { return __syscall(93, 2, 0, 0, 0, 0, 0) } 60 61 // Create eventfd with initial counter = 5. 62 let fd: i64 = nx_eventfd_new(5, NX_EFD_NONBLOCK | NX_EFD_CLOEXEC) 63 if fd < 0 { return __syscall(93, 3, 0, 0, 0, 0, 0) } 64 65 // Read should return the counter (5) and reset to 0. 66 let val_raw: *u8 = sys_mmap(16) 67 let val: *i64 = val_raw as *i64 68 let n1: i64 = nx_eventfd_read(fd, val) 69 if n1 != 8 { 70 sys_close(fd) 71 return __syscall(93, 4, 0, 0, 0, 0, 0) 72 } 73 if *val != 5 { 74 sys_close(fd) 75 return __syscall(93, 5, 0, 0, 0, 0, 0) 76 } 77 78 // Subsequent read should return -EAGAIN (counter == 0, NONBLOCK). 79 let n2: i64 = nx_eventfd_read(fd, val) 80 if n2 == 8 { 81 sys_close(fd) 82 return __syscall(93, 6, 0, 0, 0, 0, 0) 83 } 84 85 // Signal: write 7, read should return 7. 86 nx_eventfd_write(fd, 7) 87 nx_eventfd_read(fd, val) 88 if *val != 7 { 89 sys_close(fd) 90 return __syscall(93, 7, 0, 0, 0, 0, 0) 91 } 92 93 // signal helper writes 1. 94 nx_eventfd_signal(fd) 95 nx_eventfd_signal(fd) 96 nx_eventfd_signal(fd) 97 nx_eventfd_read(fd, val) 98 if *val != 3 { 99 sys_close(fd) 100 return __syscall(93, 8, 0, 0, 0, 0, 0) 101 } 102 103 sys_close(fd) 104 return 0 105}