mirror of
https://github.com/percona/percona-toolkit.git
synced 2025-09-11 13:40:07 +00:00
Rewrite Daemon.pm: don't require an OptionParser, one public func, run(), that does the whole daemonize process or just check the PID file.
This commit is contained in:
271
bin/pt-agent
271
bin/pt-agent
@@ -4091,59 +4091,86 @@ package Daemon;
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings FATAL => 'all';
|
use warnings FATAL => 'all';
|
||||||
use English qw(-no_match_vars);
|
use English qw(-no_match_vars);
|
||||||
|
|
||||||
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
|
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
|
||||||
|
|
||||||
use POSIX qw(setsid);
|
use POSIX qw(setsid);
|
||||||
|
use Fcntl qw(:DEFAULT);
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
my ( $class, %args ) = @_;
|
my ($class, %args) = @_;
|
||||||
foreach my $arg ( qw(o) ) {
|
|
||||||
die "I need a $arg argument" unless $args{$arg};
|
|
||||||
}
|
|
||||||
my $o = $args{o};
|
|
||||||
my $self = {
|
my $self = {
|
||||||
o => $o,
|
log_file => $args{log_file},
|
||||||
log_file => $o->has('log') ? $o->get('log') : undef,
|
pid_file => $args{pid_file},
|
||||||
PID_file => $o->has('pid') ? $o->get('pid') : undef,
|
daemonize => $args{daemonize},
|
||||||
};
|
};
|
||||||
|
|
||||||
check_PID_file(undef, $self->{PID_file});
|
|
||||||
|
|
||||||
PTDEBUG && _d('Daemonized child will log to', $self->{log_file});
|
|
||||||
return bless $self, $class;
|
return bless $self, $class;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub daemonize {
|
sub run {
|
||||||
my ( $self ) = @_;
|
my ($self, %args) = @_;
|
||||||
|
my $pid ||= $PID;
|
||||||
|
my $pid_file ||= $self->{pid_file};
|
||||||
|
my $log_file ||= $self->{log_file};
|
||||||
|
|
||||||
PTDEBUG && _d('About to fork and daemonize');
|
if ( $self->{daemonize} ) {
|
||||||
defined (my $pid = fork()) or die "Cannot fork: $OS_ERROR";
|
$self->_daemonize(
|
||||||
if ( $pid ) {
|
pid => $pid,
|
||||||
PTDEBUG && _d('Parent PID', $PID, 'exiting after forking child PID',$pid);
|
pid_file => $pid_file,
|
||||||
exit;
|
log_file => $log_file,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
elsif ( $pid_file ) {
|
||||||
|
$self->_make_pid_file(
|
||||||
|
pid => $pid,
|
||||||
|
pid_file => $pid_file,
|
||||||
|
);
|
||||||
|
$self->{pid_file_owner} = $pid;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PTDEBUG && _d('Neither --daemonize nor --pid was specified');
|
||||||
}
|
}
|
||||||
|
|
||||||
PTDEBUG && _d('Daemonizing child PID', $PID);
|
return;
|
||||||
$self->{PID_owner} = $PID;
|
}
|
||||||
$self->{child} = 1;
|
|
||||||
|
|
||||||
POSIX::setsid() or die "Cannot start a new session: $OS_ERROR";
|
sub _daemonize {
|
||||||
chdir '/' or die "Cannot chdir to /: $OS_ERROR";
|
my ($self, %args) = @_;
|
||||||
|
my $pid = $args{pid};
|
||||||
|
my $pid_file = $args{pid_file};
|
||||||
|
my $log_file = $args{log_file};
|
||||||
|
|
||||||
$self->_make_PID_file();
|
PTDEBUG && _d('Daemonizing');
|
||||||
|
|
||||||
|
if ( $pid_file ) {
|
||||||
|
eval {
|
||||||
|
$self->_make_pid_file(
|
||||||
|
pid => $pid, # parent's pid
|
||||||
|
pid_file => $pid_file,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
if ( $EVAL_ERROR ) {
|
||||||
|
die "Cannot daemonize: $EVAL_ERROR\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defined (my $child_pid = fork())
|
||||||
|
or die "Cannot fork: $OS_ERROR";
|
||||||
|
if ( $child_pid ) {
|
||||||
|
PTDEBUG && _d('Forked child', $child_pid);
|
||||||
|
exit 0;
|
||||||
|
}
|
||||||
|
|
||||||
$OUTPUT_AUTOFLUSH = 1;
|
|
||||||
|
|
||||||
PTDEBUG && _d('Redirecting STDIN to /dev/null');
|
PTDEBUG && _d('Redirecting STDIN to /dev/null');
|
||||||
close STDIN;
|
close STDIN;
|
||||||
open STDIN, '/dev/null'
|
open STDIN, '/dev/null'
|
||||||
or die "Cannot reopen STDIN to /dev/null: $OS_ERROR";
|
or die "Cannot reopen STDIN to /dev/null: $OS_ERROR";
|
||||||
|
if ( $log_file ) {
|
||||||
if ( $self->{log_file} ) {
|
PTDEBUG && _d('Redirecting STDOUT and STDERR to', $log_file);
|
||||||
PTDEBUG && _d('Redirecting STDOUT and STDERR to', $self->{log_file});
|
|
||||||
close STDOUT;
|
close STDOUT;
|
||||||
open STDOUT, '>>', $self->{log_file}
|
open STDOUT, '>>', $log_file
|
||||||
or die "Cannot open log file $self->{log_file}: $OS_ERROR";
|
or die "Cannot open log file $log_file: $OS_ERROR";
|
||||||
|
|
||||||
close STDERR;
|
close STDERR;
|
||||||
open STDERR, ">&STDOUT"
|
open STDERR, ">&STDOUT"
|
||||||
@@ -4166,82 +4193,123 @@ sub daemonize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PTDEBUG && _d('I am child', $PID);
|
||||||
|
|
||||||
|
if ( $pid_file ) {
|
||||||
|
$self->_update_pid_file(
|
||||||
|
pid => $PID, # child's pid
|
||||||
|
pid_file => $pid_file,
|
||||||
|
);
|
||||||
|
$self->{pid_file_owner} = $PID;
|
||||||
|
}
|
||||||
|
|
||||||
|
POSIX::setsid() or die "Cannot start a new session: $OS_ERROR";
|
||||||
|
chdir '/' or die "Cannot chdir to /: $OS_ERROR";
|
||||||
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub check_PID_file {
|
|
||||||
my ( $self, $file ) = @_;
|
sub _make_pid_file {
|
||||||
my $PID_file = $self ? $self->{PID_file} : $file;
|
my ($self, %args) = @_;
|
||||||
PTDEBUG && _d('Checking PID file', $PID_file);
|
my @required_args = qw(pid pid_file);
|
||||||
if ( $PID_file && -f $PID_file ) {
|
foreach my $arg ( @required_args ) {
|
||||||
my $pid;
|
die "I need a $arg argument" unless $args{$arg};
|
||||||
eval {
|
};
|
||||||
chomp($pid = (slurp_file($PID_file) || ''));
|
my $pid = $args{pid};
|
||||||
};
|
my $pid_file = $args{pid_file};
|
||||||
if ( $EVAL_ERROR ) {
|
|
||||||
die "The PID file $PID_file already exists but it cannot be read: "
|
eval {
|
||||||
. $EVAL_ERROR;
|
sysopen(PID_FH, $pid_file, O_RDWR|O_CREAT|O_EXCL) or die $OS_ERROR;
|
||||||
}
|
print PID_FH $PID, "\n";
|
||||||
PTDEBUG && _d('PID file exists; it contains PID', $pid);
|
close PID_FH;
|
||||||
if ( $pid ) {
|
};
|
||||||
my $pid_is_alive = kill 0, $pid;
|
if ( my $e = $EVAL_ERROR ) {
|
||||||
if ( $pid_is_alive ) {
|
if ( $e =~ m/file exists/i ) {
|
||||||
die "The PID file $PID_file already exists "
|
my $old_pid = $self->_check_pid_file(
|
||||||
. " and the PID that it contains, $pid, is running";
|
pid_file => $pid_file,
|
||||||
}
|
);
|
||||||
else {
|
if ( $old_pid ) {
|
||||||
warn "Overwriting PID file $PID_file because the PID that it "
|
warn "Overwriting PID file $pid_file because PID $old_pid "
|
||||||
. "contains, $pid, is not running";
|
. "is not running.\n";
|
||||||
}
|
}
|
||||||
|
$self->_update_pid_file(
|
||||||
|
pid => $PID,
|
||||||
|
pid_file => $pid_file
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
die "The PID file $PID_file already exists but it does not "
|
die "Error creating PID file $pid_file: $e\n";
|
||||||
. "contain a PID";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
PTDEBUG && _d('No PID file');
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub make_PID_file {
|
sub _check_pid_file {
|
||||||
my ( $self ) = @_;
|
my ($self, %args) = @_;
|
||||||
if ( exists $self->{child} ) {
|
my @required_args = qw(pid_file);
|
||||||
die "Do not call Daemon::make_PID_file() for daemonized scripts";
|
foreach my $arg ( @required_args ) {
|
||||||
}
|
die "I need a $arg argument" unless $args{$arg};
|
||||||
$self->_make_PID_file();
|
};
|
||||||
$self->{PID_owner} = $PID;
|
my $pid_file = $args{pid_file};
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _make_PID_file {
|
PTDEBUG && _d('Checking if PID in', $pid_file, 'is running');
|
||||||
my ( $self ) = @_;
|
|
||||||
|
|
||||||
my $PID_file = $self->{PID_file};
|
if ( ! -f $pid_file ) {
|
||||||
if ( !$PID_file ) {
|
PTDEBUG && _d('PID file', $pid_file, 'does not exist');
|
||||||
PTDEBUG && _d('No PID file to create');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$self->check_PID_file();
|
open my $fh, '<', $pid_file
|
||||||
|
or die "Error opening $pid_file: $OS_ERROR";
|
||||||
|
my $pid = do { local $/; <$fh> };
|
||||||
|
chomp($pid) if $pid;
|
||||||
|
close $fh
|
||||||
|
or die "Error closing $pid_file: $OS_ERROR";
|
||||||
|
|
||||||
open my $PID_FH, '>', $PID_file
|
if ( $pid ) {
|
||||||
or die "Cannot open PID file $PID_file: $OS_ERROR";
|
PTDEBUG && _d('Checking if PID', $pid, 'is running');
|
||||||
print $PID_FH $PID
|
my $pid_is_alive = kill 0, $pid;
|
||||||
or die "Cannot print to PID file $PID_file: $OS_ERROR";
|
if ( $pid_is_alive ) {
|
||||||
close $PID_FH
|
die "PID file $pid_file exists and PID $pid is running\n";
|
||||||
or die "Cannot close PID file $PID_file: $OS_ERROR";
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
die "PID file $pid_file exists but it is empty. Remove the file "
|
||||||
|
. "if the process is no longer running.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _update_pid_file {
|
||||||
|
my ($self, %args) = @_;
|
||||||
|
my @required_args = qw(pid pid_file);
|
||||||
|
foreach my $arg ( @required_args ) {
|
||||||
|
die "I need a $arg argument" unless $args{$arg};
|
||||||
|
};
|
||||||
|
my $pid = $args{pid};
|
||||||
|
my $pid_file = $args{pid_file};
|
||||||
|
|
||||||
|
open my $fh, '>', $pid_file
|
||||||
|
or die "Cannot open $pid_file: $OS_ERROR";
|
||||||
|
print { $fh } $pid, "\n"
|
||||||
|
or die "Cannot print to $pid_file: $OS_ERROR";
|
||||||
|
close $fh
|
||||||
|
or warn "Cannot close $pid_file: $OS_ERROR";
|
||||||
|
|
||||||
PTDEBUG && _d('Created PID file:', $self->{PID_file});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _remove_PID_file {
|
sub remove_pid_file {
|
||||||
my ( $self ) = @_;
|
my ($self, $pid_file) = @_;
|
||||||
if ( $self->{PID_file} && -f $self->{PID_file} ) {
|
$pid_file ||= $self->{pid_file};
|
||||||
unlink $self->{PID_file}
|
if ( $pid_file && -f $pid_file ) {
|
||||||
or warn "Cannot remove PID file $self->{PID_file}: $OS_ERROR";
|
unlink $self->{pid_file}
|
||||||
|
or warn "Cannot remove PID file $pid_file: $OS_ERROR";
|
||||||
PTDEBUG && _d('Removed PID file');
|
PTDEBUG && _d('Removed PID file');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -4251,20 +4319,15 @@ sub _remove_PID_file {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub DESTROY {
|
sub DESTROY {
|
||||||
my ( $self ) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
$self->_remove_PID_file() if ($self->{PID_owner} || 0) == $PID;
|
if ( ($self->{pid_file_owner} || 0) == $PID ) {
|
||||||
|
$self->remove_pid_file();
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub slurp_file {
|
|
||||||
my ($file) = @_;
|
|
||||||
return unless $file;
|
|
||||||
open my $fh, "<", $file or die "Cannot open $file: $OS_ERROR";
|
|
||||||
return do { local $/; <$fh> };
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _d {
|
sub _d {
|
||||||
my ($package, undef, $line) = caller 0;
|
my ($package, undef, $line) = caller 0;
|
||||||
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
|
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
|
||||||
@@ -4795,17 +4858,15 @@ sub main {
|
|||||||
# ########################################################################
|
# ########################################################################
|
||||||
# Daemonize first so all output goes to the --log.
|
# Daemonize first so all output goes to the --log.
|
||||||
# ########################################################################
|
# ########################################################################
|
||||||
my $daemon;
|
my $daemon = Daemon->new(
|
||||||
|
daemonize => $o->get('daemonize'),
|
||||||
|
pid_file => $o->get('pid'),
|
||||||
|
log_file => $o->get('log'),
|
||||||
|
);
|
||||||
if ( !$o->get('send-data') ) {
|
if ( !$o->get('send-data') ) {
|
||||||
if ( $o->get('daemonize') ) {
|
$daemon->run();
|
||||||
$daemon = new Daemon(o=>$o);
|
PTDEBUG && _d('I am a daemon now');
|
||||||
$daemon->daemonize();
|
|
||||||
PTDEBUG && _d('I am a daemon now');
|
|
||||||
}
|
|
||||||
elsif ( $o->get('pid') ) {
|
|
||||||
$daemon = new Daemon(o=>$o);
|
|
||||||
$daemon->make_PID_file();
|
|
||||||
}
|
|
||||||
# If we daemonized, the parent has already exited and we're the child.
|
# If we daemonized, the parent has already exited and we're the child.
|
||||||
# We shared a copy of every Cxn with the parent, and the parent's copies
|
# We shared a copy of every Cxn with the parent, and the parent's copies
|
||||||
# were destroyed but the dbhs were not disconnected because the parent
|
# were destroyed but the dbhs were not disconnected because the parent
|
||||||
|
307
lib/Daemon.pm
307
lib/Daemon.pm
@@ -1,4 +1,4 @@
|
|||||||
# This program is copyright 2008-2011 Percona Ireland Ltd.
|
# This program is copyright 2008-2013 Percona Ireland Ltd.
|
||||||
# Feedback and improvements are welcome.
|
# Feedback and improvements are welcome.
|
||||||
#
|
#
|
||||||
# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
|
# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
|
||||||
@@ -17,59 +17,91 @@
|
|||||||
# ###########################################################################
|
# ###########################################################################
|
||||||
# Daemon package
|
# Daemon package
|
||||||
# ###########################################################################
|
# ###########################################################################
|
||||||
{
|
|
||||||
# Package: Daemon
|
|
||||||
# Daemon daemonizes the caller and handles daemon-related tasks like PID files.
|
|
||||||
package Daemon;
|
package Daemon;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings FATAL => 'all';
|
use warnings FATAL => 'all';
|
||||||
use English qw(-no_match_vars);
|
use English qw(-no_match_vars);
|
||||||
|
|
||||||
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
|
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
|
||||||
|
|
||||||
use POSIX qw(setsid);
|
use POSIX qw(setsid);
|
||||||
|
use Fcntl qw(:DEFAULT);
|
||||||
|
|
||||||
# The required o arg is an OptionParser object.
|
|
||||||
sub new {
|
sub new {
|
||||||
my ( $class, %args ) = @_;
|
my ($class, %args) = @_;
|
||||||
foreach my $arg ( qw(o) ) {
|
|
||||||
die "I need a $arg argument" unless $args{$arg};
|
|
||||||
}
|
|
||||||
my $o = $args{o};
|
|
||||||
my $self = {
|
my $self = {
|
||||||
o => $o,
|
log_file => $args{log_file},
|
||||||
log_file => $o->has('log') ? $o->get('log') : undef,
|
pid_file => $args{pid_file},
|
||||||
PID_file => $o->has('pid') ? $o->get('pid') : undef,
|
daemonize => $args{daemonize},
|
||||||
};
|
};
|
||||||
|
|
||||||
# undef because we can't call like $self->check_PID_file() yet.
|
|
||||||
check_PID_file(undef, $self->{PID_file});
|
|
||||||
|
|
||||||
PTDEBUG && _d('Daemonized child will log to', $self->{log_file});
|
|
||||||
return bless $self, $class;
|
return bless $self, $class;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub daemonize {
|
sub run {
|
||||||
my ( $self ) = @_;
|
my ($self, %args) = @_;
|
||||||
|
my $pid ||= $PID;
|
||||||
|
my $pid_file ||= $self->{pid_file};
|
||||||
|
my $log_file ||= $self->{log_file};
|
||||||
|
|
||||||
PTDEBUG && _d('About to fork and daemonize');
|
if ( $self->{daemonize} ) {
|
||||||
defined (my $pid = fork()) or die "Cannot fork: $OS_ERROR";
|
$self->_daemonize(
|
||||||
if ( $pid ) {
|
pid => $pid,
|
||||||
PTDEBUG && _d('Parent PID', $PID, 'exiting after forking child PID',$pid);
|
pid_file => $pid_file,
|
||||||
exit;
|
log_file => $log_file,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
elsif ( $pid_file ) {
|
||||||
|
$self->_make_pid_file(
|
||||||
|
pid => $pid,
|
||||||
|
pid_file => $pid_file,
|
||||||
|
);
|
||||||
|
$self->{pid_file_owner} = $pid;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PTDEBUG && _d('Neither --daemonize nor --pid was specified');
|
||||||
}
|
}
|
||||||
|
|
||||||
# I'm daemonized now.
|
return;
|
||||||
PTDEBUG && _d('Daemonizing child PID', $PID);
|
}
|
||||||
$self->{PID_owner} = $PID;
|
|
||||||
$self->{child} = 1;
|
|
||||||
|
|
||||||
POSIX::setsid() or die "Cannot start a new session: $OS_ERROR";
|
sub _daemonize {
|
||||||
chdir '/' or die "Cannot chdir to /: $OS_ERROR";
|
my ($self, %args) = @_;
|
||||||
|
my $pid = $args{pid};
|
||||||
|
my $pid_file = $args{pid_file};
|
||||||
|
my $log_file = $args{log_file};
|
||||||
|
|
||||||
$self->_make_PID_file();
|
PTDEBUG && _d('Daemonizing');
|
||||||
|
|
||||||
$OUTPUT_AUTOFLUSH = 1;
|
# First obtain the pid file or die trying. NOTE: we're still the parent
|
||||||
|
# so the pid file will contain the parent's pid at first. This is done
|
||||||
|
# to avoid a race condition between the parent checking for the pid file,
|
||||||
|
# forking, and the child actually obtaining the pid file. This way, if
|
||||||
|
# the parent obtains the pid file, the child is guaranteed to be the only
|
||||||
|
# process running.
|
||||||
|
if ( $pid_file ) {
|
||||||
|
eval {
|
||||||
|
$self->_make_pid_file(
|
||||||
|
pid => $pid, # parent's pid
|
||||||
|
pid_file => $pid_file,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
if ( $EVAL_ERROR ) {
|
||||||
|
die "Cannot daemonize: $EVAL_ERROR\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Fork, exit parent, continue as child process.
|
||||||
|
defined (my $child_pid = fork())
|
||||||
|
or die "Cannot fork: $OS_ERROR";
|
||||||
|
if ( $child_pid ) {
|
||||||
|
# I'm the parent.
|
||||||
|
PTDEBUG && _d('Forked child', $child_pid);
|
||||||
|
exit 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# I'm the child. First, open the log file, if any. Do this first
|
||||||
|
# so that all daemon/child output goes there.
|
||||||
|
|
||||||
# We used to only reopen STDIN to /dev/null if it's a tty because
|
# We used to only reopen STDIN to /dev/null if it's a tty because
|
||||||
# otherwise it may be a pipe, in which case we didn't want to break
|
# otherwise it may be a pipe, in which case we didn't want to break
|
||||||
@@ -82,12 +114,11 @@ sub daemonize {
|
|||||||
close STDIN;
|
close STDIN;
|
||||||
open STDIN, '/dev/null'
|
open STDIN, '/dev/null'
|
||||||
or die "Cannot reopen STDIN to /dev/null: $OS_ERROR";
|
or die "Cannot reopen STDIN to /dev/null: $OS_ERROR";
|
||||||
|
if ( $log_file ) {
|
||||||
if ( $self->{log_file} ) {
|
PTDEBUG && _d('Redirecting STDOUT and STDERR to', $log_file);
|
||||||
PTDEBUG && _d('Redirecting STDOUT and STDERR to', $self->{log_file});
|
|
||||||
close STDOUT;
|
close STDOUT;
|
||||||
open STDOUT, '>>', $self->{log_file}
|
open STDOUT, '>>', $log_file
|
||||||
or die "Cannot open log file $self->{log_file}: $OS_ERROR";
|
or die "Cannot open log file $log_file: $OS_ERROR";
|
||||||
|
|
||||||
# If we don't close STDERR explicitly, then prove Daemon.t fails
|
# If we don't close STDERR explicitly, then prove Daemon.t fails
|
||||||
# because STDERR gets written before STDOUT even though we print
|
# because STDERR gets written before STDOUT even though we print
|
||||||
@@ -114,94 +145,138 @@ sub daemonize {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# XXX: I don't think we need this?
|
||||||
|
# $OUTPUT_AUTOFLUSH = 1;
|
||||||
|
|
||||||
|
PTDEBUG && _d('I am child', $PID);
|
||||||
|
|
||||||
|
# Now update the pid file to contain the correct pid, i.e. the child's pid.
|
||||||
|
if ( $pid_file ) {
|
||||||
|
$self->_update_pid_file(
|
||||||
|
pid => $PID, # child's pid
|
||||||
|
pid_file => $pid_file,
|
||||||
|
);
|
||||||
|
$self->{pid_file_owner} = $PID;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Last: other misc daemon stuff.
|
||||||
|
POSIX::setsid() or die "Cannot start a new session: $OS_ERROR";
|
||||||
|
chdir '/' or die "Cannot chdir to /: $OS_ERROR";
|
||||||
|
|
||||||
|
# We're not fully daemonized.
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
# The file arg is optional. It's used when new() calls this sub
|
|
||||||
# because $self hasn't been created yet.
|
|
||||||
sub check_PID_file {
|
|
||||||
my ( $self, $file ) = @_;
|
|
||||||
my $PID_file = $self ? $self->{PID_file} : $file;
|
|
||||||
PTDEBUG && _d('Checking PID file', $PID_file);
|
|
||||||
if ( $PID_file && -f $PID_file ) {
|
|
||||||
my $pid;
|
|
||||||
eval {
|
|
||||||
chomp($pid = (slurp_file($PID_file) || ''));
|
|
||||||
};
|
|
||||||
if ( $EVAL_ERROR ) {
|
|
||||||
# Be safe and die if we can't check that a process is
|
|
||||||
# or is not already running.
|
|
||||||
die "The PID file $PID_file already exists but it cannot be read: "
|
|
||||||
. $EVAL_ERROR;
|
|
||||||
}
|
|
||||||
PTDEBUG && _d('PID file exists; it contains PID', $pid);
|
|
||||||
if ( $pid ) {
|
|
||||||
my $pid_is_alive = kill 0, $pid;
|
|
||||||
if ( $pid_is_alive ) {
|
|
||||||
die "The PID file $PID_file already exists "
|
|
||||||
. " and the PID that it contains, $pid, is running";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
warn "Overwriting PID file $PID_file because the PID that it "
|
|
||||||
. "contains, $pid, is not running";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
# Be safe and die if we can't check that a process is
|
|
||||||
# or is not already running.
|
|
||||||
die "The PID file $PID_file already exists but it does not "
|
|
||||||
. "contain a PID";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
PTDEBUG && _d('No PID file');
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
# Call this for non-daemonized scripts to make a PID file.
|
# Call this for non-daemonized scripts to make a PID file.
|
||||||
sub make_PID_file {
|
sub _make_pid_file {
|
||||||
my ( $self ) = @_;
|
my ($self, %args) = @_;
|
||||||
if ( exists $self->{child} ) {
|
my @required_args = qw(pid pid_file);
|
||||||
die "Do not call Daemon::make_PID_file() for daemonized scripts";
|
foreach my $arg ( @required_args ) {
|
||||||
|
die "I need a $arg argument" unless $args{$arg};
|
||||||
|
};
|
||||||
|
my $pid = $args{pid};
|
||||||
|
my $pid_file = $args{pid_file};
|
||||||
|
|
||||||
|
# "If O_CREAT and O_EXCL are set, open() shall fail if the file exists.
|
||||||
|
# The check for the existence of the file and the creation of the file
|
||||||
|
# if it does not exist shall be atomic with respect to other threads
|
||||||
|
# executing open() naming the same filename in the same directory with
|
||||||
|
# O_EXCL and O_CREAT set.
|
||||||
|
eval {
|
||||||
|
sysopen(PID_FH, $pid_file, O_RDWR|O_CREAT|O_EXCL) or die $OS_ERROR;
|
||||||
|
print PID_FH $PID, "\n";
|
||||||
|
close PID_FH;
|
||||||
|
};
|
||||||
|
if ( my $e = $EVAL_ERROR ) {
|
||||||
|
if ( $e =~ m/file exists/i ) {
|
||||||
|
# Check if the existing pid is running. If yes, then die,
|
||||||
|
# else this returns and we overwrite the pid file.
|
||||||
|
my $old_pid = $self->_check_pid_file(
|
||||||
|
pid_file => $pid_file,
|
||||||
|
);
|
||||||
|
if ( $old_pid ) {
|
||||||
|
warn "Overwriting PID file $pid_file because PID $old_pid "
|
||||||
|
. "is not running.\n";
|
||||||
|
}
|
||||||
|
$self->_update_pid_file(
|
||||||
|
pid => $PID,
|
||||||
|
pid_file => $pid_file
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
die "Error creating PID file $pid_file: $e\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$self->_make_PID_file();
|
|
||||||
# This causes the PID file to be auto-removed when this obj is destroyed.
|
|
||||||
$self->{PID_owner} = $PID;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Do not call this sub directly. For daemonized scripts, it's called
|
sub _check_pid_file {
|
||||||
# automatically from daemonize() if there's a --pid opt. For non-daemonized
|
my ($self, %args) = @_;
|
||||||
# scripts, call make_PID_file().
|
my @required_args = qw(pid_file);
|
||||||
sub _make_PID_file {
|
foreach my $arg ( @required_args ) {
|
||||||
my ( $self ) = @_;
|
die "I need a $arg argument" unless $args{$arg};
|
||||||
|
};
|
||||||
|
my $pid_file = $args{pid_file};
|
||||||
|
|
||||||
my $PID_file = $self->{PID_file};
|
PTDEBUG && _d('Checking if PID in', $pid_file, 'is running');
|
||||||
if ( !$PID_file ) {
|
|
||||||
PTDEBUG && _d('No PID file to create');
|
if ( ! -f $pid_file ) {
|
||||||
|
PTDEBUG && _d('PID file', $pid_file, 'does not exist');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
# We checked this in new() but we'll double check here.
|
open my $fh, '<', $pid_file
|
||||||
$self->check_PID_file();
|
or die "Error opening $pid_file: $OS_ERROR";
|
||||||
|
my $pid = do { local $/; <$fh> };
|
||||||
|
chomp($pid) if $pid;
|
||||||
|
close $fh
|
||||||
|
or die "Error closing $pid_file: $OS_ERROR";
|
||||||
|
|
||||||
open my $PID_FH, '>', $PID_file
|
if ( $pid ) {
|
||||||
or die "Cannot open PID file $PID_file: $OS_ERROR";
|
PTDEBUG && _d('Checking if PID', $pid, 'is running');
|
||||||
print $PID_FH $PID
|
my $pid_is_alive = kill 0, $pid;
|
||||||
or die "Cannot print to PID file $PID_file: $OS_ERROR";
|
if ( $pid_is_alive ) {
|
||||||
close $PID_FH
|
die "PID file $pid_file exists and PID $pid is running\n";
|
||||||
or die "Cannot close PID file $PID_file: $OS_ERROR";
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
# PID file but no PID: not sure what to do, so be safe and die;
|
||||||
|
# let the user figure it out (i.e. rm the pid file).
|
||||||
|
die "PID file $pid_file exists but it is empty. Remove the file "
|
||||||
|
. "if the process is no longer running.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _update_pid_file {
|
||||||
|
my ($self, %args) = @_;
|
||||||
|
my @required_args = qw(pid pid_file);
|
||||||
|
foreach my $arg ( @required_args ) {
|
||||||
|
die "I need a $arg argument" unless $args{$arg};
|
||||||
|
};
|
||||||
|
my $pid = $args{pid};
|
||||||
|
my $pid_file = $args{pid_file};
|
||||||
|
|
||||||
|
open my $fh, '>', $pid_file
|
||||||
|
or die "Cannot open $pid_file: $OS_ERROR";
|
||||||
|
print { $fh } $pid, "\n"
|
||||||
|
or die "Cannot print to $pid_file: $OS_ERROR";
|
||||||
|
close $fh
|
||||||
|
or warn "Cannot close $pid_file: $OS_ERROR";
|
||||||
|
|
||||||
PTDEBUG && _d('Created PID file:', $self->{PID_file});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _remove_PID_file {
|
sub remove_pid_file {
|
||||||
my ( $self ) = @_;
|
my ($self, $pid_file) = @_;
|
||||||
if ( $self->{PID_file} && -f $self->{PID_file} ) {
|
$pid_file ||= $self->{pid_file};
|
||||||
unlink $self->{PID_file}
|
if ( $pid_file && -f $pid_file ) {
|
||||||
or warn "Cannot remove PID file $self->{PID_file}: $OS_ERROR";
|
unlink $self->{pid_file}
|
||||||
|
or warn "Cannot remove PID file $pid_file: $OS_ERROR";
|
||||||
PTDEBUG && _d('Removed PID file');
|
PTDEBUG && _d('Removed PID file');
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -211,7 +286,7 @@ sub _remove_PID_file {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sub DESTROY {
|
sub DESTROY {
|
||||||
my ( $self ) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
# Remove the PID file only if we created it. There's two cases where
|
# Remove the PID file only if we created it. There's two cases where
|
||||||
# it might be removed wrongly. 1) When the obj first daemonizes itself,
|
# it might be removed wrongly. 1) When the obj first daemonizes itself,
|
||||||
@@ -220,21 +295,16 @@ sub DESTROY {
|
|||||||
# have it. 2) When daemonized code forks its children get copies of
|
# have it. 2) When daemonized code forks its children get copies of
|
||||||
# the Daemon obj which will also call this sub when they exit. We
|
# the Daemon obj which will also call this sub when they exit. We
|
||||||
# don't remove it then because the daemonized parent code won't have it.
|
# don't remove it then because the daemonized parent code won't have it.
|
||||||
# This trick works because $self->{PID_owner}=$PID is set once to the
|
# This trick works because $self->{pid_file_owner}=$PID is set once to the
|
||||||
# owner's $PID then this value is copied on fork. But the "== $PID"
|
# owner's $PID then this value is copied on fork. But the "== $PID"
|
||||||
# here is the forked copy's PID which won't match the owner's PID.
|
# here is the forked copy's PID which won't match the owner's PID.
|
||||||
$self->_remove_PID_file() if ($self->{PID_owner} || 0) == $PID;
|
if ( ($self->{pid_file_owner} || 0) == $PID ) {
|
||||||
|
$self->remove_pid_file();
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub slurp_file {
|
|
||||||
my ($file) = @_;
|
|
||||||
return unless $file;
|
|
||||||
open my $fh, "<", $file or die "Cannot open $file: $OS_ERROR";
|
|
||||||
return do { local $/; <$fh> };
|
|
||||||
}
|
|
||||||
|
|
||||||
sub _d {
|
sub _d {
|
||||||
my ($package, undef, $line) = caller 0;
|
my ($package, undef, $line) = caller 0;
|
||||||
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
|
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
|
||||||
@@ -244,7 +314,6 @@ sub _d {
|
|||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
}
|
|
||||||
# ###########################################################################
|
# ###########################################################################
|
||||||
# End Daemon package
|
# End Daemon package
|
||||||
# ###########################################################################
|
# ###########################################################################
|
||||||
|
105
t/lib/Daemon.t
105
t/lib/Daemon.t
@@ -9,31 +9,28 @@ BEGIN {
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings FATAL => 'all';
|
use warnings FATAL => 'all';
|
||||||
use English qw(-no_match_vars);
|
use English qw(-no_match_vars);
|
||||||
|
|
||||||
use Test::More;
|
use Test::More;
|
||||||
use Time::HiRes qw(sleep);
|
use Time::HiRes qw(sleep);
|
||||||
use File::Temp qw( tempfile );
|
use File::Temp qw(tempfile);
|
||||||
|
|
||||||
use Daemon;
|
use Daemon;
|
||||||
use OptionParser;
|
|
||||||
use PerconaTest;
|
use PerconaTest;
|
||||||
#plan skip_all => "Hm";
|
|
||||||
use constant PTDEVDEBUG => $ENV{PTDEVDEBUG} || 0;
|
use constant PTDEVDEBUG => $ENV{PTDEVDEBUG} || 0;
|
||||||
|
|
||||||
my $o = new OptionParser(file => "$trunk/t/lib/samples/daemonizes.pl");
|
my $cmd = "$trunk/t/lib/samples/daemonizes.pl";
|
||||||
my $d = new Daemon(o=>$o);
|
my $pid_file = "/tmp/pt-daemon-test.pid.$PID";
|
||||||
|
my $log_file = "/tmp/pt-daemon-test.log.$PID";
|
||||||
my $pid_file = '/tmp/daemonizes.pl.pid';
|
|
||||||
my $log_file = '/tmp/daemonizes.output';
|
|
||||||
sub rm_tmp_files() {
|
sub rm_tmp_files() {
|
||||||
-e $pid_file && (unlink $pid_file || die "Error removing $pid_file");
|
-f $pid_file && (unlink $pid_file || die "Error removing $pid_file");
|
||||||
-e $log_file && (unlink $log_file || die "Error removing $log_file");
|
-f $log_file && (unlink $log_file || die "Error removing $log_file");
|
||||||
}
|
}
|
||||||
|
|
||||||
# ############################################################################
|
# ############################################################################
|
||||||
# Test that it daemonizes, creates a PID file, and removes that PID file.
|
# Test that it daemonizes, creates a PID file, and removes that PID file.
|
||||||
# ############################################################################
|
# ############################################################################
|
||||||
rm_tmp_files();
|
|
||||||
|
|
||||||
my $cmd = "$trunk/t/lib/samples/daemonizes.pl";
|
|
||||||
my $ret_val = system("$cmd 5 --daemonize --pid $pid_file >/dev/null 2>&1");
|
my $ret_val = system("$cmd 5 --daemonize --pid $pid_file >/dev/null 2>&1");
|
||||||
die 'Cannot test Daemon.pm because t/daemonizes.pl is not working'
|
die 'Cannot test Daemon.pm because t/daemonizes.pl is not working'
|
||||||
unless $ret_val == 0;
|
unless $ret_val == 0;
|
||||||
@@ -41,16 +38,34 @@ die 'Cannot test Daemon.pm because t/daemonizes.pl is not working'
|
|||||||
PerconaTest::wait_for_files($pid_file);
|
PerconaTest::wait_for_files($pid_file);
|
||||||
|
|
||||||
my $output = `ps wx | grep '$cmd 5' | grep -v grep`;
|
my $output = `ps wx | grep '$cmd 5' | grep -v grep`;
|
||||||
like($output, qr/$cmd/, 'Daemonizes');
|
|
||||||
ok(-f $pid_file, 'Creates PID file');
|
|
||||||
|
|
||||||
my ($pid) = $output =~ /\s*(\d+)\s+/;
|
like(
|
||||||
|
$output,
|
||||||
|
qr/$cmd/,
|
||||||
|
'Daemonizes'
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(
|
||||||
|
-f $pid_file,
|
||||||
|
'Creates PID file'
|
||||||
|
);
|
||||||
|
|
||||||
|
my ($pid) = $output =~ /^\s*(\d+)\s+/;
|
||||||
$output = slurp_file($pid_file);
|
$output = slurp_file($pid_file);
|
||||||
is($output, $pid, 'PID file has correct PID');
|
chomp($output) if $output;
|
||||||
|
|
||||||
|
is(
|
||||||
|
$output,
|
||||||
|
$pid,
|
||||||
|
'PID file has correct PID'
|
||||||
|
);
|
||||||
|
|
||||||
# Wait until the process goes away
|
# Wait until the process goes away
|
||||||
PerconaTest::wait_until(sub { !kill(0, $pid) });
|
PerconaTest::wait_until(sub { !kill(0, $pid) });
|
||||||
ok(! -f $pid_file, 'Removes PID file upon exit');
|
ok(
|
||||||
|
! -f $pid_file,
|
||||||
|
'Removes PID file upon exit'
|
||||||
|
);
|
||||||
|
|
||||||
# ############################################################################
|
# ############################################################################
|
||||||
# Check that STDOUT can be redirected
|
# Check that STDOUT can be redirected
|
||||||
@@ -59,10 +74,19 @@ rm_tmp_files();
|
|||||||
|
|
||||||
system("$cmd 0 --daemonize --log $log_file");
|
system("$cmd 0 --daemonize --log $log_file");
|
||||||
PerconaTest::wait_for_files($log_file);
|
PerconaTest::wait_for_files($log_file);
|
||||||
ok(-f $log_file, 'Log file exists');
|
|
||||||
|
ok(
|
||||||
|
-f $log_file,
|
||||||
|
'Log file exists'
|
||||||
|
);
|
||||||
|
|
||||||
$output = slurp_file($log_file);
|
$output = slurp_file($log_file);
|
||||||
like($output, qr/STDOUT\nSTDERR\n/, 'STDOUT and STDERR went to log file');
|
|
||||||
|
like(
|
||||||
|
$output,
|
||||||
|
qr/STDOUT\nSTDERR\n/,
|
||||||
|
'STDOUT and STDERR went to log file'
|
||||||
|
);
|
||||||
|
|
||||||
my $log_size = -s $log_file;
|
my $log_size = -s $log_file;
|
||||||
PTDEVDEBUG && PerconaTest::_d('log size', $log_size);
|
PTDEVDEBUG && PerconaTest::_d('log size', $log_size);
|
||||||
@@ -71,6 +95,7 @@ PTDEVDEBUG && PerconaTest::_d('log size', $log_size);
|
|||||||
system("$cmd 0 --daemonize --log $log_file");
|
system("$cmd 0 --daemonize --log $log_file");
|
||||||
PerconaTest::wait_until(sub { -s $log_file > $log_size });
|
PerconaTest::wait_until(sub { -s $log_file > $log_size });
|
||||||
$output = slurp_file($log_file);
|
$output = slurp_file($log_file);
|
||||||
|
|
||||||
like(
|
like(
|
||||||
$output,
|
$output,
|
||||||
qr/STDOUT\nSTDERR\nSTDOUT\nSTDERR\n/,
|
qr/STDOUT\nSTDERR\nSTDOUT\nSTDERR\n/,
|
||||||
@@ -82,6 +107,7 @@ like(
|
|||||||
# ##########################################################################
|
# ##########################################################################
|
||||||
rm_tmp_files();
|
rm_tmp_files();
|
||||||
diag(`touch $pid_file`);
|
diag(`touch $pid_file`);
|
||||||
|
|
||||||
ok(
|
ok(
|
||||||
-f $pid_file,
|
-f $pid_file,
|
||||||
'PID file already exists'
|
'PID file already exists'
|
||||||
@@ -90,7 +116,7 @@ ok(
|
|||||||
$output = `$cmd 2 --daemonize --pid $pid_file 2>&1`;
|
$output = `$cmd 2 --daemonize --pid $pid_file 2>&1`;
|
||||||
like(
|
like(
|
||||||
$output,
|
$output,
|
||||||
qr{The PID file $pid_file already exists},
|
qr{PID file $pid_file exists},
|
||||||
'Dies if PID file already exists'
|
'Dies if PID file already exists'
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -182,7 +208,7 @@ like(
|
|||||||
|
|
||||||
like(
|
like(
|
||||||
slurp_file($tempfile),
|
slurp_file($tempfile),
|
||||||
qr/$pid, is not running/,
|
qr/Overwriting PID file $pid_file because PID $pid is not running/,
|
||||||
'Says that old PID is not running (issue 419)'
|
'Says that old PID is not running (issue 419)'
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -209,54 +235,55 @@ chomp($pid = slurp_file($pid_file));
|
|||||||
$output = `$cmd 0 --daemonize --pid $pid_file 2>&1`;
|
$output = `$cmd 0 --daemonize --pid $pid_file 2>&1`;
|
||||||
like(
|
like(
|
||||||
$output,
|
$output,
|
||||||
qr/$pid, is running/,
|
qr/PID file $pid_file exists and PID $pid is running/,
|
||||||
'Says that PID is running (issue 419)'
|
'Says that PID is running (issue 419)'
|
||||||
);
|
);
|
||||||
|
|
||||||
kill SIGKILL => $pid
|
if ( $pid ) {
|
||||||
if $pid;
|
kill 9, $pid;
|
||||||
|
}
|
||||||
|
|
||||||
sleep 1;
|
sleep 0.25;
|
||||||
rm_tmp_files();
|
rm_tmp_files();
|
||||||
|
|
||||||
# #############################################################################
|
# #############################################################################
|
||||||
# Test auto-PID file removal without having to daemonize (for issue 391).
|
# Test auto-PID file removal without having to daemonize (for issue 391).
|
||||||
# #############################################################################
|
# #############################################################################
|
||||||
|
my $pid_file2 = "/tmp/pt-daemon-test.pid2.$PID";
|
||||||
{
|
{
|
||||||
@ARGV = qw(--pid /tmp/d2.pid);
|
my $d2 = Daemon->new(
|
||||||
$o->get_specs("$trunk/t/lib/samples/daemonizes.pl");
|
pid_file => $pid_file2,
|
||||||
$o->get_opts();
|
);
|
||||||
my $d2 = new Daemon(o=>$o);
|
$d2->run();
|
||||||
$d2->make_PID_file();
|
|
||||||
ok(
|
ok(
|
||||||
-f '/tmp/d2.pid',
|
-f $pid_file2,
|
||||||
'PID file for non-daemon exists'
|
'PID file for non-daemon exists'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
# Since $d2 was locally scoped, it should have been destoryed by now.
|
# Since $d2 was locally scoped, it should have been destoryed by now.
|
||||||
# This should have caused the PID file to be automatically removed.
|
# This should have caused the PID file to be automatically removed.
|
||||||
ok(
|
ok(
|
||||||
!-f '/tmpo/d2.pid',
|
!-f $pid_file2,
|
||||||
'PID file auto-removed for non-daemon'
|
'PID file auto-removed for non-daemon'
|
||||||
);
|
);
|
||||||
|
|
||||||
# We should still die if the PID file already exists,
|
# We should still die if the PID file already exists,
|
||||||
# even if we're not a daemon.
|
# even if we're not a daemon.
|
||||||
{
|
{
|
||||||
`touch /tmp/d2.pid`;
|
diag(`touch $pid_file2`);
|
||||||
@ARGV = qw(--pid /tmp/d2.pid);
|
|
||||||
$o->get_opts();
|
|
||||||
eval {
|
eval {
|
||||||
my $d2 = new Daemon(o=>$o); # should die here actually
|
my $d2 = Daemon->new(
|
||||||
$d2->make_PID_file();
|
pid_file => $pid_file2,
|
||||||
|
);
|
||||||
|
$d2->run();
|
||||||
};
|
};
|
||||||
like(
|
like(
|
||||||
$EVAL_ERROR,
|
$EVAL_ERROR,
|
||||||
qr{PID file /tmp/d2.pid already exists},
|
qr/PID file $pid_file2 exists/,
|
||||||
'Dies if PID file already exists for non-daemon'
|
'Dies if PID file already exists for non-daemon'
|
||||||
);
|
);
|
||||||
|
|
||||||
diag(`rm -rf /tmp/d2.pid >/dev/null`);
|
unlink $pid_file2 if -f $pid_file2;
|
||||||
}
|
}
|
||||||
|
|
||||||
# #############################################################################
|
# #############################################################################
|
||||||
|
@@ -12,7 +12,9 @@ BEGIN {
|
|||||||
use strict;
|
use strict;
|
||||||
use warnings FATAL => 'all';
|
use warnings FATAL => 'all';
|
||||||
use English qw(-no_match_vars);
|
use English qw(-no_match_vars);
|
||||||
use constant PTDEVDEBUG => $ENV{PTDEVDEBUG};
|
|
||||||
|
use constant PTDEBUG => $ENV{PTDEBUG} || 0;
|
||||||
|
use constant PTDEVDEBUG => $ENV{PTDEVDEBUG} || 0;
|
||||||
|
|
||||||
use Time::HiRes qw(sleep);
|
use Time::HiRes qw(sleep);
|
||||||
|
|
||||||
@@ -31,22 +33,20 @@ if ( !defined $sleep_time ) {
|
|||||||
|
|
||||||
$o->usage_or_errors();
|
$o->usage_or_errors();
|
||||||
|
|
||||||
my $daemon;
|
my $daemon = Daemon->new(
|
||||||
if ( $o->get('daemonize') ) {
|
daemonize => $o->get('daemonize'),
|
||||||
PTDEVDEBUG && PerconaTest::_d('daemonizing');
|
pid_file => $o->get('pid'),
|
||||||
|
log_file => $o->get('log'),
|
||||||
|
);
|
||||||
|
|
||||||
$OUTPUT_AUTOFLUSH = 1;
|
$daemon->run();
|
||||||
|
PTDEVDEBUG && PerconaTest::_d('daemonized');
|
||||||
|
|
||||||
$daemon = new Daemon(o=>$o);
|
print "STDOUT\n";
|
||||||
$daemon->daemonize();
|
print STDERR "STDERR\n";
|
||||||
PTDEVDEBUG && PerconaTest::_d('daemonized');
|
|
||||||
|
|
||||||
print "STDOUT\n";
|
PTDEVDEBUG && PerconaTest::_d('daemon sleep', $sleep_time);
|
||||||
print STDERR "STDERR\n";
|
sleep $sleep_time;
|
||||||
|
|
||||||
PTDEVDEBUG && PerconaTest::_d('daemon sleep', $sleep_time);
|
|
||||||
sleep $sleep_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
PTDEVDEBUG && PerconaTest::_d('daemon done');
|
PTDEVDEBUG && PerconaTest::_d('daemon done');
|
||||||
exit;
|
exit;
|
||||||
|
Reference in New Issue
Block a user