Re: Apache2::SubProcess subprocess not subprocessing properly

2010-02-20 Thread Torsten Förtsch
Tosh,

On Tuesday 09 February 2010 14:21:57 Tosh Cooey wrote:
> Hi after much trial and all error I am seeing that the browser 
> connection closing is also stopping my subprocess.
> 

I don't know what you are trying to achieve and I don't use 
Apache2::Subprocess much. What I do to fork off processes instead is this:

  my $close_fd=sub {
use POSIX ();
my %save=(2=>1);   # keep STDERR
undef @sa...@_} if( @_ );
opendir my $d, "/proc/self/fd" or do {
  warn "Cannot open directory /proc/self/fd: $!\n";
  POSIX::_exit -1;  # try this first to avoid buffer flushing
  CORE::exit -1;
};

while (defined(my $fd=readdir $d)) {
  next unless $fd=~/^\d+$/;
  POSIX::close $fd unless exists $save{$fd};
}
  };

  my $spawn=sub {
use POSIX ();
my ($daemon_should_survive_apache_restart, @args)=...@_;

local $SIG{CHLD}='IGNORE';
my $pid;
# yes, even fork can fail
select undef, undef, undef, .1 while( !defined($pid=fork) );
unless( $pid ) {# child
  # 2nd fork to cut parent relationship with a mod_perl apache
  select undef, undef, undef, .1 while( !defined($pid=fork) );
  if( $pid ) {
POSIX::_exit 0;
CORE::exit 0;
  } else {
if( ref($daemon_should_survive_apache_restart) ) {
  $close_fd->($daemon_should_survive_apache_restart->{fd});
  POSIX::setsid if( $daemon_should_survive_apache_restart->{survive} );
} else {
  $close_fd->();
  POSIX::setsid if( $daemon_should_survive_apache_restart );
}

if( 'CODE' eq ref $args[0] ) {
  my $f=shift @args;
  # TODO: restore %ENV and exit() behavior
  eval {$f->(@args)};
  CORE::exit 0;
} else {
  {exec @args;} # extra block to suppress a warning
  POSIX::_exit -1;
  CORE::exit -1;
}
  }
}
waitpid $pid, 0;# avoid a zombie on some OS
  };

And this is how to use it:

  $spawn->({survive=>1}, sub {
my ($n, $sleep)=...@_;
for(1..$n) {
  warn "sleeping $sleep\n";
  sleep $sleep;
}
warn "Done\n";
  }, 10, 2 );

or

  $spawn->
(undef, # don't survive apache stop
 qw/bash -c/,'for (( i=0; i<10; i++ )); do echo "opi" >&2; sleep 2; done')

The first argument to $spawn is an options hash with 2 possible options:

  survive=>BOOLEAN# should the subprocess survive an apache stop or not
  fd=>\...@list_of_open_file_descriptors_to_preserve

Normally the $spawn will close all files save for STDERR. With the fd option 
one can preserve other files such as database connections or other.

With the survive option true the child process will be the leader of a new 
process group.

NOTES:

- The $close_fd function is Linux-specific. I couldn't think of a really 
portable (at least across UNICES) way to get all open file descriptors of the 
current process.

- The waitpid at the end of $spawn is not necessary under Linux since 
$SIG{CHLD}='IGNORE' already takes care of zombies. But other systems need it.

- Keep in mind that %ENV and exit() work different under mod_perl. If you pass 
a subroutine this behavior remains.

Torsten


Re: Apache2::SubProcess subprocess not subprocessing properly

2010-02-20 Thread Tosh Cooey
You aren't going to like this, and maybe what you're doing is for a 
really complex situation, but it really shouldn't be so complex to just 
spawn off a long running process that you don't care to ever hear back 
from, honestly.


Tosh


Torsten Förtsch wrote:

Tosh,

On Tuesday 09 February 2010 14:21:57 Tosh Cooey wrote:
Hi after much trial and all error I am seeing that the browser 
connection closing is also stopping my subprocess.




