On Monday 18 April 2011, Stefan Fritsch wrote:
> I don't really like that. The admin should not have to count the
> LoadModule directives in order to tune DynamicModulesMax for
> minimum memory usage. Httpd should do the counting.
> - a module that wants to add modules later (like mod_perl) could
> call some function in its insert_hooks function, which would cause
> the adjustment of conf_vector_length to happen in post_config
> instead
The attached patch adds two functions, ap_reserve_module_slots() and
ap_reserve_module_slots_directive(), which can be called by relevant
modules in the pre config stage.
Can you please test this patch and call
ap_reserve_module_slots_directive("PerlLoadModule") in mod_perl's
pre_config hook?
diff --git a/include/http_config.h b/include/http_config.h
index 6d8e185..80956c0 100644
--- a/include/http_config.h
+++ b/include/http_config.h
@@ -988,6 +988,23 @@ AP_DECLARE(void) ap_register_hooks(module *m, apr_pool_t *p);
AP_DECLARE(void) ap_fixup_virtual_hosts(apr_pool_t *p,
server_rec *main_server);
+/**
+ * Reserve some modules slots for modules loaded by other means than
+ * EXEC_ON_READ directives.
+ * Relevant modules should call this in the pre_config stage.
+ * @param count The number of slots to reserve.
+ */
+AP_DECLARE(void) ap_reserve_module_slots(int count);
+
+/**
+ * Reserve some modules slots for modules loaded by a specific
+ * non-EXEC_ON_READ config directive.
+ * This counts how often the given directive is used in the config and calls
+ * ap_reserve_module_slots() accordingly.
+ * @param directive The name of the directive
+ */
+AP_DECLARE(void) ap_reserve_module_slots_directive(const char *directive);
+
/* For http_request.c... */
/**
@@ -995,7 +1012,7 @@ AP_DECLARE(void) ap_fixup_virtual_hosts(apr_pool_t *p,
* @param p The pool to allocate the config vector from
* @return The config vector
*/
-AP_CORE_DECLARE(ap_conf_vector_t*) ap_create_request_config(apr_pool_t *p);
+AP_DECLARE(ap_conf_vector_t*) ap_create_request_config(apr_pool_t *p);
/**
* Setup the config vector for per dir module configs
diff --git a/include/http_core.h b/include/http_core.h
index ba66de8..7b822a5 100644
--- a/include/http_core.h
+++ b/include/http_core.h
@@ -766,7 +766,8 @@ typedef struct {
unsigned int min_loglevel;
} ap_errorlog_format_item;
-AP_DECLARE(void) ap_register_log_hooks(apr_pool_t *p);
+AP_CORE_DECLARE(void) ap_register_log_hooks(apr_pool_t *p);
+AP_CORE_DECLARE(void) ap_register_config_hooks(apr_pool_t *p);
/* ----------------------------------------------------------------------
*
diff --git a/modules/generators/mod_cgid.c b/modules/generators/mod_cgid.c
index 651c6a0..91d290e 100644
--- a/modules/generators/mod_cgid.c
+++ b/modules/generators/mod_cgid.c
@@ -421,7 +421,7 @@ static apr_status_t get_req(int fd, request_rec *r, char **argv0, char ***env,
}
/* handle module indexes and such */
- rconf = (void **) apr_pcalloc(r->pool, sizeof(void *) * (total_modules + DYNAMIC_MODULE_LIMIT));
+ rconf = (void **)ap_create_request_config(r->pool);
temp_core = (core_request_config *)apr_palloc(r->pool, sizeof(core_module));
rconf[req->core_module_index] = (void *)temp_core;
diff --git a/server/config.c b/server/config.c
index 85dd709..3d30b5b 100644
--- a/server/config.c
+++ b/server/config.c
@@ -198,6 +198,8 @@ static int max_modules = 0;
*/
static int conf_vector_length = 0;
+static int reserved_module_slots = 0;
+
AP_DECLARE_DATA module *ap_top_module = NULL;
AP_DECLARE_DATA module **ap_loaded_modules=NULL;
@@ -548,6 +550,10 @@ AP_DECLARE(const char *) ap_add_module(module *m, apr_pool_t *p,
"reached. Please increase "
"DYNAMIC_MODULE_LIMIT and recompile.", m->name);
}
+ /*
+ * If this fails some module forgot to call ap_reserve_module_slots*.
+ */
+ ap_assert(total_modules < conf_vector_length);
m->module_index = total_modules++;
dynamic_modules++;
@@ -2257,10 +2263,36 @@ static server_rec *init_server_config(process_rec *process, apr_pool_t *p)
static apr_status_t reset_conf_vector_length(void *dummy)
{
+ reserved_module_slots = 0;
conf_vector_length = max_modules;
return APR_SUCCESS;
}
+static int conf_vector_length_pre_config(apr_pool_t *pconf, apr_pool_t *plog,
+ apr_pool_t *ptemp)
+{
+ /*
+ * We have loaded all modules that are loaded by EXEC_ON_READ directives.
+ * From now on we reduce the size of the config vectors to what we need,
+ * plus what has been reserved (e.g. by mod_perl) for additional modules
+ * loaded later on.
+ * If max_modules is too small, ap_add_module() will abort.
+ */
+ if (total_modules + reserved_module_slots < max_modules) {
+ conf_vector_length = total_modules + reserved_module_slots;
+ }
+ apr_pool_cleanup_register(pconf, NULL, reset_conf_vector_length,
+ apr_pool_cleanup_null);
+ return OK;
+}
+
+
+AP_CORE_DECLARE(void) ap_register_config_hooks(apr_pool_t *p)
+{
+ ap_hook_pre_config(conf_vector_length_pre_config, NULL, NULL,
+ APR_HOOK_REALLY_LAST);
+}
+
AP_DECLARE(server_rec*) ap_read_config(process_rec *process, apr_pool_t *ptemp,
const char *filename,
ap_directive_t **conftree)
@@ -2309,14 +2341,6 @@ AP_DECLARE(server_rec*) ap_read_config(process_rec *process, apr_pool_t *ptemp,
return NULL;
}
- /*
- * We have loaded the dynamic modules. From now on we know exactly how
- * long the config vectors need to be.
- */
- conf_vector_length = total_modules;
- apr_pool_cleanup_register(p, NULL, reset_conf_vector_length,
- apr_pool_cleanup_null);
-
error = process_command_config(s, ap_server_post_read_config, conftree,
p, ptemp);
@@ -2487,3 +2511,26 @@ AP_DECLARE(void *) ap_retained_data_create(const char *key, apr_size_t size)
apr_pool_userdata_set((const void *)retained, key, apr_pool_cleanup_null, ap_pglobal);
return retained;
}
+
+static int count_directives_sub(const char *directive, ap_directive_t *current)
+{
+ int count = 0;
+ while (current != NULL) {
+ if (current->first_child != NULL)
+ count += count_directives_sub(directive, current->first_child);
+ if (strcasecmp(current->directive, directive) == 0)
+ count++;
+ current = current->next;
+ }
+ return count;
+}
+
+AP_DECLARE(void) ap_reserve_module_slots(int count)
+{
+ reserved_module_slots += count;
+}
+
+AP_DECLARE(void) ap_reserve_module_slots_directive(const char *directive)
+{
+ ap_reserve_module_slots(count_directives_sub(directive, ap_conftree));
+}
diff --git a/server/core.c b/server/core.c
index b2cdfe0..0f3186a 100644
--- a/server/core.c
+++ b/server/core.c
@@ -4380,6 +4380,7 @@ static void register_hooks(apr_pool_t *p)
{
errorlog_hash = apr_hash_make(p);
ap_register_log_hooks(p);
+ ap_register_config_hooks(p);
ap_expr_init(p);
/* create_connection and pre_connection should always be hooked