Index: include/http_config.h
===================================================================
--- include/http_config.h	(revision 1585432)
+++ include/http_config.h	(working copy)
@@ -1169,6 +1169,16 @@ AP_DECLARE(int) ap_process_config_tree(server_rec
 AP_DECLARE(void *) ap_retained_data_create(const char *key, apr_size_t size);
 
 /**
+ * Store data which will be retained across unload/load of modules in a SHM
+ * @param key The unique key associated with this module's retained data
+ * @param size in bytes of the retained data (to be allocated)
+ * @param retained Address of new retained data structure, initially cleared
+ * @return APR_SUCCESS on success, or the SHM creation error.
+ */
+AP_DECLARE(apr_status_t) ap_retained_data_share(const char *key,
+                                                apr_size_t size,
+                                                void **retained);
+/**
  * Retrieve data which was stored by ap_retained_data_create()
  * @param key The unique key associated with this module's retained data
  * @return Address of previously retained data structure, or NULL if not yet saved
Index: server/config.c
===================================================================
--- server/config.c	(revision 1585432)
+++ server/config.c	(working copy)
@@ -34,6 +34,8 @@
 #include "apr_portable.h"
 #include "apr_file_io.h"
 #include "apr_fnmatch.h"
+#include "apr_shm.h"
+#include "apr_md5.h"
 
 #define APR_WANT_STDIO
 #define APR_WANT_STRFUNC
@@ -2605,6 +2607,44 @@ AP_DECLARE(void *) ap_retained_data_create(const c
     return retained;
 }
 
+AP_DECLARE(apr_status_t) ap_retained_data_share(const char *key,
+                                                apr_size_t size,
+                                                void **retained)
+{
+    apr_shm_t *shm;
+    apr_status_t rv;
+
+    rv = apr_shm_create(&shm, size, NULL, ap_pglobal);
+    if (rv == APR_ENOTIMPL) {
+        int n, i;
+        char *shm_path;
+        unsigned char md5[APR_MD5_DIGESTSIZE];
+        const char *hex = "0123456789abcdef";
+
+        apr_md5(md5, key, strlen(key));
+        shm_path = apr_palloc(ap_pglobal, APR_MD5_DIGESTSIZE * 2 + 1);
+        for (n = i = 0; i < APR_MD5_DIGESTSIZE; ++i) {
+            shm_path[n++] = hex[md5[i] >> 4];
+            shm_path[n++] = hex[md5[i] & 15];
+        }
+        shm_path[n] = '\0';
+        shm_path = ap_runtime_dir_relative(ap_pglobal, shm_path);
+
+        apr_shm_remove(shm_path, ap_pglobal);
+        rv = apr_shm_create(&shm, size, shm_path, ap_pglobal);
+    }
+    if (rv == APR_SUCCESS) {
+        *retained = apr_shm_baseaddr_get(shm);
+        memset(*retained , 0, sizeof **retained);
+        apr_pool_userdata_set(*retained, key, apr_pool_cleanup_null,
+                              ap_pglobal);
+    }
+    else {
+        *retained = NULL;
+    }
+    return rv;
+}
+
 static int count_directives_sub(const char *directive, ap_directive_t *current)
 {
     int count = 0;
Index: server/mpm/event/event.c
===================================================================
--- server/mpm/event/event.c	(revision 1585432)
+++ server/mpm/event/event.c	(working copy)
@@ -332,7 +332,7 @@ typedef struct event_retained_data {
     int first_thread_limit;
     int module_loads;
     int sick_child_detected;
-    ap_generation_t my_generation;
+    volatile ap_generation_t my_generation;
     int volatile is_graceful; /* set from signal handler */
     int maxclients_reported;
     /*
@@ -341,7 +341,7 @@ typedef struct event_retained_data {
      * We use this value to optimize routines that have to scan the entire
      * scoreboard.
      */
-    int max_daemons_limit;
+    volatile int max_daemons_limit;
     /*
      * idle_spawn_rate is the number of children that will be spawned on the
      * next maintenance cycle if there aren't enough idle servers.  It is
@@ -3113,7 +3113,16 @@ static int event_pre_config(apr_pool_t * pconf, ap
     /* sigh, want this only the second time around */
     retained = ap_retained_data_get(userdata_key);
     if (!retained) {
-        retained = ap_retained_data_create(userdata_key, sizeof(*retained));
+        void *userdata;
+        rv = ap_retained_data_share(userdata_key,
+                                    sizeof(*retained), &userdata);
+        if (rv != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, APLOGNO()
+                         "Couldn't create shared retained data");
+            userdata = ap_retained_data_create(userdata_key,
+                                               sizeof(*retained));
+        }
+        retained = userdata;
         retained->max_daemons_limit = -1;
         retained->idle_spawn_rate = 1;
     }
