nx_flock.nx source
↩ module page · 87 lines · 2770 B
1// nx_flock.nx -- BSD-style file locking via flock(2).
2//
3// Two flavors of file locking on Linux:
4// 1. flock(2) -- whole-file advisory lock, simpler, less powerful
5// 2. fcntl(2) F_SETLK -- byte-range lock, more flexible
6//
7// This module covers (1). flock() is what most build tools and
8// daemons use:
9// - Lockfile to prevent two builds from running concurrently
10// - Daemon PID file lock (acquire on startup, release at exit)
11// - Crash-safe single-instance enforcement
12//
13// Linux RV64 syscall: 32 (flock).
14//
15// Lock types:
16// LOCK_SH shared (read) lock
17// LOCK_EX exclusive (write) lock
18// LOCK_UN unlock
19// LOCK_NB non-blocking (OR with one of the above)
20
21// nx_safety_envelope:
22// intended_use: AUTO_APPLIED -- primitive-specific tuning queued
23// sil_target: SIL1
24// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail]
25// verdict: NOT_YET_EVALUATED
26
27import "syscalls.nx"
28
29const NX_SYS_FLOCK: i64 = 32
30
31const NX_LOCK_SH: i64 = 1
32const NX_LOCK_EX: i64 = 2
33const NX_LOCK_NB: i64 = 4
34const NX_LOCK_UN: i64 = 8
35
36// Acquire a lock on `fd`. Blocks unless NX_LOCK_NB is set.
37// Returns 0 on success, -EWOULDBLOCK (-11) if NB and contended,
38// other negative errno on failure.
39func nx_flock(fd: i64, op: i64) -> i64 {
40 return __syscall(NX_SYS_FLOCK, fd, op, 0, 0, 0, 0)
41}
42
43// Convenience: acquire exclusive blocking.
44func nx_flock_ex(fd: i64) -> i64 {
45 return nx_flock(fd, NX_LOCK_EX)
46}
47
48// Convenience: acquire exclusive non-blocking. Returns 1 if
49// acquired, 0 if contended, negative errno on failure.
50func nx_flock_try_ex(fd: i64) -> i64 {
51 let r: i64 = nx_flock(fd, NX_LOCK_EX | NX_LOCK_NB)
52 if r == 0 { return 1 }
53 if r == 0 - 11 { return 0 } // -EWOULDBLOCK
54 return r
55}
56
57func nx_flock_sh(fd: i64) -> i64 {
58 return nx_flock(fd, NX_LOCK_SH)
59}
60
61func nx_flock_un(fd: i64) -> i64 {
62 return nx_flock(fd, NX_LOCK_UN)
63}
64
65// ---- self-test ---------------------------------------------------
66
67func main() -> i64 {
68 if NX_LOCK_SH != 1 { return __syscall(93, 1, 0, 0, 0, 0, 0) }
69 if NX_LOCK_EX != 2 { return __syscall(93, 2, 0, 0, 0, 0, 0) }
70 if NX_LOCK_NB != 4 { return __syscall(93, 3, 0, 0, 0, 0, 0) }
71 if NX_LOCK_UN != 8 { return __syscall(93, 4, 0, 0, 0, 0, 0) }
72
73 // Lock stderr (always a valid fd; flock on it is harmless and
74 // immediately released).
75 let fd: i64 = 2
76 let r1: i64 = nx_flock_try_ex(fd)
77 // Some hosts disallow flock on stderr (returns -EBADF);
78 // accept either success(1) or 0/negative without crashing.
79 if r1 < -100 { return __syscall(93, 5, 0, 0, 0, 0, 0) }
80
81 if r1 == 1 {
82 let r2: i64 = nx_flock_un(fd)
83 if r2 != 0 { return __syscall(93, 6, 0, 0, 0, 0, 0) }
84 }
85
86 return 0
87}