I don't know what you are trying to achieve and I don't use 
Apache2::Subprocess much. What I do to fork off processes instead is this:


  my $close_fd=sub {
use POSIX ();
my %save=(2=>1);   # keep STDERR
undef @sa...@_} if( @_ );
opendir my $d, "/proc/self/fd" or do {
  warn "Cannot open directory /proc/self/fd: $!\n";
  POSIX::_exit -1;  # try this first to avoid buffer flushing
  CORE::exit -1;
};

while (defined(my $fd=readdir $d)) {
  next unless $fd=~/^\d+$/;
  POSIX::close $fd unless exists $save{$fd};
}
  };

  my $spawn=sub {
use POSIX ();
my ($daemon_should_survive_apache_restart, @args)=...@_;

local $SIG{CHLD}='IGNORE';
my $pid;
# yes, even fork can fail
select undef, undef, undef, .1 while( !defined($pid=fork) );
unless( $pid ) {# child
  # 2nd fork to cut parent relationship with a mod_perl apache
  select undef, undef, undef, .1 while( !defined($pid=fork) );
  if( $pid ) {
POSIX::_exit 0;
CORE::exit 0;
  } else {
if( ref($daemon_should_survive_apache_restart) ) {
  $close_fd->($daemon_should_survive_apache_restart->{fd});
  POSIX::setsid if( $daemon_should_survive_apache_restart->{survive} );
} else {
  $close_fd->();
  POSIX::setsid if( $daemon_should_survive_apache_restart );
}

if( 'CODE' eq ref $args[0] ) {
  my $f=shift @args;
  # TODO: restore %ENV and exit() behavior
  eval {$f->(@args)};
  CORE::exit 0;
} else {
  {exec @args;} # extra block to suppress a warning
  POSIX::_exit -1;
  CORE::exit -1;
}
  }
}
waitpid $pid, 0;# avoid a zombie on some OS
  };

And this is how to use it:

  $spawn->({survive=>1}, sub {
my ($n, $sleep)=...@_;
for(1..$n) {
  warn "sleeping $sleep\n";
  sleep $sleep;
}
warn "Done\n";
  }, 10, 2 );

or

  $spawn->
(undef, # don't survive apache stop
 qw/bash -c/,'for (( i=0; i<10; i++ )); do echo "opi" >&2; sleep 2; done')

The first argument to $spawn is an options hash with 2 possible options:

  survive=>BOOLEAN# should the subprocess survive an apache stop or not
  fd=>\...@list_of_open_file_descriptors_to_preserve

Normally the $spawn will close all files save for STDERR. With the fd option 
one can preserve other files such as database connections or other.


With the survive option true the child process will be the leader of a new 
process group.


NOTES:

- The $close_fd function is Linux-specific. I couldn't think of a really 
portable (at least across UNICES) way to get all open file descriptors of the 
current process.


- The waitpid at the end of $spawn is not necessary under Linux since 
$SIG{CHLD}='IGNORE' already takes care of zombies. But other systems need it.


- Keep in mind that %ENV and exit() work different under mod_perl. If you pass 
a subroutine this behavior remains.


Torsten



--
McIntosh Cooey - Twelve Hundred Group LLC - http://www.1200group.com/


Re: Apache2::SubProcess sucks

2010-02-20 Thread Tosh Cooey
Maybe it does or doesn't work under MP::R, the answer to that is perhaps 
individual.


Anyway, the solution, at least so far until I run into other problems, 
seems to be to just make a system() call and the called program uses 
Proc::Daemon and things *seem* to work fine in testing, we'll see when 
it hits production...


Tosh



Fred Moyer wrote:

I haven't been following this thread too closely, but is there a
reason you aren't using PerlHandlers instead of ModPerl::Registry?
MP::R is meant mostly for CGI migration, so it is probably not widely
tested with Apache2::SubProcess calls.  I'd suggest trying your
external call under a PerlHandler instead and see if that works.

On Fri, Feb 19, 2010 at 1:52 PM, Tosh Cooey  wrote:

Seriously, you know what, the code below doesn't even work.

And if I get rid of the redirect and replace it with some nice pretty text:

print "Content-type: text/html\n\nTesting";

You know what?  The warning for 1 (from the 'for' loop) is printed and then
it all stops, probably as the browser connection "closes".

Hiding it behind more forks made it work once but then never again.

