My 1st question about locking (and other related issues)

M

Michele Dondi

I have a *working* .sig rotation script that begins like this:


#!/usr/bin/perl

use strict;
use warnings;
use POSIX;

$|++;
setsid;

# ...
# Do some administrative things like
# redirecting STDIN STDOUT and STDERR
# ...

fork and exit;


then it starts an infinite loop and writes to a fifo (creating it if
it doesn't exist).

Now I'd like to use some mechanism to prevent more than one copy of
the program to run at the same time on the same machine. The named
pipe is in my home, mounted on nfs.

I've thought of using a lockfile, but then since I can be logged at
the same time on different machines, I *think* I should write in it
the hostname, possibly along with other info.

Anyway, I've really *no* experience in these matters, so can you give
me any suggestion? Also, I'm not asking you to do the job for me, but
could you please provide some minimal code snippet?

Note: I know I've read that file creation/deletion is not atomic over
nfs, but I don't think this is really a major issue, since I'll call
the script from my .bash_profile and it's hard to imagine how there
could be race conditions...

Last, I have another request: as I said above, I want to launch my
script on login, and even if it wouldn't be a problem to have it
running as a background process when I'm not logged in, I'd rather
prefer to have it exit when I exit the shell.

I know this is not strictly speaking a Perl question, but also in this
case I'd welcome an actual code snippet.


TIA,
Michele
--
#!/usr/bin/perl -lp
BEGIN{*ARGV=do{open $_,q,<,,\$/;$_}}s z^z seek DATA,11,$[;($,
=ucfirst<DATA>)=~s x .*x q^~ZEX69l^^q,^2$;][@,xe.$, zex,s e1e
q 1~BEER XX1^q~4761rA67thb ~eex ,s aba m,P..,,substr$&,$.,age
__END__
 
A

Anno Siegel

Michele Dondi said:
I have a *working* .sig rotation script that begins like this:


#!/usr/bin/perl

use strict;
use warnings;
use POSIX;

$|++;
setsid;

# ...
# Do some administrative things like
# redirecting STDIN STDOUT and STDERR
# ...

fork and exit;


then it starts an infinite loop and writes to a fifo (creating it if
it doesn't exist).

Now I'd like to use some mechanism to prevent more than one copy of
the program to run at the same time on the same machine. The named
pipe is in my home, mounted on nfs.

I've thought of using a lockfile, but then since I can be logged at
the same time on different machines, I *think* I should write in it
the hostname, possibly along with other info.

I wouldn't write the hostname in the lockfile but name the lockfile
after the host. In fact, you don't need explicit file locking,
the existence of the lockfile can be used. The usual problem with
this approach is to reliably remove the lockfile when the program
terminates. %SIG handlers and an END block cover most of that.

use Sys::Hostname;
use Fcntl;

my $lockdir = "$ENV{ HOME}/lockfiles";
my $host = hostname;
my $lockfile = "$lockdir/$host";
sysopen my $lock, $lockfile, O_CREAT | O_EXCL, or
die "$0 already running on $host";
my $havelock = 1;
END { unlink $lockfile if $havelock }
$SIG{ $_} = sub { unlink $lockfile if $havelock } for
qw( INT TERM); # add more signals if needed

# rest of script
# ...

This ignores possible problems with NFS and atomic file operations.

Anno
 
M

Michele Dondi

I wouldn't write the hostname in the lockfile but name the lockfile
after the host. In fact, you don't need explicit file locking,
the existence of the lockfile can be used. The usual problem with
this approach is to reliably remove the lockfile when the program
terminates. %SIG handlers and an END block cover most of that.

[snip code]

Thank you so much for the supplied code, I really appreciated that! In
fact I noticed that some other programs do something very similar...
it still seems a bit of an overhead for such a simple script.

I was wondering if there could be the possibility of using the named
pipe itself to determine if there's already a copy of $0 running, i.e.
trying to read from it and if nothing comes out in a certain amount of
time (but then how much time?!?) then decide that it is not. Not
terribly reliable, I guess, but... just curious about this
possibility!

Also, could you be so kind to answer my other question or give a
suggestion just as good as this one wrt it? I mean: how can make my
script exit on logging out of the shell from which it was started?


TIA again,
Michele
 
D

Dale Henderson

AS> comp.lang.perl.misc:

AS> I wouldn't write the hostname in the lockfile but name the
AS> lockfile after the host. In fact, you don't need explicit
AS> file locking, the existence of the lockfile can be used. The
AS> usual problem with this approach is to reliably remove the
AS> lockfile when the program terminates. %SIG handlers and an
AS> END block cover most of that.

Another approach would be to write the pid into the
"lockfile". This would allow for the possibility of checking for
stale lock files although I do not know of any good way to check
for a process given a pid or verify it's the correct
process (i.e. not another process that just happens to have
inherited your pid).

This also allows for a "kill" script in the .bash_logout that
would open the "lockfile" and send an appropriate signal to the
specified pid. Of course this is problematic for it would kill
your sigfile "daemon" when the first shell exited. I presume you
would want the "daemon" to continue until the last shell exited.

What would be ideal (I think) is something like Debian's
start-stop-daemon but this is not portable. You might look into
your systems /etc/init.d/ scripts to see how daemons are started
and stopped.

AS> Anno
 
M

Michele Dondi

Another approach would be to write the pid into the
"lockfile". This would allow for the possibility of checking for
stale lock files although I do not know of any good way to check
for a process given a pid or verify it's the correct
process (i.e. not another process that just happens to have
inherited your pid).

As a wild guess I'd say that this approach would tend to be more
complicated than that suggested before, but indeed I've seen something
along these lines...
This also allows for a "kill" script in the .bash_logout that
would open the "lockfile" and send an appropriate signal to the
specified pid. Of course this is problematic for it would kill
your sigfile "daemon" when the first shell exited. I presume you
would want the "daemon" to continue until the last shell exited.

Well, I think that *if* I have a duplicate processes prevention
mechanism *and* if it continues until the shell it was started from is
exited, *then* that shell will be "the last to be exited".
What would be ideal (I think) is something like Debian's
start-stop-daemon but this is not portable. You might look into
your systems /etc/init.d/ scripts to see how daemons are started
and stopped.

My distro (here at home, at University we/they use Gentoo) is very
KISS-oriented (CRUX, available at <http://crux.nu>). As an example the
gpm daemon script (which I wrote myself modelling it after the ones
shipped with the distro) is as follows:

#!/bin/sh
#
# /etc/rc.d/gpm: start/stop gpm daemon
#

case $1 in
start)
modprobe -q psmouse
/usr/sbin/gpm -m /dev/misc/psaux -t ps2
;;
stop)
/usr/sbin/gpm -k || killall -q /usr/sbin/gpm
;;
restart)
$0 stop
sleep 2
$0 start
;;
*)
echo "usage: $0 [start|stop|restart]"
;;
esac

# End of file


Michele
 
D

Dale Henderson

MD> On 01 Jul 2004 21:26:25 -0500, Dale Henderson

MD> As a wild guess I'd say that this approach would tend to be
MD> more complicated than that suggested before, but indeed I've
MD> seen something along these lines...

Unfortunately it would be MUCH more complicated.


MD> Well, I think that *if* I have a duplicate processes
MD> prevention mechanism *and* if it continues until the shell it
MD> was started from is exited, *then* that shell will be "the
MD> last to be exited".

I don't follow this. Consider:

Shell 1 starts (daemon starts)

Shell 2 starts

Shell 1 exits (daemon stops)

Shell 2 exits

So the daemon stops with shell 1 but shell 2 is the last to exit.
 
M

Michele Dondi

MD> Well, I think that *if* I have a duplicate processes
MD> prevention mechanism *and* if it continues until the shell it
MD> was started from is exited, *then* that shell will be "the
MD> last to be exited".

I don't follow this. Consider:

Shell 1 starts (daemon starts)

Shell 2 starts

Shell 1 exits (daemon stops)

Shell 2 exits

So the daemon stops with shell 1 but shell 2 is the last to exit.

Uh-Oh!!! Was I missing something hugely obvious? Yes, definitely I
was...


Michele
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top