Index: server/mpm/eventopt/eventopt.c
===================================================================
--- server/mpm/eventopt/eventopt.c	(revision 1585432)
+++ server/mpm/eventopt/eventopt.c	(working copy)
@@ -322,7 +322,7 @@ typedef struct event_retained_data {
     int first_thread_limit;
     int module_loads;
     int sick_child_detected;
-    ap_generation_t my_generation;
+    volatile ap_generation_t my_generation;
     int volatile is_graceful; /* set from signal handler */
     int maxclients_reported;
     /*
@@ -331,7 +331,7 @@ typedef struct event_retained_data {
      * We use this value to optimize routines that have to scan the entire
      * scoreboard.
      */
-    int max_daemons_limit;
+    volatile int max_daemons_limit;
     /*
      * idle_spawn_rate is the number of children that will be spawned on the
      * next maintenance cycle if there aren't enough idle servers.  It is
@@ -3020,7 +3020,16 @@ static int event_pre_config(apr_pool_t * pconf, ap
     /* sigh, want this only the second time around */
     retained = ap_retained_data_get(userdata_key);
     if (!retained) {
-        retained = ap_retained_data_create(userdata_key, sizeof(*retained));
+        void *userdata;
+        rv = ap_retained_data_share(userdata_key,
+                                    sizeof(*retained), &userdata);
+        if (rv != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, APLOGNO()
+                         "Couldn't create shared retained data");
+            userdata = ap_retained_data_create(userdata_key,
+                                               sizeof(*retained));
+        }
+        retained = userdata;
         retained->max_daemons_limit = -1;
         retained->idle_spawn_rate = 1;
     }
Index: server/mpm/prefork/prefork.c
===================================================================
--- server/mpm/prefork/prefork.c	(revision 1585432)
+++ server/mpm/prefork/prefork.c	(working copy)
@@ -102,7 +102,7 @@ static ap_pod_t *pod;
 typedef struct prefork_retained_data {
     int first_server_limit;
     int module_loads;
-    ap_generation_t my_generation;
+    volatile ap_generation_t my_generation;
     int volatile is_graceful; /* set from signal handler */
     int maxclients_reported;
     /*
@@ -110,7 +110,7 @@ typedef struct prefork_retained_data {
      * to deal with MaxRequestWorkers changes across AP_SIG_GRACEFUL restarts.  We
      * use this value to optimize routines that have to scan the entire scoreboard.
      */
-    int max_daemons_limit;
+    volatile int max_daemons_limit;
     /*
      * idle_spawn_rate is the number of children that will be spawned on the
      * next maintenance cycle if there aren't enough idle servers.  It is
@@ -282,7 +282,7 @@ static int prefork_query(int query_code, int *resu
     *rv = APR_SUCCESS;
     switch(query_code){
     case AP_MPMQ_MAX_DAEMON_USED:
-        *result = ap_daemons_limit;
+        *result = retained->max_daemons_limit;
         break;
     case AP_MPMQ_IS_THREADED:
         *result = AP_MPMQ_NOT_SUPPORTED;
@@ -1290,7 +1290,16 @@ static int prefork_pre_config(apr_pool_t *p, apr_p
     /* sigh, want this only the second time around */
     retained = ap_retained_data_get(userdata_key);
     if (!retained) {
-        retained = ap_retained_data_create(userdata_key, sizeof(*retained));
+        void *userdata;
+        rv = ap_retained_data_share(userdata_key,
+                                    sizeof(*retained), &userdata);
+        if (rv != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, APLOGNO()
+                         "Couldn't create shared retained data");
+            userdata = ap_retained_data_create(userdata_key,
+                                               sizeof(*retained));
+        }
+        retained = userdata;
         retained->max_daemons_limit = -1;
         retained->idle_spawn_rate = 1;
     }
