Apache HTTPD
mod_slotmem_shm.c
Go to the documentation of this file.
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#include "ap_mpm.h" /* for ap_mpm_query() */
29
30#define AP_SLOTMEM_IS_PREGRAB(t) (t->desc->type & AP_SLOTMEM_TYPE_PREGRAB)
31#define AP_SLOTMEM_IS_PERSIST(t) (t->desc->type & AP_SLOTMEM_TYPE_PERSIST)
32#define AP_SLOTMEM_IS_CLEARINUSE(t) (t->desc->type & AP_SLOTMEM_TYPE_CLEARINUSE)
33
34/* The description of the slots to reuse the slotmem */
35typedef struct {
36 apr_size_t size; /* size of each memory slot */
37 unsigned int num; /* number of mem slots */
38 ap_slotmem_type_t type; /* type-specific flags */
40
41#define AP_SLOTMEM_OFFSET (APR_ALIGN_DEFAULT(sizeof(sharedslotdesc_t)))
42#define AP_UNSIGNEDINT_OFFSET (APR_ALIGN_DEFAULT(sizeof(unsigned int)))
43
45 char *name; /* file based SHM path/name */
46 char *pname; /* persisted file path/name */
47 int fbased; /* filebased? */
48 void *shm; /* ptr to memory segment (apr_shm_t *) */
49 void *base; /* data set start */
50 apr_pool_t *gpool; /* per segment pool (generation cleared) */
51 char *inuse; /* in-use flag table*/
52 unsigned int *num_free; /* slot free count for this instance */
53 void *persist; /* persist dataset start */
54 const sharedslotdesc_t *desc; /* per slot desc */
55 struct ap_slotmem_instance_t *next; /* location of next allocated segment */
56};
57
58/*
59 * Layout for SHM and persisted file :
60 *
61 * +-------------------------------------------------------------+~>
62 * | desc | num_free | base (slots) | inuse (array) | md5 | desc | compat..
63 * +------+-----------------------------------------+------------+~>
64 * ^ ^ ^ \ / ^ :
65 * |______|_____________ SHM (mem->@) ______________| | _____|__/
66 * | |/ |
67 * | ^ v |
68 * |_____________________ File (mem->persist + [meta]) __|
69 */
70
71/* global pool and list of slotmem we are handling */
74
75#define DEFAULT_SLOTMEM_PREFIX "slotmem-shm-"
76#define DEFAULT_SLOTMEM_SUFFIX ".shm"
77#define DEFAULT_SLOTMEM_PERSIST_SUFFIX ".persist"
78
79/*
80 * Persist the slotmem in a file
81 * slotmem name and file name.
82 * none : no persistent data
83 * rel_name : $server_root/rel_name
84 * /abs_name : $abs_name
85 *
86 */
88 const char *slotname,
89 const char **filename,
90 const char **persistname)
91{
92 const char *fname = NULL, *pname = NULL;
93
94 if (slotname && *slotname && strcasecmp(slotname, "none") != 0) {
96 /* Each generation needs its own file name. */
97 int generation = 0;
98 ap_mpm_query(AP_MPMQ_GENERATION, &generation);
100 slotname, generation, DEFAULT_SLOTMEM_SUFFIX);
102 }
103 else {
104 /* Don't mangle the file name if given an absolute path, it's
105 * up to the caller to provide a unique name when necessary.
106 */
107 fname = slotname;
108 }
109
110 if (persistname) {
111 /* Persisted file names are immutable... */
116 NULL);
118 }
119 else {
122 NULL);
123 }
124 }
125 }
126
127 *filename = fname;
128 if (persistname) {
130 }
131 return (fname != NULL);
132}
133
135{
136 unsigned int i;
137 char *inuse;
138
139 if (!slot) {
140 return;
141 }
142
143 inuse = slot->inuse;
144
145 for (i = 0; i < slot->desc->num; i++, inuse++) {
146 if (*inuse) {
147 *inuse = 0;
148 (*slot->num_free)++;
149 }
150 }
151}
152
154{
155 apr_file_t *fp;
156 apr_status_t rv;
158 unsigned char digest[APR_MD5_DIGESTSIZE];
159 const char *storename = slotmem->pname;
160
162 "storing %s", storename);
163
164 if (storename) {
167 if (APR_STATUS_IS_EEXIST(rv)) {
171 }
172 if (rv != APR_SUCCESS) {
173 return;
174 }
177 }
179 (slotmem->desc->num * sizeof(char)) + AP_UNSIGNEDINT_OFFSET;
182 if (rv == APR_SUCCESS) {
184 }
185 if (rv == APR_SUCCESS) {
187 NULL);
188 }
189 apr_file_close(fp);
190 if (rv != APR_SUCCESS) {
192 }
193 }
194}
195
197 const char *storename, apr_size_t size,
199{
200 apr_file_t *fp;
202 void *ptr = (char *)desc + AP_SLOTMEM_OFFSET;
204 unsigned char digest[APR_MD5_DIGESTSIZE];
205 unsigned char digest2[APR_MD5_DIGESTSIZE];
207
209 "restoring %s", storename);
210
211 if (storename) {
213 pool);
214 if (rv == APR_SUCCESS) {
215 rv = apr_file_read_full(fp, ptr, nbytes, NULL);
216 if (rv == APR_SUCCESS || rv == APR_EOF) {
217 /*
218 * if at EOF, don't bother checking md5
219 * - backwards compatibility
220 * */
221 if (apr_file_eof(fp) != APR_EOF) {
223 if (rv == APR_SUCCESS || rv == APR_EOF) {
224 apr_md5(digest2, ptr, nbytes);
226 rv = APR_EMISMATCH;
227 }
228 /*
229 * if at EOF, don't bother checking desc
230 * - backwards compatibility
231 * */
232 else if (apr_file_eof(fp) != APR_EOF) {
233 rv = apr_file_read_full(fp, desc_buf, sizeof(desc_buf), NULL);
234 if (rv == APR_SUCCESS || rv == APR_EOF) {
235 if (memcmp(desc, desc_buf, sizeof(desc_buf))) {
236 rv = APR_EMISMATCH;
237 }
238 else {
239 rv = APR_SUCCESS;
240 }
241 }
242 else {
243 rv = APR_INCOMPLETE;
244 }
245 }
246 else {
247 rv = APR_EOF;
248 }
249 }
250 else {
251 rv = APR_INCOMPLETE;
252 }
253 }
254 else {
255 rv = APR_EOF;
256 }
257 if (rv == APR_EMISMATCH) {
259 "persisted slotmem md5/desc mismatch");
260 }
261 else if (rv == APR_EOF) {
263 "persisted slotmem at EOF... bypassing md5/desc match check "
264 "(old persist file?)");
265 rv = APR_SUCCESS;
266 }
267 }
268 else {
269 rv = APR_INCOMPLETE;
270 }
271 if (rv == APR_INCOMPLETE) {
273 "persisted slotmem read had unexpected size");
274 }
275 apr_file_close(fp);
276 }
277 }
278 return rv;
279}
280
281/*
282 * Whether the module is called from a MPM that re-enter main() and
283 * pre/post_config phases.
284 */
286{
287#ifdef WIN32
288 return getenv("AP_PARENT_PID") != NULL;
289#else
290 return 0;
291#endif
292}
293
295{
298
299 while (next) {
302 }
305 next = next->next;
306 }
307
309 return APR_SUCCESS;
310}
311
314 void *data, apr_pool_t *pool)
315{
316 unsigned int i;
317 char *ptr;
318 char *inuse;
320
321 if (!mem) {
322 return APR_ENOSHMAVAIL;
323 }
324
325 ptr = (char *)mem->base;
326 inuse = mem->inuse;
327 for (i = 0; i < mem->desc->num; i++, inuse++) {
328 if (!AP_SLOTMEM_IS_PREGRAB(mem) || *inuse) {
329 retval = func((void *) ptr, data, pool);
330 if (retval != APR_SUCCESS)
331 break;
332 }
333 ptr += mem->desc->size;
334 }
335 return retval;
336}
337
339 const char *name, apr_size_t item_size,
340 unsigned int item_num,
342{
343 int fbased = 1;
344 int restored = 0;
345 char *ptr;
349 const char *fname, *pname = NULL;
350 apr_shm_t *shm;
353 (item_num * sizeof(char)) + basesize;
354 int persist = (type & AP_SLOTMEM_TYPE_PERSIST) != 0;
355 apr_status_t rv;
356
357 *new = NULL;
358 if (gpool == NULL) {
359 return APR_ENOSHMAVAIL;
360 }
362 /* first try to attach to existing slotmem */
363 if (next) {
364 for (;;) {
365 if (strcmp(next->name, fname) == 0) {
366 /* we already have it */
367 *new = next;
369 "create found %s in global list", fname);
370 return APR_SUCCESS;
371 }
372 if (!next->next) {
373 break;
374 }
375 next = next->next;
376 }
377 }
379 "create didn't find %s in global list", fname);
380 }
381 else {
382 fbased = 0;
383 fname = "none";
384 }
385
386 /* first try to attach to existing shared memory */
388 "create %s: %"APR_SIZE_T_FMT"/%u", fname, item_size,
389 item_num);
390
391 {
392 /* For MPMs that run pre/post_config() phases in both the parent
393 * and children processes (e.g. winnt), SHMs created by the
394 * parent exist in the children already; attach them.
395 */
396 if (fbased) {
397 if (is_child_process()) {
398 rv = apr_shm_attach(&shm, fname, gpool);
399 }
400 else {
403 }
404 }
405 else {
406 rv = apr_shm_create(&shm, size, NULL, gpool);
407 }
409 rv, ap_server_conf, APLOGNO(02611)
410 "create: apr_shm_%s(%s) %s",
411 fbased && is_child_process() ? "attach" : "create",
412 fname, rv == APR_SUCCESS ? "succeeded" : "failed");
413 if (rv != APR_SUCCESS) {
414 return rv;
415 }
416
418 memset(desc, 0, size);
420 desc->num = item_num;
421 desc->type = type;
422
423 /*
424 * TODO: Error check the below... What error makes
425 * sense if the restore fails? Any?
426 * For now, we continue with a fresh new slotmem,
427 * but NOTICE in the log.
428 */
429 if (persist) {
431 if (rv == APR_SUCCESS) {
432 restored = 1;
433 }
434 else {
435 /* just in case, re-zero */
437 APLOGNO(02554) "could not restore %s", fname);
438 memset((char *)desc + AP_SLOTMEM_OFFSET, 0,
440 }
441 }
442 }
443
444 ptr = (char *)desc + AP_SLOTMEM_OFFSET;
445
446 /* For the chained slotmem stuff */
448 res->name = apr_pstrdup(gpool, fname);
449 res->pname = apr_pstrdup(gpool, pname);
450 res->fbased = fbased;
451 res->shm = shm;
452 res->persist = (void *)ptr;
453 res->num_free = (unsigned int *)ptr;
455 if (!restored) {
456 *res->num_free = item_num;
457 }
458 res->base = (void *)ptr;
459 res->desc = desc;
460 res->gpool = gpool;
461 res->next = NULL;
462 res->inuse = ptr + basesize;
463 if (fbased) {
464 if (globallistmem == NULL) {
466 }
467 else {
468 next->next = res;
469 }
470 }
471
472 *new = res;
473 return APR_SUCCESS;
474}
475
477 const char *name, apr_size_t *item_size,
478 unsigned int *item_num, apr_pool_t *pool)
479{
480 char *ptr;
484 const char *fname;
485 apr_shm_t *shm;
486 apr_status_t rv;
487
488 if (gpool == NULL) {
489 return APR_ENOSHMAVAIL;
490 }
492 return APR_ENOSHMAVAIL;
493 }
494
496 "attach looking for %s", fname);
497
498 /* first try to attach to existing slotmem */
499 if (next) {
500 for (;;) {
501 if (strcmp(next->name, fname) == 0) {
502 /* we already have it */
503 *new = next;
504 *item_size = next->desc->size;
505 *item_num = next->desc->num;
507 APLOGNO(02302)
508 "attach found %s: %"APR_SIZE_T_FMT"/%u", fname,
510 return APR_SUCCESS;
511 }
512 if (!next->next) {
513 break;
514 }
515 next = next->next;
516 }
517 }
518
519 /* next try to attach to existing shared memory */
520 rv = apr_shm_attach(&shm, fname, gpool);
521 if (rv != APR_SUCCESS) {
522 return rv;
523 }
524
525 /* Read the description of the slotmem */
527 ptr = (char *)desc + AP_SLOTMEM_OFFSET;
528
529 /* For the chained slotmem stuff */
531 res->name = apr_pstrdup(gpool, fname);
532 res->fbased = 1;
533 res->shm = shm;
534 res->persist = (void *)ptr;
535 res->num_free = (unsigned int *)ptr;
537 res->base = (void *)ptr;
538 res->desc = desc;
539 res->gpool = gpool;
540 res->inuse = ptr + (desc->size * desc->num);
541 res->next = NULL;
542
543 *new = res;
544 *item_size = desc->size;
545 *item_num = desc->num;
547 APLOGNO(02303)
548 "attach found %s: %"APR_SIZE_T_FMT"/%u", fname,
550 return APR_SUCCESS;
551}
552
554 unsigned int id, void **mem)
555{
556 char *ptr;
557
558 if (!slot) {
559 return APR_ENOSHMAVAIL;
560 }
561 if (id >= slot->desc->num) {
562 return APR_EINVAL;
563 }
564
565 ptr = (char *)slot->base + slot->desc->size * id;
566 if (!ptr) {
567 return APR_ENOSHMAVAIL;
568 }
569 *mem = (void *)ptr;
570 return APR_SUCCESS;
571}
572
574 unsigned char *dest, apr_size_t dest_len)
575{
576 void *ptr;
577 char *inuse;
579
580 if (!slot) {
581 return APR_ENOSHMAVAIL;
582 }
583
584 inuse = slot->inuse + id;
585 if (id >= slot->desc->num) {
586 return APR_EINVAL;
587 }
588 if (AP_SLOTMEM_IS_PREGRAB(slot) && !*inuse) {
589 return APR_NOTFOUND;
590 }
591 ret = slotmem_dptr(slot, id, &ptr);
592 if (ret != APR_SUCCESS) {
593 return ret;
594 }
595 *inuse = 1;
596 memcpy(dest, ptr, dest_len); /* bounds check? */
597 return APR_SUCCESS;
598}
599
601 unsigned char *src, apr_size_t src_len)
602{
603 void *ptr;
604 char *inuse;
606
607 if (!slot) {
608 return APR_ENOSHMAVAIL;
609 }
610
611 inuse = slot->inuse + id;
612 if (id >= slot->desc->num) {
613 return APR_EINVAL;
614 }
615 if (AP_SLOTMEM_IS_PREGRAB(slot) && !*inuse) {
616 return APR_NOTFOUND;
617 }
618 ret = slotmem_dptr(slot, id, &ptr);
619 if (ret != APR_SUCCESS) {
620 return ret;
621 }
622 *inuse=1;
623 memcpy(ptr, src, src_len); /* bounds check? */
624 return APR_SUCCESS;
625}
626
628{
629 return slot->desc->num;
630}
631
633{
635 return *slot->num_free;
636 else {
637 unsigned int i, counter=0;
638 char *inuse = slot->inuse;
639 for (i=0; i<slot->desc->num; i++, inuse++) {
640 if (!*inuse)
641 counter++;
642 }
643 return counter;
644 }
645}
646
648{
649 return slot->desc->size;
650}
651
653{
654 unsigned int i;
655 char *inuse;
656
657 if (!slot) {
658 return APR_ENOSHMAVAIL;
659 }
660
661 inuse = slot->inuse;
662
663 for (i = 0; i < slot->desc->num; i++, inuse++) {
664 if (!*inuse) {
665 break;
666 }
667 }
668 if (i >= slot->desc->num) {
670 "slotmem(%s) grab failed. Num %u/num_free %u",
673 return APR_EINVAL;
674 }
675 *inuse = 1;
676 *id = i;
677 (*slot->num_free)--;
678 return APR_SUCCESS;
679}
680
682{
683 char *inuse;
684
685 if (!slot) {
686 return APR_ENOSHMAVAIL;
687 }
688
689 if (id >= slot->desc->num) {
691 "slotmem(%s) fgrab failed. Num %u/num_free %u",
694 return APR_EINVAL;
695 }
696 inuse = slot->inuse + id;
697
698 if (!*inuse) {
699 *inuse = 1;
700 (*slot->num_free)--;
701 }
702 return APR_SUCCESS;
703}
704
706 unsigned int id)
707{
708 char *inuse;
709
710 if (!slot) {
711 return APR_ENOSHMAVAIL;
712 }
713
714 inuse = slot->inuse;
715
716 if (id >= slot->desc->num || !inuse[id] ) {
718 "slotmem(%s) release failed. Num %u/inuse[%u] %d",
720 id, (int)inuse[id]);
721 if (id >= slot->desc->num) {
722 return APR_EINVAL;
723 } else {
724 return APR_NOTFOUND;
725 }
726 }
727 inuse[id] = 0;
728 (*slot->num_free)++;
729 return APR_SUCCESS;
730}
731
747
748/* make the storage usable from outside */
750{
751 return (&storage);
752}
753
754/*
755 * Make sure the shared memory is cleaned
756 */
763
765{
766 gpool = p;
768 return OK;
769}
770
779
782 NULL, /* create per-directory config structure */
783 NULL, /* merge per-directory config structures */
784 NULL, /* create per-server config structure */
785 NULL, /* merge per-server config structures */
786 NULL, /* command apr_table_t */
787 ap_slotmem_shm_register_hook /* register hooks */
788};
Apache Multi-Processing Module library.
Memory Slot Extension Storage Module for Apache.
char * ap_runtime_dir_relative(apr_pool_t *p, const char *fname)
Definition config.c:1610
void ap_hook_post_config(ap_HOOK_post_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:105
#define AP_DECLARE_MODULE(foo)
void ap_hook_pre_config(ap_HOOK_pre_config_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition config.c:91
#define OK
Definition httpd.h:456
#define APLOGNO(n)
Definition http_log.h:117
#define APLOG_NOTICE
Definition http_log.h:69
#define APLOG_ERR
Definition http_log.h:67
#define ap_log_error
Definition http_log.h:370
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_DEBUG
Definition http_log.h:71
server_rec * ap_server_conf
Definition config.c:62
apr_status_t ap_register_provider(apr_pool_t *pool, const char *provider_group, const char *provider_name, const char *provider_version, const void *provider)
Definition provider.c:35
#define APR_EMISMATCH
Definition apr_errno.h:478
#define APR_EOF
Definition apr_errno.h:461
#define APR_INCOMPLETE
Definition apr_errno.h:452
#define APR_ENOSHMAVAIL
Definition apr_errno.h:315
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_NOTFOUND
Definition apr_errno.h:463
#define APR_EINVAL
Definition apr_errno.h:711
#define APR_MD5_DIGESTSIZE
Definition apr_md5.h:68
#define APR_STATUS_IS_EEXIST(s)
Definition apr_errno.h:1233
apr_pool_t apr_dbd_t apr_dbd_results_t ** res
Definition apr_dbd.h:287
const char * src
Definition apr_encode.h:167
#define APR_HOOK_LAST
Definition apr_hooks.h:305
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
#define AP_SLOTMEM_TYPE_PERSIST
Definition ap_slotmem.h:70
unsigned int ap_slotmem_type_t
Definition ap_slotmem.h:55
#define AP_SLOTMEM_PROVIDER_GROUP
Definition ap_slotmem.h:52
#define AP_SLOTMEM_PROVIDER_VERSION
Definition ap_slotmem.h:53
apr_status_t ap_slotmem_callback_fn_t(void *mem, void *data, apr_pool_t *pool)
Definition ap_slotmem.h:84
#define STANDARD20_MODULE_STUFF
int ap_os_is_path_absolute(apr_pool_t *p, const char *dir)
Definition util.c:229
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
void apr_size_t * nbytes
void * data
int type
#define APR_READ
Definition apr_file_io.h:93
#define APR_WRITE
Definition apr_file_io.h:94
#define APR_CREATE
Definition apr_file_io.h:95
#define APR_OS_DEFAULT
const char * fname
int strcasecmp(const char *a, const char *b)
const char apr_uint32_t * id
apr_interval_time_t apr_pollcb_cb_t func
Definition apr_poll.h:422
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
apr_shm_t * shm
apr_size_t const char * filename
Definition apr_shm.h:72
void * mem
const char * s
Definition apr_strings.h:95
apr_status_t ap_mpm_query(int query_code, int *result)
Definition mpm_common.c:421
#define AP_MPMQ_GENERATION
Definition ap_mpm.h:178
Command line options.
HTTP Daemon routines.
apr_pool_t * p
Definition md_event.c:32
static ap_slotmem_instance_t * slotmem
static int post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
static apr_size_t slotmem_slot_size(ap_slotmem_instance_t *slot)
static struct ap_slotmem_instance_t * globallistmem
#define AP_SLOTMEM_OFFSET
#define AP_UNSIGNEDINT_OFFSET
static int pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
static unsigned int slotmem_num_free_slots(ap_slotmem_instance_t *slot)
static void store_slotmem(ap_slotmem_instance_t *slotmem)
static apr_status_t slotmem_create(ap_slotmem_instance_t **new, const char *name, apr_size_t item_size, unsigned int item_num, ap_slotmem_type_t type, apr_pool_t *pool)
#define AP_SLOTMEM_IS_PREGRAB(t)
static apr_status_t slotmem_attach(ap_slotmem_instance_t **new, const char *name, apr_size_t *item_size, unsigned int *item_num, apr_pool_t *pool)
static apr_status_t slotmem_put(ap_slotmem_instance_t *slot, unsigned int id, unsigned char *src, apr_size_t src_len)
static apr_status_t slotmem_doall(ap_slotmem_instance_t *mem, ap_slotmem_callback_fn_t *func, void *data, apr_pool_t *pool)
static apr_status_t restore_slotmem(sharedslotdesc_t *desc, const char *storename, apr_size_t size, apr_pool_t *pool)
static const ap_slotmem_provider_t * slotmem_shm_getstorage(void)
static apr_status_t slotmem_get(ap_slotmem_instance_t *slot, unsigned int id, unsigned char *dest, apr_size_t dest_len)
static apr_pool_t * gpool
static APR_INLINE int is_child_process(void)
static void ap_slotmem_shm_register_hook(apr_pool_t *p)
static unsigned int slotmem_num_slots(ap_slotmem_instance_t *slot)
#define DEFAULT_SLOTMEM_SUFFIX
static void slotmem_clearinuse(ap_slotmem_instance_t *slot)
static apr_status_t cleanup_slotmem(void *param)
#define AP_SLOTMEM_IS_CLEARINUSE(t)
#define AP_SLOTMEM_IS_PERSIST(t)
static apr_status_t slotmem_dptr(ap_slotmem_instance_t *slot, unsigned int id, void **mem)
static apr_status_t slotmem_release(ap_slotmem_instance_t *slot, unsigned int id)
#define DEFAULT_SLOTMEM_PREFIX
static const ap_slotmem_provider_t storage
#define DEFAULT_SLOTMEM_PERSIST_SUFFIX
static int slotmem_filenames(apr_pool_t *pool, const char *slotname, const char **filename, const char **persistname)
static apr_status_t slotmem_grab(ap_slotmem_instance_t *slot, unsigned int *id)
static apr_status_t slotmem_fgrab(ap_slotmem_instance_t *slot, unsigned int id)
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
char * name
unsigned int * num_free
const sharedslotdesc_t * desc
struct ap_slotmem_instance_t * next
A structure to store information for each virtual server.
Definition httpd.h:1322
ap_slotmem_type_t type
const char * digest
Definition testmd5.c:30