Add the --kill subcommand. It works as follows: Whenever a semaphore operation is performed, the PID of the process is stored in the sempid field of the semaphore. This PID can be obtained from a different process by calling semctl with the GETPID command. com_kill() first tries to acquire the lock by calling the new mutex_try_lock() function of ipc.c. In contrast to mutex_lock(), mutex_try_lock() only operates on the first semaphore in the semaphore set, leaving the sempid field of the second semaphore unchanged. If mutex_try_lock() succeeds, no running dss process is holding the lock and the kill command fails. Otherwise, some dss process is running whose PID can be obtained by calling semctl() on the second semaphore.
Use semaphore locking to avoid starting dss multiple times. It's trickier than one might expect but it is hopefully also much better than any pidfile-based approach. This patch adds ipc.c and ipc.h containing the public lock_dss() function which acquires a semaphore-based lock whose key is based on the hash of the resolved path name of the dss config file. This allows different instances of dss to coexist. All semaphore operations are called with both the SEM_UNDO and the IPC_NOWAIT flag. SEM_UNDO guarantees that no stale lock remains after dss was killed by SIGKIlL while IPC_NOWAIT makes the call to lock_dss() fail if another process is already holding the lock. The prune/create/run commands simply take the lock at startup and exit if it could not be acquired. The underlying semaphore set contains two semaphores. This is necessary to implement the --kill subcommand which is done in a subsequent patch.