On Sunday, 16 October 2011 02:26:53 Ævar Arnfjörð Bjarmason wrote:
> > $ cat xx
> > <Perl>
> > use POSIX();
> > POSIX::exit(15);
> > </Perl>
> > $ httpd -c 'Include "'$PWD/xx'"'; echo $?
> > 15
> > $ cat xx
> > <Perl>
> > die
> > </Perl>
> > $ httpd -c 'Include "'$PWD/xx'"'; echo $?
> > Syntax error on line 2 of /.../xx:
> > \t(in cleanup) Died at /.../xx line 2.\n
> > 1
> > $
> 
> I can load code earlier, but unless I'm misunderstanding something the
> PerlInterpreter running that code won't be the one that'll be forked
> and serving requests.

If you are running prefork with a non-threaded perl (-Uuseithreads and
-Uusemultiplicity) it's always the same interpreter.

The only thing is the code in a <Perl> block is interpreted twice at
startup.

Between the both runs the interpreter shuts down. If modperl is compiled
as shared library it is even unloaded from memory. The same happens by
the way when Apache receives a SIGHUP (restart) or SIGUSR1 (graceful
restart).

Now let's see what happens with a threaded perl and worker MPM.

Here is again my xx file that is included after the main httpd.conf has
been read.

0 r2@opi ~/Download$ cat xx
<Perl>
  package XX;
  use ModPerl::Util ();
  use Apache2::RequestRec ();
  use Apache2::RequestIO ();
  use Apache2::ServerUtil ();

  sub stderr {readlink "/proc/$$/fd/2"}
  sub l {
    open my $f, '>>', '/tmp/xx';
    print $f "$$: ".ModPerl::Util::current_callback.
             ": perl=".ModPerl::Util::current_perl_id.
             " restart_count=".Apache2::ServerUtil::restart_count.
             " stderr=".stderr."\n";
    0;
  }

  l;

  sub handler {
    my ($r)=@_;
    $r->content_type("text/plain");
    $r->print("$$: perl=".ModPerl::Util::current_perl_id.
              " restart_count=".Apache2::ServerUtil::restart_count."\n");
    0;
  }
</Perl>
<Location /xx>
SetHandler modperl
PerlResponseHandler XX
</Location>
PerlChildInitHandler XX::l
PerlPostConfigHandler XX::l
PerlFixupHandler XX::l

0 r2@opi ~/Download$ :>/tmp/xx &&
> chmod 666 /tmp/xx &&
> sudo /opt/apache-worker/sbin/httpd -f 
> /etc/opt/apache-worker/original/httpd-modperl.conf -c 'Include "'$PWD/xx\"

0 r2@opi ~/Download$ cat /tmp/xx
19751: ��z: perl=0x79f3f0 restart_count=1 stderr=/dev/pts/4
19751: PerlPostConfigHandler: perl=0x79f3f0 restart_count=1 
stderr=/var/opt/apache-worker/logs/error_log

PID 19751 is the parent of the process that is normally referred to as the
parent apache. This process is still a child of the shell and hence can
report a return code. In the first line STDERR is still connected to the
terminal. PostConfig runs after OpenLogs. So, here error_log is active and
STDERR goes there.

Now apache throws away all done so far and even unloads modperl from
memory. Also STDERR is closed and the httpd disconnects from the calling
shell.

19752: �>l: perl=0x9932b0 restart_count=2 stderr=/dev/null
19752: PerlPostConfigHandler: perl=0x9932b0 restart_count=2 
stderr=/var/opt/apache-worker/logs/error_log

PPID of process 19752 is 1. Now httpd cannot report to the shell. The perl
interpreter 0x9932b0 is called the interpreter pool parent. Later on when
requests are served this interpreter is cloned. So, the clones inherit all
the code that is compiled in this interpreter. An exception to this rule
is the PerlOption +Parent. If a VHost is configured with this option it
gets a brand new interpreter pool parent.

19754: PerlChildInitHandler: perl=0x9932b0 restart_count=2 
stderr=/var/opt/apache-worker/logs/error_log
19755: PerlChildInitHandler: perl=0x9932b0 restart_count=2 
stderr=/var/opt/apache-worker/logs/error_log
19756: PerlChildInitHandler: perl=0x9932b0 restart_count=2 
stderr=/var/opt/apache-worker/logs/error_log

The same interpreter runs the ChildInit phase for each child process.

Now let's see what happens at runtime:

0 r2@opi ~/Download$ curl http://localhost/xx
19754: perl=0xb7a2d0 restart_count=2

Perl interpreter 0xb7a2d0 is a clone of 0x9932b0. It is created on demand.
But the fact that is can execute the code from the <Perl> section shows
that it inherits such things.

0 r2@opi ~/Download$ tail -2 /tmp/xx
19756: PerlChildInitHandler: perl=0x9932b0 restart_count=2 
stderr=/var/opt/apache-worker/logs/error_log
19754: PerlFixupHandler: perl=0xb7a2d0 restart_count=2 stderr=

The Fixup handler is run by the same interpreter. This can be controlled
by the PerlInterpScope directive which is "request" by default. Were it
"handler" we couldn't say for sure that the Response phase is run by the
same interpreter as Fixup is. But both interpreters would be clones of the
interpreter pool parent.

Conclusion:

1) As can be seen by the example above httpd can report a return code to
the calling shell only while restart_count==1. Otherwise it has already
disconnected and is a child of the init process.

2) Application code can be compiled in <Perl> sections, by PerlLoadModule
or PerlConfigRequire. It is inherited by the interpreter cloning process.

The important point for you is 1). httpd will report the status code to
the calling shell also if the interpreter is started by a PerlRequire or
PerlPostConfigRequire but only if restart_count is still 1.

Torsten Förtsch

-- 
Need professional modperl support? Hire me! (http://foertsch.name)

Like fantasy? http://kabatinte.net

Reply via email to