If mpg321 is killed in the wrong way, it can leave its semaphores
sitting around locked, and is unable to play again (because it
requests an exclusive semaphore create the next time it runs). I've
triggered the bug twice, mostly during transient network hangs, or by
sending several signals together that kill it during its cleanup
It's also possible to kill mpg321 before it finishes opening a remote
file to reproduce this problem. This occurs in part because the
signal handlers aren't set up to register an actual exit before the file
One easy way to reproduce is to ensure that startup fails the shmget
initialization; the exit code in that situation does not RMID the
semaphore, or on fork failure, etc., etc. I think this is endemic to the
error handling style used in the main mpg321.c file...
this also reveals a few other bugs with the semaphores; the
semarray declaration, for instance, shouldn't be defined in the .h file,
only declared. (Ditto for decode pos and play pos) There are
numerous other places where this bug can be triggered.
I think an atexit handler might be the easist way to centralize the
semaphore cleanup, or a strategically placed goto. I've attached a
patch that puts it all in an atexit handler. Kill -9'ing the mpg321
process will still result in a lost semaphore, but at least the atexit
handling is an improvement. Patch for this attached. It's still
possible to cause mpg321 to coredump in ao_play() by killing at at
the wrong time, but at least it cleans up its semaphores correctly.
A related bug is that because ftok() is used to generate the ID of the
(private) semaphore, only one copy of mpg321 can be used on the
system at a time. Makes it impossible to use with multiple sound
Best solution I can think of is to either create a unique value to pass
to ftok, since the semaphore is only used for communication between
the producer and consumer processes.