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


Reply via email to