perl-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Torsten Foertsch <torsten.foert...@gmx.net>
Subject [PATCH] please review: interpreter allocation
Date Tue, 25 Sep 2007 13:52:01 GMT
Hi Gozer,

this patch is a complete rework of the interpreter allocation. I have tested 
it with apache 2.2.6 with prefork and worker MPM but only with a perl 5.8.8 
that has defined USE_ITHREADS. The rest of this text concerns only the worker 
MPM.

The main idea behind the patch is to eliminate hash lookups as much as 
possible while selecting an interpreter.

In previous versions of mod_perl the interpreter currently in use was saved as 
userdata in a request or connection pool according to PerlInterpScope or in 
the rcfg structure if scope==handler. This means each phase does a hash 
lookup in the pool's userdata to get the interpreter.

This is now eliminated. The current interpreter is saved in the ccfg 
structure. modperl_interp_select has only to there once to discover whether a 
new interpreter needs to be allocated or there is one that can be used.

However, there is one case where I could not eliminate the hash lookup. 
modperl_module_cmd_take123 and modperl_module_config_merge don't work on a 
request_rec or conn_rec but only on a pool. While at startup time this pool 
is pconf at request time it is allways the request pool. So in 
modperl_hook_create_request I put a pointer to the request_rec as userdata in 
the request pool just in case a custom configuration directive is used 
somewhere in the request cycle. This is certainly not an ideal solution. So, 
if someone know of a way to convert a request pool into the corresponding 
request_rec please let me know. So modperl_interp_pool_select called at 
request time does a hash lookup to fetch the request_rec pointer and then 
calls modperl_interp_select.

The lifetime of an interpreter is now completely controlled by its refcnt. If 
it is unselected with a refcnt==0 it is put back into the pool. Otherwise the 
refcnt is simply decremented. The selection process is also quite simple. If 
ccfg->interp is not NULL it means there is already an interpreter assigned to 
this connection. If it is NULL a new interpreter is pulled from the pool and 
put in ccfg->interp. At this stage its refcnt is 0. Now PerlInterpScope is 
consulted to decide what to do. For scope==handler nothing is done. For 
scope==request a pool cleanup that calls modperl_interp_unselect is 
registered with the main request pool and the refcnt is incremented. For 
scope==subrequest or scope==connection a the cleanup function is registered 
with the appropriate pool.

This has a few consequences. Mainly, the first time an interpreter is needed 
decides about its scope. If a URI translation handler needs an interpreter 
and the server wide scope is request the interpreter is locked for the whole 
request time even if a subsequent <Location> says otherwise. Further, once an 
interpreter is allocated for a request, subrequest or connection it is used 
in all cases that need one. That means a <Location> that sets scope==handler 
will not acquire a new one but use the one already assigned to the request.

A word about cleanup functions. In previous versions in case of scope==handler 
a PerlCleanupHandler was called every time the interpreter was unselected. 
But it has never really worked and it somehow contradicts with the docs that 
say "It is used to execute some code immediately after the request has been 
served (the client went away) and before the request object is destroyed."
The patched modperl behaves according to the docs in that a PerlCleanupHandler 
is called at the end of a request even with scope==handler. That means also 
that as with each other phase with scope==handler a PerlCleanupHandler is not 
guaranteed to be called with a specific (previously used) interpreter.

However, there are ways to extend the lifetime of an interpreter from perl 
level. A new pool adds a reference to the current interpreter. So even with 
scope==handler one can say:

sub fixup {
  $_[0]->pnotes->{lock_interpreter}=APR::Pool->new;
  $_[0]->push_handlers(PerlCleanupHandler=>sub {
    delete $_[0]->pnotes->{lock_interpreter};
    return Apache2::Const::DECLINED;
  });
  return Apache2::Const::DECLINED;
}

This guarantees the same interpreter from fixup to cleanup. Do not use 
$r->pool->new in this case. It creates a sub-pool of the request pool which 
is destroyed before the PerlCleanupHandler is called.

Also, a pool cleanup function locks the interpreter until the pool is 
destroyed. So avoid $r->pool->cleanup_register if scope==handler is what you 
want.

I think the patch is fairly complete regarding interpreter 
allocation/deallocation. It may have flaws with other resources. For example 
I think pnotes need to be dropped whenever an interpreter is freed. I still 
have to check that.

Also, there are calls to PERL_SET_CONTEXT(aTHX) throughout the code. Since I 
do not really know what they are for I cannot say if there are some missing.

Please review the patch.

Thanks,
Torsten

Mime
View raw message