tryLockExclusive(fd) returns a promise for one flock(fd, LOCK_EX | LOCK_NB) attempt. The syscall runs off the JavaScript thread. The caller keeps the descriptor open through completion; the binding does not open, duplicate, or close it. It exposes neither a blocking-wait API nor a shared-lock API.
The native tests exercise real descriptors and independent processes. The C oracle calls the operating system directly, independently of system.node.
| Condition | Required observation |
|---|---|
| No conflicting lock | Acquisition resolves to void |
| Same open file description acquires again | Acquisition succeeds without a second ownership record |
| Separate opens of the same file | Exactly one exclusive holder; the contender rejects with EAGAIN/EWOULDBLOCK |
| Different files | Both can be locked |
| Independent C flock holder | The addon cannot acquire, and the C oracle cannot acquire while the addon holds the lock |
| A shared flock holder | The addon's exclusive attempt conflicts |
| Holder remains live | A nonblocking attempt reports contention before the holder unlocks |
| Ordinary read/write by another process | Access is allowed: flock is advisory, not an I/O permission mechanism |
| One unrelated descriptor closes | The actual holder keeps its lock |
| A descriptor inherited by a child remains open | Closing the parent's descriptor does not release the shared open file description's lock |
| Last owning descriptor closes | An already-open contender can acquire |
| Holder process exits or is killed | Acquisition succeeds after process exit, without a stale-lock timeout |
| Invalid descriptor | The promise rejects with EBADF and positive errno |
| Native argument validation fails | The JavaScript entry returns a rejected promise without throwing synchronously |
| Native completion callback | It receives zero or the request's positive errno asynchronously |
| Native completion callback throws | The exception reaches Node's uncaught-exception handler |
| Concurrent success/failure calls | Each completion receives its own syscall errno |
| Worker environment terminates before or during its callback | Native work and cleanup reach completion without taking ownership of the caller's descriptor |
Tests synchronize through IPC or flushed line protocols and await process exit before asserting crash recovery. They do not use fixed sleeps or a millisecond performance threshold to prove nonblocking behavior. The syscall oracle is built only for tests and never included in a published platform package.
Locks belong to open file descriptions and follow the host filesystem's flock semantics. Removing or replacing a pathname does not transfer a lock to the replacement inode; the JSONL backend separately checks inode identity. Network filesystems can have different or unsupported lock semantics. Windows does not use this API and retains its existing semaphore implementation.
Node-API compatibility tests reuse the same platform addon under different Node versions. They complement these syscall tests; loading a binary alone does not prove correct locking behavior.