HTTPd start-up phase:

HTTPd restart:

1st and next post_config hook calls

A common hack to execute the post_config hook body only once is to set a flag on 1st execution and exit. On 2nd execution, the flag is retrieved and module initialization is performed. This hack uses the apr_pool_userdata_set and apr_pool_userdata_get functions to saves the flag in memory managed by the process pool.

static int shm_counter_post_config(apr_pool_t *pconf, apr_pool_t *plog,
                                   apr_pool_t *ptemp, server_rec *s)
{
    apr_status_t rv;
    shm_counter_scfg_t *scfg;
    void *data = NULL;
    const char *userdata_key = "shm_counter_post_config";

    /* Apache loads DSO modules twice. We want to wait until the second
     * load before setting up our global mutex and shared memory segment.
     * To avoid the first call to the post_config hook, we set some
     * dummy userdata in a pool that lives longer than the first DSO
     * load, and only run if that data is set on subsequent calls to
     * this hook. */
    apr_pool_userdata_get(&data, userdata_key, s->process->pool);
    if (data == NULL) {
        /* WARNING: This must *not* be apr_pool_userdata_setn(). The
         * reason for this is because the static symbol section of the
         * DSO may not be at the same address offset when it is reloaded.
         * Since setn() does not make a copy and only compares addresses,
         * the get() will be unable to find the original userdata. */
        apr_pool_userdata_set((const void *)1, userdata_key,
                              apr_pool_cleanup_null, s->process->pool);
        return OK; /* This would be the first time through */
    }

    /* If we made it this far, we can safely initialize the module */

A problem with this hack exists when a module is installed while the server is running, and the server is just restarted to load the module. In this case, the post_config hook is executed once after restart and will only set the flag. Module initialization will not be performed, and when child_init and other hooks are called, bad things may happen.

post_config hook call by children processes

On WinNT MPM, the post_config hook is also called by the children processes.

To know if we are in a child, we can check the AP_PARENT_PID environment variable: it is only set in children on the WinNT MPM.

Note: Some module take for granted that the post_config hook is only called in the parent process. That's wrong (on Win32). But calling apr_global_mutex_create() in the parent and in the child with the same filename does not hurt, the mutex is shared.

    /* If we made it this far, we can safely initialize the module */
    scfg = ap_get_module_config(s->module_config, &shm_counter_module);

    ap_add_version_component(pconf, "mod_shm_counter/$Revision $");

    /* Since we are still in the parent before any children have been
     * created, it is safe to create the shared lock and shared segment.
     * If we waited until a child had been created, we run in to a race
     * condition.
     */

    rv = apr_global_mutex_create(&scfg->mutex, scfg->shmcounterlockfile,
                                 APR_LOCK_DEFAULT, pconf);

Race conditions during graceful restart

During a graceful restart, old children are still serving old requests while new children are serving new requests. If the same lock must be used by old and new children, then the lock name must be the same and cannot be generated with tmpnam() or similar functions in the post_config hook.

Preventing module unloading

To prevent module unloading, there is a sick and twisted hack (wrowe dixit): "the evil method is to use apr_dso_load() against the process pool to load it 'permanently'".

ModuleLife (last edited 2009-09-20 22:13:20 by localhost)