I'm pretty sure the POSIX docs say that you can't call mutex routines from within interrupt code, which makes sense--the last thing you want is for an interrupt handler to block on a mutex aquisition.
I haven't got a copy, but I'd be surprised if they explicitly forbade it - I think however you *do* need to be very careful if you need to mix mutexes and signals, so that you don't self-deadlock.
This isn't actually a big deal, as it's reasonably straightforward to write code that can handle multiple user-space readers and writers (which can guard themselves with mutexes) and a single interrupt-time writer. Proper ordering and checking of operations inside the code makes this straightforward, if a pain. (And I know the ordering's doable, otherwise every single OS on the planet with interrupt code would fall down and go boom :) The nasty part comes in with multiple interrupt-time writers. I'm not sure if it's common to be able to have multiple concurrent interrupt handlers running, but I do know it's possible.
You *cannot* achieve what you want by 'proper ordering and checking of operations', as this will *not* work on a SMP machine, where the ordering of loads and stores is *not* guaranteed, *irrespective* of what appears to be the order of instructions produced by the compiler. To achieve what you want you need a memory barrier, which is other thing a mutex provides in addition to synchronization. For details, see either section 3.4 "Memory visibility between threads" in "Programming with Posix Threads" by David Butenhof, or follow the links below:
http://www.math.cmu.edu/Parallel_Cluster/smp/Lthreadsfaq.htm#Q118 http://www.math.cmu.edu/Parallel_Cluster/smp/Lthreadsfaq.htm#Q156 http://www.math.cmu.edu/Parallel_Cluster/smp/Lthreadsfaq.htm#Q162 http://www.math.cmu.edu/Parallel_Cluster/smp/Lthreadsfaq.htm#Q180 http://www.math.cmu.edu/Parallel_Cluster/smp/Lthreadsfaq.htm#Q202
I'd considered just up and disabling interrupts entirely but I didn't want to take the performance hit from it. I'm thinking now that decision was a bad one, but luckily one that's not welded into anything anywhere (and wouldn't have been even if I'd kept going this way, as all we would've guaranteed is thread-safe interrupt-safe queues) so it's simple enough to change.
Disabling signals and interrupts is still going to be platform-specific, but that's not a big deal.
I think that what you are trying to do is ensure that the queue operations are async-signal safe - here is what our threads expert has to say about this:
| For a function to be async-signal safe (that is, to be callable both | at main level and from a signal handler) it has to block all signals | before acquiring any locks (including any locks acquired by any | library functions it calls). Otherwise, it could grab a lock at main | level, take a signal, and attempt to acquire the same lock at | interrupt level, thereby deadlocking itself. | | And, no, recursive locks are not the answer; all that would do is | invite data corruption: the lock is being held because the data | invariants are being modified; allowing a signal handler to re-modify | them just corrupts them. | | Now, if there is a lock that is acquired *only* while in a signal | handler, then it is sufficient to block all signals while in the signal | handler (and this can be accomplished with no additional overhead by | doing sigfillset(&action.sa_mask) before using 'action' to set up | the signal handler).
Hope that helps,
-- Alan Burlison --