So it is my belief that Apache2::SubProcess sucks dirty things, and that
belief won't change until I see proof to the contrary.

On a related note, anyone have tips for avoiding zombies in CGI forking?

Tosh



Tosh Cooey wrote:

Hi after much trial and all error I am seeing that the browser connection
closing is also stopping my subprocess.

The main ModPerl::Registry program looks like this:
### file.pl ###
use Apache2::SubProcess ();
use JSON();

&main(shift);

sub main {
 my $r = shift;
 ...
 $r->spawn_proc_prog ('/web/html/file_fork.pl', \...@argv);
 return print $cgi->redirect('index.pl');
}
###

And

### file_fork.pl ###
use JSON();
use warnings;
use POSIX 'setsid';
chdir '/'or die "Can't chdir to /: $!";
open STDIN, '/dev/null'  or die "Can't read /dev/null: $!";
open STDOUT, '+>>', '/tmp/debug.txt' or die "Can't write to
/tmp/debug.txt: $!";
open STDERR, '>&STDOUT'  or die "Can't dup stdout: $!";
setsid or die "Can't start a new session: $!";

 # run your code here or call exec to another program
foreach my $num (1..10) {
 warn $num;
 sleep(1);
}
###

When file.pl is executed it calls file_fork.pl and file_fork starts to
print 1, 2, 3 and then stops around 2 or 3 depending on how long my browser
is connected.

Are there any glaring errors that anyone sees?  It should work shouldn't
it, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 after 10 seconds...

Thank-you all!

Tosh



--
McIntosh Cooey - Twelve Hundred Group LLC - http://www.1200group.com/





--
McIntosh Cooey - Twelve Hundred Group LLC - http://www.1200group.com/


Re: Apache2::SubProcess sucks

2010-02-20 Thread mackenna

On Feb 20, 2010, at 7:01 AM, Tosh Cooey wrote:

Anyway, the solution, at least so far until I run into other  
problems, seems to be to just make a system() call and the called  
program uses Proc::Daemon and things *seem* to work fine in  
testing, we'll see when it hits production...


Tosh


Doesn't a process that calls 'system' wait for the child
process to complete?  If the parent process is an Apache
child, is that in keeping with what you're trying to do?

cmac



Re: How to get a file listing

2010-02-20 Thread ceauke

Hi there

Here is my code. I get the IMG displayed but also the perl error: No such
file or directory.

"
#!E:\ea12\apps\tech_st\10.1.2\perl\5.6.1\bin\MSWin32-x86\perl.exe
print "Content-type: text/html \n\n"; 

print "Test:";
print " /Ski/temp.jpg ";

opendir(DIR, "/Ski") or die print "Error $!";

print "Dir list: ";
while( ($filename = readdir(DIR))){
 print("$filename");
}
closedir DIR;  "

It seems like the webserver (apache) knows what /Ski is but perl doesn't.
It's looking for /ski in cgi-bin. my /ski folder is out of the root. I have
an alias, directory and location defined in httpd.conf for it. How do I get
perl to see it?
-- 
View this message in context: 
http://old.nabble.com/How-to-get-a-file-listing-tp27644565p27668252.html
Sent from the mod_perl - General mailing list archive at Nabble.com.



Re: How to get a file listing

2010-02-20 Thread Brad Van Sickle

Apache knows the context, PERL does not.

Fully qualify that directory name and it should work.





On 2/20/2010 1:01 PM, ceauke wrote:

Hi there

Here is my code. I get the IMG displayed but also the perl error: No such
file or directory.

"
#!E:\ea12\apps\tech_st\10.1.2\perl\5.6.1\bin\MSWin32-x86\perl.exe
print "Content-type: text/html \n\n";

print "Test:";
print " /Ski/temp.jpg ";

opendir(DIR, "/Ski") or die print "Error $!";

print "Dir list: ";
while( ($filename = readdir(DIR))){
  print("$filename");
}
closedir DIR;  "

It seems like the webserver (apache) knows what /Ski is but perl doesn't.
It's looking for /ski in cgi-bin. my /ski folder is out of the root. I have
an alias, directory and location defined in httpd.conf for it. How do I get
perl to see it?
   


