]> granicus.if.org Git - apache/blob - modules/slotmem/mod_slotmem_shm.c
Fix mistaken reset of num_free with restored shm
[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     int restored = 0;
300     char *ptr;
301     sharedslotdesc_t desc;
302     ap_slotmem_instance_t *res;
303     ap_slotmem_instance_t *next = globallistmem;
304     const char *fname;
305     apr_shm_t *shm;
306     apr_size_t basesize = (item_size * item_num);
307     apr_size_t size = AP_SLOTMEM_OFFSET + AP_UNSIGNEDINT_OFFSET +
308                       (item_num * sizeof(char)) + basesize;
309     apr_status_t rv;
310
311     if (gpool == NULL) {
312         return APR_ENOSHMAVAIL;
313     }
314     fname = slotmem_filename(pool, name, 0);
315     if (fname) {
316         /* first try to attach to existing slotmem */
317         if (next) {
318             for (;;) {
319                 if (strcmp(next->name, fname) == 0) {
320                     /* we already have it */
321                     *new = next;
322                     return APR_SUCCESS;
323                 }
324                 if (!next->next) {
325                      break;
326                 }
327                 next = next->next;
328             }
329         }
330     }
331     else {
332         fbased = 0;
333         fname = "none";
334     }
335
336     /* first try to attach to existing shared memory */
337     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02300)
338                  "create %s: %"APR_SIZE_T_FMT"/%u", fname, item_size,
339                  item_num);
340     if (fbased) {
341         rv = apr_shm_attach(&shm, fname, gpool);
342     }
343     else {
344         rv = APR_EINVAL;
345     }
346     if (rv == APR_SUCCESS) {
347         /* check size */
348         if (apr_shm_size_get(shm) != size) {
349             apr_shm_detach(shm);
350             return APR_EINVAL;
351         }
352         ptr = (char *)apr_shm_baseaddr_get(shm);
353         memcpy(&desc, ptr, sizeof(desc));
354         if (desc.size != item_size || desc.num != item_num) {
355             apr_shm_detach(shm);
356             return APR_EINVAL;
357         }
358         ptr += AP_SLOTMEM_OFFSET;
359     }
360     else {
361         apr_size_t dsize = size - AP_SLOTMEM_OFFSET;
362         if (fbased) {
363             apr_shm_remove(fname, gpool);
364             rv = apr_shm_create(&shm, size, fname, gpool);
365         }
366         else {
367             rv = apr_shm_create(&shm, size, NULL, gpool);
368         }
369         if (rv != APR_SUCCESS) {
370             return rv;
371         }
372         if (fbased) {
373             /* Set permissions to shared memory
374              * so it can be attached by child process
375              * having different user credentials
376              *
377              * See apr:shmem/unix/shm.c
378              */
379             unixd_set_shm_perms(fname);
380         }
381         ptr = (char *)apr_shm_baseaddr_get(shm);
382         desc.size = item_size;
383         desc.num = item_num;
384         desc.type = type;
385         memcpy(ptr, &desc, sizeof(desc));
386         ptr += AP_SLOTMEM_OFFSET;
387         memset(ptr, 0, dsize);
388         /*
389          * TODO: Error check the below... What error makes
390          * sense if the restore fails? Any?
391          */
392         if (type & AP_SLOTMEM_TYPE_PERSIST) {
393             restore_slotmem(ptr, fname, dsize, pool);
394             restored = 1;
395         }
396     }
397
398     /* For the chained slotmem stuff */
399     res = (ap_slotmem_instance_t *) apr_pcalloc(gpool,
400                                                 sizeof(ap_slotmem_instance_t));
401     res->name = apr_pstrdup(gpool, fname);
402     res->fbased = fbased;
403     res->shm = shm;
404     res->num_free = (unsigned int *)ptr;
405     if (!restored) {
406         *res->num_free = item_num;
407     }
408     res->persist = (void *)ptr;
409     ptr += AP_UNSIGNEDINT_OFFSET;
410     res->base = (void *)ptr;
411     res->desc = desc;
412     res->gpool = gpool;
413     res->next = NULL;
414     res->inuse = ptr + basesize;
415     if (globallistmem == NULL) {
416         globallistmem = res;
417     }
418     else {
419         next->next = res;
420     }
421
422     *new = res;
423     return APR_SUCCESS;
424 }
425
426 static apr_status_t slotmem_attach(ap_slotmem_instance_t **new,
427                                    const char *name, apr_size_t *item_size,
428                                    unsigned int *item_num, apr_pool_t *pool)
429 {
430 /*    void *slotmem = NULL; */
431     char *ptr;
432     ap_slotmem_instance_t *res;
433     ap_slotmem_instance_t *next = globallistmem;
434     sharedslotdesc_t desc;
435     const char *fname;
436     apr_shm_t *shm;
437     apr_status_t rv;
438
439     if (gpool == NULL) {
440         return APR_ENOSHMAVAIL;
441     }
442     fname = slotmem_filename(pool, name, 0);
443     if (!fname) {
444         return APR_ENOSHMAVAIL;
445     }
446
447     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02301)
448                  "attach looking for %s", fname);
449
450     /* first try to attach to existing slotmem */
451     if (next) {
452         for (;;) {
453             if (strcmp(next->name, fname) == 0) {
454                 /* we already have it */
455                 *new = next;
456                 *item_size = next->desc.size;
457                 *item_num = next->desc.num;
458                 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
459                              APLOGNO(02302)
460                              "attach found %s: %"APR_SIZE_T_FMT"/%u", fname,
461                              *item_size, *item_num);
462                 return APR_SUCCESS;
463             }
464             if (!next->next) {
465                  break;
466             }
467             next = next->next;
468         }
469     }
470
471     /* next try to attach to existing shared memory */
472     rv = apr_shm_attach(&shm, fname, gpool);
473     if (rv != APR_SUCCESS) {
474         return rv;
475     }
476
477     /* Read the description of the slotmem */
478     ptr = (char *)apr_shm_baseaddr_get(shm);
479     memcpy(&desc, ptr, sizeof(desc));
480     ptr += AP_SLOTMEM_OFFSET;
481
482     /* For the chained slotmem stuff */
483     res = (ap_slotmem_instance_t *) apr_pcalloc(gpool,
484                                                 sizeof(ap_slotmem_instance_t));
485     res->name = apr_pstrdup(gpool, fname);
486     res->fbased = 1;
487     res->shm = shm;
488     res->num_free = (unsigned int *)ptr;
489     res->persist = (void *)ptr;
490     ptr += AP_UNSIGNEDINT_OFFSET;
491     res->base = (void *)ptr;
492     res->desc = desc;
493     res->gpool = gpool;
494     res->inuse = ptr + (desc.size * desc.num);
495     res->next = NULL;
496     if (globallistmem == NULL) {
497         globallistmem = res;
498     }
499     else {
500         next->next = res;
501     }
502
503     *new = res;
504     *item_size = desc.size;
505     *item_num = desc.num;
506     ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
507                  APLOGNO(02303)
508                  "attach found %s: %"APR_SIZE_T_FMT"/%u", fname,
509                  *item_size, *item_num);
510     return APR_SUCCESS;
511 }
512
513 static apr_status_t slotmem_dptr(ap_slotmem_instance_t *slot,
514                                  unsigned int id, void **mem)
515 {
516     char *ptr;
517
518     if (!slot) {
519         return APR_ENOSHMAVAIL;
520     }
521     if (id >= slot->desc.num) {
522         return APR_EINVAL;
523     }
524
525     ptr = (char *)slot->base + slot->desc.size * id;
526     if (!ptr) {
527         return APR_ENOSHMAVAIL;
528     }
529     *mem = (void *)ptr;
530     return APR_SUCCESS;
531 }
532
533 static apr_status_t slotmem_get(ap_slotmem_instance_t *slot, unsigned int id,
534                                 unsigned char *dest, apr_size_t dest_len)
535 {
536     void *ptr;
537     char *inuse;
538     apr_status_t ret;
539
540     if (!slot) {
541         return APR_ENOSHMAVAIL;
542     }
543
544     inuse = slot->inuse + id;
545     if (id >= slot->desc.num) {
546         return APR_EINVAL;
547     }
548     if (AP_SLOTMEM_IS_PREGRAB(slot) && !*inuse) {
549         return APR_NOTFOUND;
550     }
551     ret = slotmem_dptr(slot, id, &ptr);
552     if (ret != APR_SUCCESS) {
553         return ret;
554     }
555     *inuse = 1;
556     memcpy(dest, ptr, dest_len); /* bounds check? */
557     return APR_SUCCESS;
558 }
559
560 static apr_status_t slotmem_put(ap_slotmem_instance_t *slot, unsigned int id,
561                                 unsigned char *src, apr_size_t src_len)
562 {
563     void *ptr;
564     char *inuse;
565     apr_status_t ret;
566
567     if (!slot) {
568         return APR_ENOSHMAVAIL;
569     }
570
571     inuse = slot->inuse + id;
572     if (id >= slot->desc.num) {
573         return APR_EINVAL;
574     }
575     if (AP_SLOTMEM_IS_PREGRAB(slot) && !*inuse) {
576         return APR_NOTFOUND;
577     }
578     ret = slotmem_dptr(slot, id, &ptr);
579     if (ret != APR_SUCCESS) {
580         return ret;
581     }
582     *inuse=1;
583     memcpy(ptr, src, src_len); /* bounds check? */
584     return APR_SUCCESS;
585 }
586
587 static unsigned int slotmem_num_slots(ap_slotmem_instance_t *slot)
588 {
589     return slot->desc.num;
590 }
591
592 static unsigned int slotmem_num_free_slots(ap_slotmem_instance_t *slot)
593 {
594     if (AP_SLOTMEM_IS_PREGRAB(slot))
595         return *slot->num_free;
596     else {
597         unsigned int i, counter=0;
598         char *inuse = slot->inuse;
599         for (i=0; i<slot->desc.num; i++, inuse++) {
600             if (!*inuse)
601                 counter++;
602         }
603         return counter;
604     }
605 }
606
607 static apr_size_t slotmem_slot_size(ap_slotmem_instance_t *slot)
608 {
609     return slot->desc.size;
610 }
611
612 static apr_status_t slotmem_grab(ap_slotmem_instance_t *slot, unsigned int *id)
613 {
614     unsigned int i;
615     char *inuse;
616
617     if (!slot) {
618         return APR_ENOSHMAVAIL;
619     }
620
621     inuse = slot->inuse;
622
623     for (i = 0; i < slot->desc.num; i++, inuse++) {
624         if (!*inuse) {
625             break;
626         }
627     }
628     if (i >= slot->desc.num) {
629         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02293)
630                      "slotmem(%s) grab failed. Num %u/num_free %u",
631                      slot->name, slotmem_num_slots(slot),
632                      slotmem_num_free_slots(slot));
633         return APR_EINVAL;
634     }
635     *inuse = 1;
636     *id = i;
637     (*slot->num_free)--;
638     return APR_SUCCESS;
639 }
640
641 static apr_status_t slotmem_fgrab(ap_slotmem_instance_t *slot, unsigned int id)
642 {
643     char *inuse;
644     
645     if (!slot) {
646         return APR_ENOSHMAVAIL;
647     }
648
649     if (id >= slot->desc.num) {
650         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02397)
651                      "slotmem(%s) fgrab failed. Num %u/num_free %u",
652                      slot->name, slotmem_num_slots(slot),
653                      slotmem_num_free_slots(slot));
654         return APR_EINVAL;
655     }
656     inuse = slot->inuse + id;
657
658     if (!*inuse) {
659         *inuse = 1;
660         (*slot->num_free)--;
661     }
662     return APR_SUCCESS;
663 }
664
665 static apr_status_t slotmem_release(ap_slotmem_instance_t *slot,
666                                     unsigned int id)
667 {
668     char *inuse;
669
670     if (!slot) {
671         return APR_ENOSHMAVAIL;
672     }
673
674     inuse = slot->inuse;
675
676     if (id >= slot->desc.num || !inuse[id] ) {
677         ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02294)
678                      "slotmem(%s) release failed. Num %u/inuse[%u] %d",
679                      slot->name, slotmem_num_slots(slot),
680                      id, (int)inuse[id]);
681         if (id >= slot->desc.num) {
682             return APR_EINVAL;
683         } else {
684             return APR_NOTFOUND;
685         }
686     }
687     inuse[id] = 0;
688     (*slot->num_free)++;
689     return APR_SUCCESS;
690 }
691
692 static const ap_slotmem_provider_t storage = {
693     "sharedmem",
694     &slotmem_doall,
695     &slotmem_create,
696     &slotmem_attach,
697     &slotmem_dptr,
698     &slotmem_get,
699     &slotmem_put,
700     &slotmem_num_slots,
701     &slotmem_num_free_slots,
702     &slotmem_slot_size,
703     &slotmem_grab,
704     &slotmem_release,
705     &slotmem_fgrab
706 };
707
708 /* make the storage usuable from outside */
709 static const ap_slotmem_provider_t *slotmem_shm_getstorage(void)
710 {
711     return (&storage);
712 }
713
714 /* initialise the global pool */
715 static void slotmem_shm_initgpool(apr_pool_t *p)
716 {
717     gpool = p;
718 }
719
720 /* Add the pool_clean routine */
721 static void slotmem_shm_initialize_cleanup(apr_pool_t *p)
722 {
723     apr_pool_cleanup_register(p, &globallistmem, cleanup_slotmem,
724                               apr_pool_cleanup_null);
725 }
726
727 /*
728  * Make sure the shared memory is cleaned
729  */
730 static int post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
731                        server_rec *s)
732 {
733     slotmem_shm_initialize_cleanup(p);
734     return OK;
735 }
736
737 static int pre_config(apr_pool_t *p, apr_pool_t *plog,
738                       apr_pool_t *ptemp)
739 {
740     slotmem_shm_initgpool(p);
741     return OK;
742 }
743
744 static void ap_slotmem_shm_register_hook(apr_pool_t *p)
745 {
746     const ap_slotmem_provider_t *storage = slotmem_shm_getstorage();
747     ap_register_provider(p, AP_SLOTMEM_PROVIDER_GROUP, "shm",
748                          AP_SLOTMEM_PROVIDER_VERSION, storage);
749     ap_hook_post_config(post_config, NULL, NULL, APR_HOOK_LAST);
750     ap_hook_pre_config(pre_config, NULL, NULL, APR_HOOK_MIDDLE);
751 }
752
753 AP_DECLARE_MODULE(slotmem_shm) = {
754     STANDARD20_MODULE_STUFF,
755     NULL,                       /* create per-directory config structure */
756     NULL,                       /* merge per-directory config structures */
757     NULL,                       /* create per-server config structure */
758     NULL,                       /* merge per-server config structures */
759     NULL,                       /* command apr_table_t */
760     ap_slotmem_shm_register_hook  /* register hooks */
761 };