]> granicus.if.org Git - apache/blob - modules/slotmem/mod_slotmem_shm.c
3959e93a8e1c5034428e534704f029ec03eb8209
[apache] / modules / slotmem / mod_slotmem_shm.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /* Memory handler for a shared memory divided in slot.
18  * This one uses shared memory.
19  *
20  * Shared memory is cleaned-up for each restart, graceful or
21  * otherwise.
22  */
23
24 #include  "ap_slotmem.h"
25
26 #include "httpd.h"
27 #include "http_main.h"
28 #ifdef AP_NEED_SET_MUTEX_PERMS
29 #include "unixd.h"
30 #endif
31
32 #if APR_HAVE_UNISTD_H
33 #include <unistd.h>         /* for getpid() */
34 #endif
35
36 #if HAVE_SYS_SEM_H
37 #include <sys/shm.h>
38 #if !defined(SHM_R)
39 #define SHM_R 0400
40 #endif
41 #if !defined(SHM_W)
42 #define SHM_W 0200
43 #endif
44 #endif
45
46 #define AP_SLOTMEM_IS_PREGRAB(t)    (t->desc.type & AP_SLOTMEM_TYPE_PREGRAB)
47 #define AP_SLOTMEM_IS_PERSIST(t)    (t->desc.type & AP_SLOTMEM_TYPE_PERSIST)
48 #define AP_SLOTMEM_IS_CLEARINUSE(t) (t->desc.type & AP_SLOTMEM_TYPE_CLEARINUSE)
49
50 /* The description of the slots to reuse the slotmem */
51 typedef struct {
52     apr_size_t size;             /* size of each memory slot */
53     unsigned int num;            /* number of mem slots */
54     ap_slotmem_type_t type;      /* type-specific flags */
55 } sharedslotdesc_t;
56
57 #define AP_SLOTMEM_OFFSET (APR_ALIGN_DEFAULT(sizeof(sharedslotdesc_t)))
58 #define AP_UNSIGNEDINT_OFFSET (APR_ALIGN_DEFAULT(sizeof(unsigned int)))
59
60 struct ap_slotmem_instance_t {
61     char                 *name;       /* per segment name */
62     int                  fbased;      /* filebased? */
63     void                 *shm;        /* ptr to memory segment (apr_shm_t *) */
64     void                 *base;       /* data set start */
65     apr_pool_t           *gpool;      /* per segment global pool */
66     char                 *inuse;      /* in-use flag table*/
67     unsigned int         *num_free;   /* slot free count for this instance */
68     void                 *persist;    /* persist dataset start */
69     sharedslotdesc_t     desc;        /* per slot desc */
70     struct ap_slotmem_instance_t  *next;       /* location of next allocated segment */
71 };
72
73 /*
74  * Memory layout:
75  *     sharedslotdesc_t | num_free | slots | isuse array |
76  *                      ^          ^
77  *                      |          . base
78  *                      . persist (also num_free)
79  */
80
81 /* global pool and list of slotmem we are handling */
82 static struct ap_slotmem_instance_t *globallistmem = NULL;
83 static apr_pool_t *gpool = NULL;
84
85 #define DEFAULT_SLOTMEM_PREFIX "slotmem-shm-"
86 #define DEFAULT_SLOTMEM_SUFFIX ".shm"
87 #define DEFAULT_SLOTMEM_PERSIST_SUFFIX ".persist"
88
89 /* apr:shmem/unix/shm.c */
90 static apr_status_t unixd_set_shm_perms(const char *fname)
91 {
92 #ifdef AP_NEED_SET_MUTEX_PERMS
93 #if APR_USE_SHMEM_SHMGET || APR_USE_SHMEM_SHMGET_ANON
94     struct shmid_ds shmbuf;
95     key_t shmkey;
96     int shmid;
97
98     shmkey = ftok(fname, 1);
99     if (shmkey == (key_t)-1) {
100         return errno;
101     }
102     if ((shmid = shmget(shmkey, 0, SHM_R | SHM_W)) == -1) {
103         return errno;
104     }
105 #if MODULE_MAGIC_NUMBER_MAJOR <= 20081212
106 #define ap_unixd_config unixd_config
107 #endif
108     shmbuf.shm_perm.uid  = ap_unixd_config.user_id;
109     shmbuf.shm_perm.gid  = ap_unixd_config.group_id;
110     shmbuf.shm_perm.mode = 0600;
111     if (shmctl(shmid, IPC_SET, &shmbuf) == -1) {
112         return errno;
113     }
114     return APR_SUCCESS;
115 #else
116     return APR_ENOTIMPL;
117 #endif
118 #else
119     return APR_ENOTIMPL;
120 #endif
121 }
122
123 /*
124  * Persist the slotmem in a file
125  * slotmem name and file name.
126  * none      : no persistent data
127  * rel_name  : $server_root/rel_name
128  * /abs_name : $abs_name
129  *
130  */
131
132 static const char *slotmem_filename(apr_pool_t *pool, const char *slotmemname,
133                                     int persist)
134 {
135     const char *fname;
136     if (!slotmemname || strcasecmp(slotmemname, "none") == 0) {
137         return NULL;
138     }
139     else if (slotmemname[0] != '/') {
140         const char *filenm = apr_pstrcat(pool, DEFAULT_SLOTMEM_PREFIX,
141                                          slotmemname, DEFAULT_SLOTMEM_SUFFIX,
142                                          NULL);
143         fname = ap_runtime_dir_relative(pool, filenm);
144     }
145     else {
146         fname = slotmemname;
147     }
148
149     if (persist) {
150         return apr_pstrcat(pool, fname, DEFAULT_SLOTMEM_PERSIST_SUFFIX,
151                            NULL);
152     }
153     return fname;
154 }
155
156 static void slotmem_clearinuse(ap_slotmem_instance_t *slot)
157 {
158     unsigned int i;
159     char *inuse;
160     
161     if (!slot) {
162         return;
163     }
164     
165     inuse = slot->inuse;
166     
167     for (i = 0; i < slot->desc.num; i++, inuse++) {
168         if (*inuse) {
169             *inuse = 0;
170             (*slot->num_free)++;
171         }
172     }
173 }
174
175 static void store_slotmem(ap_slotmem_instance_t *slotmem)
176 {
177     apr_file_t *fp;
178     apr_status_t rv;
179     apr_size_t nbytes;
180     const char *storename;
181
182     storename = slotmem_filename(slotmem->gpool, slotmem->name, 1);
183
184     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02334)
185                  "storing %s", storename);
186
187     if (storename) {
188         rv = apr_file_open(&fp, storename, APR_CREATE | APR_READ | APR_WRITE,
189                            APR_OS_DEFAULT, slotmem->gpool);
190         if (APR_STATUS_IS_EEXIST(rv)) {
191             apr_file_remove(storename, slotmem->gpool);
192             rv = apr_file_open(&fp, storename, APR_CREATE | APR_READ | APR_WRITE,
193                                APR_OS_DEFAULT, slotmem->gpool);
194         }
195         if (rv != APR_SUCCESS) {
196             return;
197         }
198         if (AP_SLOTMEM_IS_CLEARINUSE(slotmem)) {
199             slotmem_clearinuse(slotmem);
200         }
201         nbytes = (slotmem->desc.size * slotmem->desc.num) +
202                  (slotmem->desc.num * sizeof(char)) + AP_UNSIGNEDINT_OFFSET;
203         /* XXX: Error handling */
204         apr_file_write_full(fp, slotmem->persist, nbytes, NULL);
205         apr_file_close(fp);
206     }
207 }
208
209 /* should be apr_status_t really */
210 static void restore_slotmem(void *ptr, const char *name, apr_size_t size,
211                             apr_pool_t *pool)
212 {
213     const char *storename;
214     apr_file_t *fp;
215     apr_size_t nbytes = size;
216     apr_status_t rv;
217
218     storename = slotmem_filename(pool, name, 1);
219
220     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02335)
221                  "restoring %s", storename);
222
223     if (storename) {
224         rv = apr_file_open(&fp, storename, APR_READ | APR_WRITE, APR_OS_DEFAULT,
225                            pool);
226         if (rv == APR_SUCCESS) {
227             apr_finfo_t fi;
228             if (apr_file_info_get(&fi, APR_FINFO_SIZE, fp) == APR_SUCCESS) {
229                 if (fi.size == nbytes) {
230                     apr_file_read(fp, ptr, &nbytes);
231                 }
232                 else {
233                     apr_file_close(fp);
234                     apr_file_remove(storename, pool);
235                     return;
236                 }
237             }
238             apr_file_close(fp);
239         }
240     }
241 }
242
243 static apr_status_t cleanup_slotmem(void *param)
244 {
245     ap_slotmem_instance_t **mem = param;
246
247     if (*mem) {
248         ap_slotmem_instance_t *next = *mem;
249         while (next) {
250             if (AP_SLOTMEM_IS_PERSIST(next)) {
251                 store_slotmem(next);
252             }
253             if (next->fbased) {
254                 apr_shm_remove(next->name, next->gpool);
255             }
256             apr_shm_destroy((apr_shm_t *)next->shm);
257             next = next->next;
258         }
259     }
260     /* apr_pool_destroy(gpool); */
261     globallistmem = NULL;
262     return APR_SUCCESS;
263 }
264
265 static apr_status_t slotmem_doall(ap_slotmem_instance_t *mem,
266                                   ap_slotmem_callback_fn_t *func,
267                                   void *data, apr_pool_t *pool)
268 {
269     unsigned int i;
270     char *ptr;
271     char *inuse;
272     apr_status_t retval = APR_SUCCESS;
273
274     if (!mem) {
275         return APR_ENOSHMAVAIL;
276     }
277
278     ptr = (char *)mem->base;
279     inuse = mem->inuse;
280     for (i = 0; i < mem->desc.num; i++, inuse++) {
281         if (!AP_SLOTMEM_IS_PREGRAB(mem) ||
282            (AP_SLOTMEM_IS_PREGRAB(mem) && *inuse)) {
283             retval = func((void *) ptr, data, pool);
284             if (retval != APR_SUCCESS)
285                 break;
286         }
287         ptr += mem->desc.size;
288     }
289     return retval;
290 }
291
292 static apr_status_t slotmem_create(ap_slotmem_instance_t **new,
293                                    const char *name, apr_size_t item_size,
294                                    unsigned int item_num,
295                                    ap_slotmem_type_t type, apr_pool_t *pool)
296 {
297 /*    void *slotmem = NULL; */
298     int fbased = 1;
299     char *ptr;
300     sharedslotdesc_t desc;
301     ap_slotmem_instance_t *res;
302     ap_slotmem_instance_t *next = globallistmem;
303     const char *fname;
304     apr_shm_t *shm;
305     apr_size_t basesize = (item_size * item_num);
306     apr_size_t size = AP_SLOTMEM_OFFSET + AP_UNSIGNEDINT_OFFSET +
307                       (item_num * sizeof(char)) + basesize;
308     apr_status_t rv;
309
310     if (gpool == NULL) {
311         return APR_ENOSHMAVAIL;
312     }
313     fname = slotmem_filename(pool, name, 0);
314     if (fname) {
315         /* first try to attach to existing slotmem */
316         if (next) {
317             for (;;) {
318                 if (strcmp(next->name, fname) == 0) {
319                     /* we already have it */
320                     *new = next;
321                     return APR_SUCCESS;
322                 }
323                 if (!next->next) {
324                      break;
325                 }
326                 next = next->next;
327             }
328         }
329     }
330     else {
331         fbased = 0;
332         fname = "none";
333     }
334
335     /* first try to attach to existing shared memory */
336     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02300)
337                  "create %s: %"APR_SIZE_T_FMT"/%u", fname, item_size,
338                  item_num);
339     if (fbased) {
340         rv = apr_shm_attach(&shm, fname, gpool);
341     }
342     else {
343         rv = APR_EINVAL;
344     }
345     if (rv == APR_SUCCESS) {
346         /* check size */
347         if (apr_shm_size_get(shm) != size) {
348             apr_shm_detach(shm);
349             return APR_EINVAL;
350         }
351         ptr = (char *)apr_shm_baseaddr_get(shm);
352         memcpy(&desc, ptr, sizeof(desc));
353         if (desc.size != item_size || desc.num != item_num) {
354             apr_shm_detach(shm);
355             return APR_EINVAL;
356         }
357         ptr += AP_SLOTMEM_OFFSET;
358     }
359     else {
360         apr_size_t dsize = size - AP_SLOTMEM_OFFSET;
361         if (fbased) {
362             apr_shm_remove(fname, gpool);
363             rv = apr_shm_create(&shm, size, fname, gpool);
364         }
365         else {
366             rv = apr_shm_create(&shm, size, NULL, gpool);
367         }
368         if (rv != APR_SUCCESS) {
369             return rv;
370         }
371         if (fbased) {
372             /* Set permissions to shared memory
373              * so it can be attached by child process
374              * having different user credentials
375              *
376              * See apr:shmem/unix/shm.c
377              */
378             unixd_set_shm_perms(fname);
379         }
380         ptr = (char *)apr_shm_baseaddr_get(shm);
381         desc.size = item_size;
382         desc.num = item_num;
383         desc.type = type;
384         memcpy(ptr, &desc, sizeof(desc));
385         ptr += AP_SLOTMEM_OFFSET;
386         memset(ptr, 0, dsize);
387         /*
388          * TODO: Error check the below... What error makes
389          * sense if the restore fails? Any?
390          */
391         if (type & AP_SLOTMEM_TYPE_PERSIST) {
392             restore_slotmem(ptr, fname, dsize, pool);
393         }
394     }
395
396     /* For the chained slotmem stuff */
397     res = (ap_slotmem_instance_t *) apr_pcalloc(gpool,
398                                                 sizeof(ap_slotmem_instance_t));
399     res->name = apr_pstrdup(gpool, fname);
400     res->fbased = fbased;
401     res->shm = shm;
402     res->num_free = (unsigned int *)ptr;
403     *res->num_free = item_num;
404     res->persist = (void *)ptr;
405     ptr += AP_UNSIGNEDINT_OFFSET;
406     res->base = (void *)ptr;
407     res->desc = desc;
408     res->gpool = gpool;
409     res->next = NULL;
410     res->inuse = ptr + basesize;
411     if (globallistmem == NULL) {
412         globallistmem = res;
413     }
414     else {
415         next->next = res;
416     }
417
418     *new = res;
419     return APR_SUCCESS;
420 }
421
422 static apr_status_t slotmem_attach(ap_slotmem_instance_t **new,
423                                    const char *name, apr_size_t *item_size,
424                                    unsigned int *item_num, apr_pool_t *pool)
425 {
426 /*    void *slotmem = NULL; */
427     char *ptr;
428     ap_slotmem_instance_t *res;
429     ap_slotmem_instance_t *next = globallistmem;
430     sharedslotdesc_t desc;
431     const char *fname;
432     apr_shm_t *shm;
433     apr_status_t rv;
434
435     if (gpool == NULL) {
436         return APR_ENOSHMAVAIL;
437     }
438     fname = slotmem_filename(pool, name, 0);
439     if (!fname) {
440         return APR_ENOSHMAVAIL;
441     }
442
443     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02301)
444                  "attach looking for %s", fname);
445
446     /* first try to attach to existing slotmem */
447     if (next) {
448         for (;;) {
449             if (strcmp(next->name, fname) == 0) {
450                 /* we already have it */
451                 *new = next;
452                 *item_size = next->desc.size;
453                 *item_num = next->desc.num;
454                 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
455                              APLOGNO(02302)
456                              "attach found %s: %"APR_SIZE_T_FMT"/%u", fname,
457                              *item_size, *item_num);
458                 return APR_SUCCESS;
459             }
460             if (!next->next) {
461                  break;
462             }
463             next = next->next;
464         }
465     }
466
467     /* next try to attach to existing shared memory */
468     rv = apr_shm_attach(&shm, fname, gpool);
469     if (rv != APR_SUCCESS) {
470         return rv;
471     }
472
473     /* Read the description of the slotmem */
474     ptr = (char *)apr_shm_baseaddr_get(shm);
475     memcpy(&desc, ptr, sizeof(desc));
476     ptr += AP_SLOTMEM_OFFSET;
477
478     /* For the chained slotmem stuff */
479     res = (ap_slotmem_instance_t *) apr_pcalloc(gpool,
480                                                 sizeof(ap_slotmem_instance_t));
481     res->name = apr_pstrdup(gpool, fname);
482     res->fbased = 1;
483     res->shm = shm;
484     res->num_free = (unsigned int *)ptr;
485     res->persist = (void *)ptr;
486     ptr += AP_UNSIGNEDINT_OFFSET;
487     res->base = (void *)ptr;
488     res->desc = desc;
489     res->gpool = gpool;
490     res->inuse = ptr + (desc.size * desc.num);
491     res->next = NULL;
492     if (globallistmem == NULL) {
493         globallistmem = res;
494     }
495     else {
496         next->next = res;
497     }
498
499     *new = res;
500     *item_size = desc.size;
501     *item_num = desc.num;
502     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
503                  APLOGNO(02303)
504                  "attach found %s: %"APR_SIZE_T_FMT"/%u", fname,
505                  *item_size, *item_num);
506     return APR_SUCCESS;
507 }
508
509 static apr_status_t slotmem_dptr(ap_slotmem_instance_t *slot,
510                                  unsigned int id, void **mem)
511 {
512     char *ptr;
513
514     if (!slot) {
515         return APR_ENOSHMAVAIL;
516     }
517     if (id >= slot->desc.num) {
518         return APR_EINVAL;
519     }
520
521     ptr = (char *)slot->base + slot->desc.size * id;
522     if (!ptr) {
523         return APR_ENOSHMAVAIL;
524     }
525     *mem = (void *)ptr;
526     return APR_SUCCESS;
527 }
528
529 static apr_status_t slotmem_get(ap_slotmem_instance_t *slot, unsigned int id,
530                                 unsigned char *dest, apr_size_t dest_len)
531 {
532     void *ptr;
533     char *inuse;
534     apr_status_t ret;
535
536     if (!slot) {
537         return APR_ENOSHMAVAIL;
538     }
539
540     inuse = slot->inuse + id;
541     if (id >= slot->desc.num) {
542         return APR_EINVAL;
543     }
544     if (AP_SLOTMEM_IS_PREGRAB(slot) && !*inuse) {
545         return APR_NOTFOUND;
546     }
547     ret = slotmem_dptr(slot, id, &ptr);
548     if (ret != APR_SUCCESS) {
549         return ret;
550     }
551     *inuse = 1;
552     memcpy(dest, ptr, dest_len); /* bounds check? */
553     return APR_SUCCESS;
554 }
555
556 static apr_status_t slotmem_put(ap_slotmem_instance_t *slot, unsigned int id,
557                                 unsigned char *src, apr_size_t src_len)
558 {
559     void *ptr;
560     char *inuse;
561     apr_status_t ret;
562
563     if (!slot) {
564         return APR_ENOSHMAVAIL;
565     }
566
567     inuse = slot->inuse + id;
568     if (id >= slot->desc.num) {
569         return APR_EINVAL;
570     }
571     if (AP_SLOTMEM_IS_PREGRAB(slot) && !*inuse) {
572         return APR_NOTFOUND;
573     }
574     ret = slotmem_dptr(slot, id, &ptr);
575     if (ret != APR_SUCCESS) {
576         return ret;
577     }
578     *inuse=1;
579     memcpy(ptr, src, src_len); /* bounds check? */
580     return APR_SUCCESS;
581 }
582
583 static unsigned int slotmem_num_slots(ap_slotmem_instance_t *slot)
584 {
585     return slot->desc.num;
586 }
587
588 static unsigned int slotmem_num_free_slots(ap_slotmem_instance_t *slot)
589 {
590     if (AP_SLOTMEM_IS_PREGRAB(slot))
591         return *slot->num_free;
592     else {
593         unsigned int i, counter=0;
594         char *inuse = slot->inuse;
595         for (i=0; i<slot->desc.num; i++, inuse++) {
596             if (!*inuse)
597                 counter++;
598         }
599         return counter;
600     }
601 }
602
603 static apr_size_t slotmem_slot_size(ap_slotmem_instance_t *slot)
604 {
605     return slot->desc.size;
606 }
607
608 static apr_status_t slotmem_grab(ap_slotmem_instance_t *slot, unsigned int *id)
609 {
610     unsigned int i;
611     char *inuse;
612
613     if (!slot) {
614         return APR_ENOSHMAVAIL;
615     }
616
617     inuse = slot->inuse;
618
619     for (i = 0; i < slot->desc.num; i++, inuse++) {
620         if (!*inuse) {
621             break;
622         }
623     }
624     if (i >= slot->desc.num) {
625         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02293)
626                      "slotmem(%s) grab failed. Num %u/num_free %u",
627                      slot->name, slotmem_num_slots(slot),
628                      slotmem_num_free_slots(slot));
629         return APR_EINVAL;
630     }
631     *inuse = 1;
632     *id = i;
633     (*slot->num_free)--;
634     return APR_SUCCESS;
635 }
636
637 static apr_status_t slotmem_fgrab(ap_slotmem_instance_t *slot, unsigned int id)
638 {
639     char *inuse;
640     
641     if (!slot) {
642         return APR_ENOSHMAVAIL;
643     }
644
645     if (id >= slot->desc.num) {
646         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02397)
647                      "slotmem(%s) fgrab failed. Num %u/num_free %u",
648                      slot->name, slotmem_num_slots(slot),
649                      slotmem_num_free_slots(slot));
650         return APR_EINVAL;
651     }
652     inuse = slot->inuse + id;
653
654     if (!*inuse) {
655         *inuse = 1;
656         (*slot->num_free)--;
657     }
658     return APR_SUCCESS;
659 }
660
661 static apr_status_t slotmem_release(ap_slotmem_instance_t *slot,
662                                     unsigned int id)
663 {
664     char *inuse;
665
666     if (!slot) {
667         return APR_ENOSHMAVAIL;
668     }
669
670     inuse = slot->inuse;
671
672     if (id >= slot->desc.num || !inuse[id] ) {
673         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02294)
674                      "slotmem(%s) release failed. Num %u/inuse[%u] %d",
675                      slot->name, slotmem_num_slots(slot),
676                      id, (int)inuse[id]);
677         if (id >= slot->desc.num) {
678             return APR_EINVAL;
679         } else {
680             return APR_NOTFOUND;
681         }
682     }
683     inuse[id] = 0;
684     (*slot->num_free)++;
685     return APR_SUCCESS;
686 }
687
688 static const ap_slotmem_provider_t storage = {
689     "sharedmem",
690     &slotmem_doall,
691     &slotmem_create,
692     &slotmem_attach,
693     &slotmem_dptr,
694     &slotmem_get,
695     &slotmem_put,
696     &slotmem_num_slots,
697     &slotmem_num_free_slots,
698     &slotmem_slot_size,
699     &slotmem_grab,
700     &slotmem_release,
701     &slotmem_fgrab
702 };
703
704 /* make the storage usuable from outside */
705 static const ap_slotmem_provider_t *slotmem_shm_getstorage(void)
706 {
707     return (&storage);
708 }
709
710 /* initialise the global pool */
711 static void slotmem_shm_initgpool(apr_pool_t *p)
712 {
713     gpool = p;
714 }
715
716 /* Add the pool_clean routine */
717 static void slotmem_shm_initialize_cleanup(apr_pool_t *p)
718 {
719     apr_pool_cleanup_register(p, &globallistmem, cleanup_slotmem,
720                               apr_pool_cleanup_null);
721 }
722
723 /*
724  * Make sure the shared memory is cleaned
725  */
726 static int post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
727                        server_rec *s)
728 {
729     slotmem_shm_initialize_cleanup(p);
730     return OK;
731 }
732
733 static int pre_config(apr_pool_t *p, apr_pool_t *plog,
734                       apr_pool_t *ptemp)
735 {
736     slotmem_shm_initgpool(p);
737     return OK;
738 }
739
740 static void ap_slotmem_shm_register_hook(apr_pool_t *p)
741 {
742     const ap_slotmem_provider_t *storage = slotmem_shm_getstorage();
743     ap_register_provider(p, AP_SLOTMEM_PROVIDER_GROUP, "shm",
744                          AP_SLOTMEM_PROVIDER_VERSION, storage);
745     ap_hook_post_config(post_config, NULL, NULL, APR_HOOK_LAST);
746     ap_hook_pre_config(pre_config, NULL, NULL, APR_HOOK_MIDDLE);
747 }
748
749 AP_DECLARE_MODULE(slotmem_shm) = {
750     STANDARD20_MODULE_STUFF,
751     NULL,                       /* create per-directory config structure */
752     NULL,                       /* merge per-directory config structures */
753     NULL,                       /* create per-server config structure */
754     NULL,                       /* merge per-server config structures */
755     NULL,                       /* command apr_table_t */
756     ap_slotmem_shm_register_hook  /* register hooks */
757 };