Re: How to get a file listing

2010-02-20 Thread ceauke

No, 
that doesn't work either. I used opendir (DIR, "G:\FTP\Ski") ...
I've tried the slashes in all directions, and with and without preceding and
slashes in the end.
e.g. \Ski,  \Ski\, /ski, /ski/

How do I get perl to understand the context? is there some function that
points to the root? (even that will be pointless as I'm on WINXP where I
have multiple drives.



Apache knows the context, PERL does not.

Fully qualify that directory name and it should work.

-- 
View this message in context: 
http://old.nabble.com/How-to-get-a-file-listing-tp27644565p27668907.html
Sent from the mod_perl - General mailing list archive at Nabble.com.



Re: How to get a file listing

2010-02-20 Thread ceauke

Sorry, 

got it working with your advice:
opendir(DIR, "G:/FTP/Ski") or die print "Error $!"; worked in the end...
Damn these slashes :-D

Thanks for the help
-- 
View this message in context: 
http://old.nabble.com/How-to-get-a-file-listing-tp27644565p27668922.html
Sent from the mod_perl - General mailing list archive at Nabble.com.



Re: Apache2::SubProcess sucks

2010-02-20 Thread Tosh Cooey
It does, but Proc::Daemon closes a billion file handles and sets new 
process IDs and forks and forks and maybe forks a couple more times for 
good measure... Fingers crossed!


I do enjoy the fact that nobody really seems to have a simple definitive 
vanilla fork/spawn process down pat, it seems everyone does what I do, 
trying this and that stumbling about until they come up with some 
monstrosity like Torsen has that works under the sheer weight of tricks.


Tosh


macke...@animalhead.com wrote:

On Feb 20, 2010, at 7:01 AM, Tosh Cooey wrote:

Anyway, the solution, at least so far until I run into other problems, 
seems to be to just make a system() call and the called program uses 
Proc::Daemon and things *seem* to work fine in testing, we'll see when 
it hits production...


Tosh


Doesn't a process that calls 'system' wait for the child
process to complete?  If the parent process is an Apache
child, is that in keeping with what you're trying to do?

cmac




--
McIntosh Cooey - Twelve Hundred Group LLC - http://www.1200group.com/


Re: Apache2::SubProcess sucks

2010-02-20 Thread Torsten Förtsch
On Saturday 20 February 2010 19:25:39 Tosh Cooey wrote:
> I do enjoy the fact that nobody really seems to have a simple definitive 
> vanilla fork/spawn process down pat, it seems everyone does what I do, 
> trying this and that stumbling about until they come up with some 
> monstrosity like Torsen has that works under the sheer weight of tricks.
> 
Well, if I'd said: "Tosh take ModPerl::Something from CPAN and call 
ModPerl::Something::spawn" you'd liked it (no matter what it does internally), 
right?

That sheer weight of tricks comes down to 3 points:

- you have to close the client socket in the child process or the browser will 
wait for more data

- if your process should survive an apache restart it must create its own 
process group, hence the setsid().

- accidental leaking file descriptors to child processes is generally 
considered a security hole

This is what my function does, it closes all file descriptors except for 
STDERR and calls setsid, nothing special. Perhaps it would be good to reopen 
STDIN and STDOUT as /dev/null because many programs don't like closed 
STDIN/STDOUT but again, no tricks.

A tricky part would be to really restore the normal Perl environment if you 
don't want to exec() another program but simply to call a Perl function. 
Reverting the effect of *CORE::GLOBAL::exit=\&ModPerl::Util::exit in an 
already compiled function, that is tricky. Or reestablish the connection 
between %ENV and C-level char *environ[].

Torsten


Re: Apache2::SubProcess sucks

2010-02-20 Thread Cosimo Streppone
In data 20 febbraio 2010 alle ore 21:16:22, Torsten Förtsch  
 ha scritto:



On Saturday 20 February 2010 19:25:39 Tosh Cooey wrote:

I do enjoy the fact that nobody really seems to have a simple definitive
vanilla fork/spawn process down pat, it seems everyone does what I do,
trying this and that stumbling about until they come up with some
monstrosity like Torsen has that works under the sheer weight of tricks.


Well, if I'd said: "Tosh take ModPerl::Something from CPAN and call
ModPerl::Something::spawn" you'd liked it (no matter what it does  
internally), right?


