system 1, "perl stuff.pl";
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] |
I use the Win32::Process module, which allows a bit more control. | [reply] |
Here's a demo program showing how to write a cross-platform Windows/Linux background process spawner
#!/usr/bin/perl
use warnings;
use strict;
use Carp;
use Time::HiRes;
use POSIX 'setsid';
my $child_pid;
my $child_proc;
my $cmd = "./aprogram.exe";
my $debug = 1;
start_child();
sleep(5.0);
stop_child();
sub start_child
{
die "cannot execute cmd: $cmd" unless -x $cmd;
if ($^O eq 'MSWin32') # Windows
{
require Win32::Process;
Win32::Process::Create($child_proc, $cmd, $cmd, 0, 0, ".") || confess "Could not spawn child: $!";
$child_pid = $child_proc->GetProcessID();
}
else # Unix
{
$SIG{CHLD} = 'IGNORE';
$child_pid = fork();
unless (defined $child_pid)
{
confess "Could not spawn child (Unix): $!";
}
if ($child_pid == 0 ) # child
{
unless ($debug)
{
open STDIN, "<", "/dev/null" or die "Can't read /dev/null: $!";
open STDOUT, ">", "/dev/null" or die "Can't write /dev/null: $!";
}
setsid or warn "setsid cannot start a new session: $!";
unless ($debug)
{
open STDERR, '>&STDOUT' or die "Can't dup stdout: $!";
}
local $| = 1;
unless (exec($cmd))
{
confess "Could not start child: $cmd: $!";
CORE::exit(0);
}
}
# parent
$SIG{CHLD} = 'DEFAULT';
}
# catch early child exit, e.g. if program path is incorrect
sleep(1.0);
POSIX::waitpid(-1, POSIX::WNOHANG()); # clean up any defunct child process
if (kill(0,$child_pid))
{
print "Started child process id $child_pid\n";
}
else
{
warn "Child process exited quickly: $cmd: process $child_pid";
}
}
sub stop_child
{
if ($^O eq 'MSWin32') # Windows
{
Win32::Process::KillProcess($child_pid,0);
}
else # Unix
{
kill 9, $child_pid || warn "could not kill process $child_pid: $!";
}
print "Stopped child process id $child_pid\n";
}
| [reply] |
@ Peter Dragon,
Did you ever test your script? It can never work as the script starts with a die........
| [reply] |
@ Peter Dragon, Did you ever test your script? It can never work as the script starts with a die........
A conditional die, makes all the difference in the world
$ perl -le " die 6 if 9 "
6 at -e line 1.
$ perl -le " die 6 if not 9 ; die 8 "
8 at -e line 1.
| [reply] [d/l] |
The most portable way of doing this that I can think of is to use fork followed by exec. Consider the following:
sub run_in_bg {
my $pid = fork;
die "Can't fork a new process" unless defined $pid;
# child gets PID 0
if ($pid == 0) {
exec(@_) || die "Can't exec $_[0]";
}
# in case you wanted to use waitpid on it
return $pid;
}
You'd call this the same way you'd call system, except now it forks a new process before running the first arg. | [reply] [d/l] |
Be careful with that solution. Fork on windows is emulated using threads, not real processes. See perlfork doc. This may not matter for your application, but you should be aware of it.
| [reply] |
I recently had to write a quick script that I wanted to run in the background indefinitely in Windows.
Tried to find a solution with Win32::Process, but whenever I killed the parent process the child would die as well.
Anyway, I went ahead and ended up doing this:
fork() ? exit(): exec("$cmd $args");
I know Windows implements fork differently which probably explains an odd bug where the parent process hangs instead of exiting. This is fine, I kill it manually. The end result - a headless, background child process - still works fine.
Annoying side effect of Perl's fork() implementation on Windows, the PID is not valid. So I cannot keep track of it to kill the process later.
Actually, I'm a little baffled that this method works. Isn't Perl fork() on Windows supposed to simulate another process, not actually create another one? I believe it has something to do with the nature of exec(). | [reply] [d/l] |