I'm using named System V semaphores to lock a file across all my apps on OSX and linux. Not prettiest of APIs by any definition.
It seems to work, but I can't quite figure out how to properly destroy the semaphore after everybody is done with it.
General logic is like this:
Creating:
[1] Thread or process tries to open a semaphore set with key_t created for the file by ftok(). Set contains 2 semaphores. [2] If semaphore set doesn't exist, it is created with 666 permissions. [3] "Lock" (one of the semaphores) set into released state (value 1). [4] "Reference count" (another semaphore in the same set) is incremented.
Locking/unlocking:
To lock [5], a thread decrements the value of "Lock" semaphore by 1 (with undo), thus waiting if it is already zero. To unlock [6], thread increments it by one, thus allowing somebody else to lock it.
Destroying:
[7] "Reference count" semaphore is attempted to be decremented (with IPC_NOWAIT flag). [8] Its value is checked to be 0, and if it is [9] semaphore set is destroyed.
(There is also a layer of logic based on thread local storage to make the lock recursive within one thread.)
The questions are:
- How do I synchronize steps [1] and [2]? (if semaphore set doesn't exist, but while we were counting stars, it was created by somebody else so now creation will fail too)
- How do I synchronize steps [4] with [8] so that [9] does not kill me prematurely?
- Are there any other race conditions?
PS: While POSIX semaphores have much nicer API, I don't think I can survive sem_inlink() behavior as described here:
Calls to sem_open() to re-create or re-connect to the semaphore refer to a new semaphore after sem_unlink() is called.
So I will have no way to release them...