Index: server/mpm/simple/simple_core.c
===================================================================
--- server/mpm/simple/simple_core.c	(revision 1585432)
+++ server/mpm/simple/simple_core.c	(working copy)
@@ -38,13 +38,22 @@ apr_status_t simple_core_init_once(void)
     apr_status_t rv;
     const char *userdata_key = "mpm_simple_module";
     simple_core_t *sc;
+    void *userdata;
 
     g_simple_core = ap_retained_data_get(userdata_key);
     if (g_simple_core) {
         return APR_SUCCESS;
     }
 
-    sc = g_simple_core = ap_retained_data_create(userdata_key, sizeof(*g_simple_core));
+    rv = ap_retained_data_share(userdata_key,
+                                sizeof(*retained), &userdata);
+    if (rv != APR_SUCCESS) {
+        ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, APLOGNO()
+                     "Couldn't create shared retained data");
+        userdata = ap_retained_data_create(userdata_key,
+                                           sizeof(*retained));
+    }
+    sc = g_simple_core = userdata;
 
     apr_pool_create(&sc->pool, ap_pglobal);
 
Index: server/mpm/simple/simple_types.h
===================================================================
--- server/mpm/simple/simple_types.h	(revision 1585432)
+++ server/mpm/simple/simple_types.h	(working copy)
@@ -30,8 +30,8 @@ typedef struct simple_core_t simple_core_t;
 
 typedef struct
 {
-    int proc_count;
-    int thread_count;
+    volatile int proc_count;
+    volatile int thread_count;
     int max_requests_per_child;
 } simple_proc_mgr_t;
 
Index: server/mpm/worker/worker.c
===================================================================
--- server/mpm/worker/worker.c	(revision 1585432)
+++ server/mpm/worker/worker.c	(working copy)
@@ -142,7 +142,7 @@ typedef struct worker_retained_data {
     int first_thread_limit;
     int module_loads;
     int sick_child_detected;
-    ap_generation_t my_generation;
+    volatile ap_generation_t my_generation;
     int volatile is_graceful; /* set from signal handler */
     int maxclients_reported;
     int near_maxclients_reported;
@@ -152,7 +152,7 @@ typedef struct worker_retained_data {
      * We use this value to optimize routines that have to scan the entire
      * scoreboard.
      */
-    int max_daemons_limit;
+    volatile int max_daemons_limit;
     /*
      * idle_spawn_rate is the number of children that will be spawned on the
      * next maintenance cycle if there aren't enough idle servers.  It is
@@ -2007,7 +2007,16 @@ static int worker_pre_config(apr_pool_t *pconf, ap
     /* sigh, want this only the second time around */
     retained = ap_retained_data_get(userdata_key);
     if (!retained) {
-        retained = ap_retained_data_create(userdata_key, sizeof(*retained));
+        void *userdata;
+        rv = ap_retained_data_share(userdata_key,
+                                    sizeof(*retained), &userdata);
+        if (rv != APR_SUCCESS) {
+            ap_log_error(APLOG_MARK, APLOG_ERR, rv, NULL, APLOGNO()
+                         "Couldn't create shared retained data");
+            userdata = ap_retained_data_create(userdata_key,
+                                               sizeof(*retained));
+        }
+        retained = userdata;
         retained->max_daemons_limit = -1;
         retained->idle_spawn_rate = 1;
     }
