sysv-semaphore
v0.1.3
Published
node bindings for Unix System V Semaphores
Maintainers
Readme
sysv-semaphore
Node.js bindings for Unix System V Semaphores.
Should work on any system that supports System V semaphores. YMMV. If it breaks, let me know, or better still fix it and make a PR.
Requirements
- Node.js 14.x or later
- A Unix-like operating system with System V IPC support
- Prebuilt binaries supported: Linux (x64, arm64, i386) OSX (x64, arm64)
- otherwise, C++ build tools (for native compilation)
Installation
npm install sysv-semaphoreFor other platforms, the module will be built from source during installation.
Usage
A simple API that uses the Unix System V semget family of system calls to create and use semaphores.
All operations are performed with SEM_UNDO ensuring that semaphores are released by the kernel when the process exits.
API Reference
Creating/Opening Semaphores
// Create a semaphore, but only if one does not already exist
const sem = Semaphore.createExclusive('/path/to/some/file', 10);
// Open an existing semaphore, or create it if it doesn't exist
const sem = Semaphore.create('/path/to/some/file', 10);
// Open an existing semaphore
const sem = Semaphore.open('/path/to/some/file');Semaphore Operations
// Block waiting for the semaphore (not recommended in most cases)
sem.wait();
sem.wait(1);
// Block waiting for the semaphore to be greater then the value (not recommended in most cases)
sem.wait(10);
// Non-blocking attempt to acquire semaphore
if (sem.trywait()) {
// Critical section
}
if (sem.trywait(1)) {
// Critical section
}
// Aquire multiple units
if (sem.trywait(10)) {
// Critical section
}
// Get current value
const value = sem.valueOf();
// Release one unit
sem.post();
// Release multiple units
sem.post(10);
// get number of references to this semaphore
sem.refs();
// Clean up
sem.close();Basic Example
// myModule.js
const { Semaphore } = require('sysv-semaphore');
// Create a module-scoped semaphore
// Initial value of 1 makes this a mutex/binary semaphore
const mutex = Semaphore.create('/path/to/some/file', 1);
// Example function that uses the semaphore
async function doSomethingExclusive() {
if (mutex.trywait()) {
try {
// Critical section
console.log('Acquired semaphore');
await someAsyncWork();
} finally {
// Release the semaphore
mutex.post();
}
} else {
console.log('Semaphore was not available');
}
}
// Another example with a counting semaphore
const poolSemaphore = Semaphore.create('/path/to/some/file', 5); // Allow 5 concurrent operations
async function useResourcePool() {
// Aquire 2 resources
if (poolSemaphore.trywait(2)) {
try {
// Use the aquired resources
await doSomeWork();
} finally {
// Release 2 resources
poolSemaphore.post(2);
}
} else {
// Pool is full, handle accordingly
}
}
// Semaphores will be automatically cleaned up when the process exitsBest Practices
- Always use
try/finallyblocks to ensure semaphores are properly closed - Prefer
trywait()overwait()to avoid blocking the Node.js event loop - Use
create()instead ofcreateExclusive()for better crash recovery - Keep critical sections as short as possible
- Handle errors appropriately - check
error.codefor specific error conditions
Error Handling
All operations can throw system errors. The error object will have:
error.code: Standard Node.js error codes (e.g., 'EACCES', 'EINVAL')error.message: Includes the failing system call name
Common error codes:
** refer to your systems manual page for the syscall in the error message **
EACCES: Permission deniedEEXIST: Semaphore exists (with createExclusive)ENOENT: Semaphore does not existEINVAL: Invalid argument
Troubleshooting
Semaphore not being released:
- Ensure
close()is called in afinallyblock - Check if process crashed while holding semaphore
- Ensure
Permission errors:
- Check file permissions of the key file
- Verify user has appropriate system permissions
Resource limits:
- Check system semaphore limits (
ipcs -l) - Clean up unused semaphores (
ipcs -sto list,ipcrmto remove)
- Check system semaphore limits (
Notes on Garbage Collection
While the Node.js garbage collector will eventually clean up semaphores, it's best practice to explicitly call close() when done. This ensures:
- Timely resource release
- Predictable cleanup
- Better system resource management
License
This is free software with no warranty expressed or implied. If it breaks you get to keep both pieces. See the LICENSE.