That sheer weight of tricks comes down to 3 points:
[...]


That's really valuable, thanks for sharing.
However, a question:

is this something that should be included in Apache2::SubProcess
to make it better? Or is this something that could be published
another, separate, CPAN distribution?
Or maybe it's already out there?

--
Cosimo


Re: Apache2::SubProcess sucks

2010-02-20 Thread Torsten Förtsch
On Saturday 20 February 2010 21:24:31 Cosimo Streppone wrote:
> That's really valuable, thanks for sharing.
> However, a question:
> 
> is this something that should be included in Apache2::SubProcess
> to make it better? Or is this something that could be published
> another, separate, CPAN distribution?
> Or maybe it's already out there?
> 
Apache2::SubProcess' purpose is more for creating processes similar to CGI-
scripts. A CGI-script is killed by apache if it does not produce output for a 
certain period of time. Also, the process gets killed I think at the end of 
the request.

I think it could be an Apache2::SubProcess extension. That would mean adding 
the stuff to xs/Apache2/SubProcess/SubProcess_pm in the source tree. But there 
are a few things that are unsolved:

- is there a portable way to get all open file descriptors of the current 
process? Under Linux one can readdir(/proc/self/fd). On Darwin I once simply 
closed all fds from 0 to 1000. Some systems have getdtablesize(2), sometimes 
it is getrlimit. Sometimes you can open /dev/something or /proc/self/something 
and read the descriptor table at a certain offset. What the module should do 
on Windows I simply don't know.

If you can solve this problem with apr-functions I think the it can really be 
in Apache2::SubProcess.

- a way of really restoring the perl environment would be good, so that you 
really can fork off subroutines.

But the real reason why it is not shaped out as a separate module yet is that 
the code is really old and quite seldom needed. The main part was written 
around year 2000 for mp1. At that time I didn't know about POSIX::close and 
thus invented my own version like:

  sub SYS_close {6;}# works on Linux and Darwin
  sub sysclose {
syscall &SYS_close, shift()+0;
  }

In short, the code was ugly.

And because my solution is Linux-only.

Torsten


Re: Apache2::SubProcess sucks

2010-02-20 Thread Jeff McCarrell
re: close all open file descriptors portably

well, if one is on a POSIX system, _SC_OPEN_MAX gives the max integer.
Then just close them all.
Here's my usual recipe for this:

# close all open file descriptors
my $max_fd = POSIX::sysconf(&POSIX::_SC_OPEN_MAX);
$max_fd = ((! defined $max_fd) || $max_fd < 0) ? 64 : $max_fd;
while (--$max_fd >= 0) {
next if ($max_fd == fileno($pid_fh));
POSIX::close($max_fd);
}

# now reopen std{in,out,err} on /dev/null
open(STDIN,  "+>/dev/null");
open(STDOUT, "+>&STDIN");
open(STDERR, "+>&STDIN");

Proc::Daemon does the same thing...

HTH,
-- jeff


On 2/20/10 1:10 PM, "Torsten Förtsch"  wrote:

> - is there a portable way to get all open file descriptors of the current
> process? Under Linux one can readdir(/proc/self/fd). On Darwin I once simply 



Re: Apache2::SubProcess sucks

2010-02-20 Thread Scott Gifford
2010/2/20 Torsten Förtsch 
[ ... ]

> - is there a portable way to get all open file descriptors of the current
> process? Under Linux one can readdir(/proc/self/fd). On Darwin I once
> simply
> closed all fds from 0 to 1000. Some systems have getdtablesize(2),
> sometimes
> it is getrlimit. Sometimes you can open /dev/something or
> /proc/self/something
> and read the descriptor table at a certain offset. What the module should
> do
> on Windows I simply don't know.
>

I think just closing stdin and stdout is likely to be enough, or maybe all
file descriptors from 0 to $^F .  The OS will close any others that have the
close-on-exec bit set, and the close-on-exec bit is set by default by Perl's
open function.  Anybody setting this to something different probably
understands the consequences.

Scott.