Portable Perl pidfiles
Standard pidfile usage is to create a file, write your PID to it then go and do your stuff. Subsequent invocations of the same application will check for the existence of the file and die if it exists.
Smart pidfile usage is to check if the PID listed in the file actually refers to a running process and if not, overwrite it and go on about your business
How do we do it in Perl? What's a portable way of checking whether a process exists? We can't just look in /proc because not all systems have /proc. We can't parse the output of ps because different systems produce different formats of output. And besides it would be a really hacky and ugly thing to do.
How about sending signal 0 to the process we want to check?
We would expect one of three things to happen.
- Nothing. If the other process is actually running under the same UID, the signal will be processed but nothing will actually happen because signal 0 has no effect.
- We'll get an error (EPERM) because the process is running but we don't have permission to send signals to another user's processes. Unless we're root, of course, in which case see point 1. above.
- We'll get an error (ESRCH) because there is no such process.
Which means all we have to do is try to send signal 0 and wait to see if we get ESRCH. If we do, the pidfile is stale and can be replaced with our own.
use Errno; if (open PID, "< $pidfile") { my $pid = <PID>; close PID; kill 0, $pid; die "Lock held by PID $pid!\n" if $! == Errno::ESRCH; }
Why the funky if $! == Errno::ESRCH thing?
We could use if defined $!{ESRCH} but the Perl which ships with Solaris 8 doesn't define %! in this case. And we could use if $! eq "No such process" but then our test would fail if the current locale didn't produce error messages in English.
There's probably a funky module on CPAN which will do this but the method I describe works out of the box.