httpd-modules-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Sorin Manolache <sor...@gmail.com>
Subject Re: Apache: Create server config only once
Date Sat, 25 May 2013 19:29:51 GMT
On 2013-05-25 15:22, Sindhi Sindhi wrote:
> Hi,
>
> I see that the create_server_config callback is called twice for every
> Apache server startup. I want to do a lot of initialization in this
> callback and allocations in this function are meant to be long lived. And
> these buffers are very huge, so I want to ensure these initializations are
> done only once per server start. As of now I'm trying to do the following -

There's not much you can do against the double-call of create_*_config.

Here's a rough sketch of how apache works:

create conf pool
create config objects for all modules and virtual hosts
read config
call pre_config callbacks
parse config
call post_config callbacks

loop:
    _clear the conf pool_
    create config objects for all modules and virtual hosts
    read config
    call pre_config callbacks
    parse config
    call post_config callbacks
    create generation of children to handle the requests
    wait on the generation to die
    if the signal was to stop => exit the loop
    else (i.e. reload conf) iterate

So apache invokes create_*_config twice before starting to handle the 
requests. But please note the following points:

1. The conf pool is cleared between the first and second call to 
create_*_config. So if you allocated something in create_*_config when 
it was called the first time you won't find it again when called the 
second time.

2. A new server_rec is constructed each time apache calls "create config 
objects for all modules and virtual hosts". This is why you don't find 
your conf object with ap_get_module_config.

3. The create_*_config callbacks are called not only at the beginning, 
but each time a new generation of children is spawned. An old generation 
is sent the message to shut down when apache is sent a signal, either to 
stop or to restart or to gracefully restart. Typically you want to 
reload the conf because you changed it, so it's normal that apache 
reparses the conf.

What you could do is to create the conf in the first call. You also 
store it somewhere, let's say in a global variable. Then, in the second 
call, you do not try to get it from the server_rec (as anyway the 
server_rec is brand new and you would not find it there), but you get it 
from where you stored it in the first call.

So something like that:

static MyConf *my_global_conf;

void *
create_server_config() {
    if (my_global_conf != NULL)
        return my_global_conf;
    my_global_conf = new MyConf;
    return my_global_conf;
}

Note that if you adopt this approach you should not allocate anything in 
the pool that is passed to create_server_config because the pool is 
cleared between invocations.

Also there are two problems with this approach:

1. You'll have one single object for all virtual hosts.
2. You cannot distinguish between the second call and subsequent calls. 
So you cannot do a conf reload (a graceful restart) anymore because all 
invocations of create_server_config except the first one will return the 
old my_global_conf and will not react to changes in the configuration. 
So you will be forced to do server restarts (as opposed to graceful 
restarts) in order to load a new configuration.

My advice is to live with the double invocation because you gain more 
than you lose. It solves you the two problems mentioned above. You pay 
only by waiting a little longer at startup. Even if apache did not call 
the create_*_config functions twice before serving requests you would 
have to live with several invocations of the create_*_config callbacks 
if you want to support conf reloads. And conf reloads are very useful, 
you can reload the conf without losing requests.

In order not to leak, place a cleanup function in the list of cleanup 
callbacks of the conf pool. For example:

void *
create_server_config(apr_pool_t *pconf, ...) {
    MyConf *cnf = new MyConf;
    apr_pool_cleanup_register(pconf, cnf, &my_cleanup, 
&apr_pool_cleanup_null);
    return cnf;
}

apr_status_t
my_cleanup(void *data) {
    MyConf *cnf = reinterpret_cast<MyConf *>(data);
    delete cnf;
    return APR_SUCCESS;
}

my_cleanup will be called when the conf pool is cleared, i.e. before 
each new reparsing of the conf and creation of each new generation of 
children.

Sorin

>
> typedef struct
> {
> int bEnabled; // Enable or disable the module.
> MyFilterInit* myFilterInitObj; // A class that has methods to do all huge
> initializations
> bool serverConfigured;
> } MyFilterConfig;
>
> static int serverConfigHit = 0;
>
> static void* CreateServerConfig(apr_pool_t* pool, server_rec* virtServer) {
>      MyFilterConfig *pExistingConfig = (MyFilterConfig *)
> ap_get_module_config (virtServer,  &tag_filter_module);
>
> if (serverConfigHit == 0) {
> MyFilterConfig *pConfig = (MyFilterConfig *) apr_pcalloc (pool, sizeof
> *pConfig);
> pConfig->myFilterInitObj = new MyFilterInit(); // This does all the huge
> initializations
> serverConfigHit = serverConfigHit +1;
> return pConfig;
> }
> return pExistingConfig;
> }
>
> But I see an issue here. The second time when CreateServerConfig is called,
> 1. pExistingConfig is not having the address which was set during the first
> call to CreateServerConfig
> 2. serverConfigHit is zero.
>
> Which means when CreateServerConfig was called first time, all the
> initializations I made is not recorded by the server. Which means all the
> allocations I made in the first call using malloc/new will result in a
> memory leak.
>
> Kindly advice how do I ensure that my initializations are performed only
> once.
>
> Thanks
>


Mime
View raw message