Return-Path: Delivered-To: apmail-perl-modperl-archive@www.apache.org Received: (qmail 83296 invoked from network); 13 Dec 2006 10:46:04 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.2) by minotaur.apache.org with SMTP; 13 Dec 2006 10:46:04 -0000 Received: (qmail 12975 invoked by uid 500); 13 Dec 2006 10:46:04 -0000 Delivered-To: apmail-perl-modperl-archive@perl.apache.org Received: (qmail 12957 invoked by uid 500); 13 Dec 2006 10:46:04 -0000 Mailing-List: contact modperl-help@perl.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: List-Id: Delivered-To: mailing list modperl@perl.apache.org Received: (qmail 12945 invoked by uid 99); 13 Dec 2006 10:46:04 -0000 Received: from herse.apache.org (HELO herse.apache.org) (140.211.11.133) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 13 Dec 2006 02:46:04 -0800 X-ASF-Spam-Status: No, hits=-0.0 required=10.0 tests=SPF_PASS X-Spam-Check-By: apache.org Received-SPF: pass (herse.apache.org: domain of torsten.foertsch@gmx.net designates 213.165.64.20 as permitted sender) Received: from [213.165.64.20] (HELO mail.gmx.net) (213.165.64.20) by apache.org (qpsmtpd/0.29) with SMTP; Wed, 13 Dec 2006 02:45:52 -0800 Received: (qmail invoked by alias); 13 Dec 2006 10:45:30 -0000 Received: from dialin096079.justdsl.de (EHLO opi.home) [85.25.96.79] by mail.gmx.net (mp018) with SMTP; 13 Dec 2006 11:45:30 +0100 X-Authenticated: #1700068 Received: by opi.home (Postfix, from userid 1000) id 9014539D17; Wed, 13 Dec 2006 11:44:13 +0100 (CET) From: Torsten Foertsch To: "Alex Beamish" Subject: Re: Forking to an interactive program under mod_perl Date: Wed, 13 Dec 2006 11:44:08 +0100 User-Agent: KMail/1.9.1 Cc: "mod_perl list" References: <57FDC457-C935-4C73-A1A8-6C9695672515@2xlp.com> In-Reply-To: MIME-Version: 1.0 Content-Type: multipart/signed; boundary="nextPart2672925.27GFXTykR6"; protocol="application/pgp-signature"; micalg=pgp-sha1 Content-Transfer-Encoding: 7bit Message-Id: <200612131144.13082.torsten.foertsch@gmx.net> X-Y-GMX-Trusted: 0 X-Virus-Checked: Checked by ClamAV on apache.org --nextPart2672925.27GFXTykR6 Content-Type: text/plain; charset="iso-8859-15" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline On Wednesday 13 December 2006 02:03, Alex Beamish wrote: > Interesting suggestions, thank you, and I'm coming around to the idea that > a daemon will need to be used for the heavy lifting .. and then perhaps > mod_perl can communicate with the daemon using named pipes .. > > The whole point of this exercise is to keep all of the page information in > memory so that when Ghostscript gets another page request it can service = it > right away, rather having to reload everything all over again. Lower > latency, at the cost of higher memory requirements. So that tells me I > don't want to load Ghostscript each time a new request comes in. > > I'll deal with multiple documents with some combination of stale timers a= nd > LRU slots, but that's not really what I see as the most complicated or > difficult part of this problem. For this particular application, my > inactivity timer will probably by 10-15 minutes, and I'll expect to have > 6-8 documents open at any given time, so it shouldn't be a big drain on > memory. And I will probably be able to set something up that signals that= a > document has been expired as well .. (this is just me thinking out loud) = =2E. > > Thanks for your feedback .. I think named pipes is my next focus. Alex, one thing you might run into while trying to control gs is buffering. Most= =20 programs buffer their output if STDOUT is not bound to a terminal. That mea= ns=20 even if you have switched off output buffering in Perl ($|=3D1) you write a= =20 command to the external program but won't get an answer until enough output= =20 is generated to fill up a buffer. This problem can be solved using pseudo terminals. IO::Pty is handy at this. =46urther, I'd use a unix domain socket to talk to your gs-controller-daemo= n.=20 apache + mod_perl ^ | | IO::Socket::UNIX | v gs-controller ^ | | IO::Pty | v gs Let gs-controller listen on a socket. Each actual connection to a gs is=20 assigned a unique ID by the gs-controller. This ID you can put into your pa= ge=20 as a session handle. So a subsequent request for the same gs-connection rea= ds=20 this ID and transfers it to the gs-controller together with the gs-commands. gs-controller then finds the actual PTY and submits the commands. Of course= ,=20 your gs-controller has to handle timeouts and errors. If you need to spawn off the gs-controller daemon on demand from mod_perl=20 remember that 1) Apache opens a lot more file descriptors than STDIN, STDOUT and STDERR 2) use CORE::exit if you really want your program to exit (after a fork may= be) 3) Apache signals it's process group if it wants to shut down or restart Maybe some of the problems can be avoided using Apache2::SubProcess. I have= =20 never used it. For me the following code does the job: sub sysclose { require 'syscall.ph'; syscall &SYS_close, shift()+0; } sub RLIMIT_NOFILE {7;} # linux specific sub getrlimit { require 'syscall.ph'; my $x=3D"x"x8; # result syscall &SYS_getrlimit, shift()+0, $x; unpack "ii", $x; } sub close_fd { my @l=3Dgetrlimit( RLIMIT_NOFILE ); my $l; # close all files save STDIN, STDOUT and STDERR for( $l=3D3; $l<$l[0]; $l++ ) { sysclose $l; } sysclose 0; open STDIN, '/dev/null'; sysclose 1; open STDOUT, '>/dev/null'; } sub spawn { my ($daemon_should_survive_apache_restart, @args)=3D@_; local $SIG{CHLD}=3D'IGNORE'; my $pid; # yes, even fork can fail select undef, undef, undef, .1 while( !defined($pid=3Dfork) ); unless( $pid ) { # child # 2nd fork to cut parent relationship with a mod_perl apache select undef, undef, undef, .1 while( !defined($pid=3Dfork) ); if( $pid ) { CORE::exit 0; } else { close_fd; POSIX::setsid if( $daemon_should_survive_apache_restart ); exec @args; CORE::exit 0; } } waitpid $pid, 0; # avoid a zombie } The spawned process has only 1 open file, STDERR. For mod_perl processes it= =20 points to the ErrorLog. For processes spawned by CGI scripts (Apache 2.x) it is a pipe to the Apache child. In this latter case you must open your own=20 STDERR. Torsten --nextPart2672925.27GFXTykR6 Content-Type: application/pgp-signature -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.2 (GNU/Linux) iD8DBQBFf9l9wicyCTir8T4RAjkxAKDIMDTQUPhh25guSC5eMvjvMC6d1wCfdLL2 NcaGMZXkOFFl3r5xBLSS2jY= =NFde -----END PGP SIGNATURE----- --nextPart2672925.27GFXTykR6--