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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 /* Memory handler for a shared memory divided in slot.
18 * This one uses shared memory.
21 #include "ap_slotmem.h"
24 #ifdef AP_NEED_SET_MUTEX_PERMS
29 #include <unistd.h> /* for getpid() */
42 #define AP_SLOTMEM_IS_PREGRAB(t) (t->type & AP_SLOTMEM_TYPE_PREGRAB)
44 struct ap_slotmem_instance_t {
45 char *name; /* per segment name */
46 void *shm; /* ptr to memory segment (apr_shm_t *) */
47 void *base; /* data set start */
48 apr_size_t size; /* size of each memory slot */
49 unsigned int num; /* number of mem slots */
50 apr_pool_t *gpool; /* per segment global pool */
51 char *inuse; /* in-use flag table*/
52 ap_slotmem_type_t type; /* type-specific flags */
53 struct ap_slotmem_instance_t *next; /* location of next allocated segment */
57 /* The description of the slots to reuse the slotmem */
58 struct sharedslotdesc {
60 unsigned int item_num;
61 ap_slotmem_type_t type;
66 * sharedslotdesc | slots | isuse array
69 /* global pool and list of slotmem we are handling */
70 static struct ap_slotmem_instance_t *globallistmem = NULL;
71 static apr_pool_t *gpool = NULL;
73 /* apr:shmem/unix/shm.c */
74 static apr_status_t unixd_set_shm_perms(const char *fname)
76 #ifdef AP_NEED_SET_MUTEX_PERMS
77 #if APR_USE_SHMEM_SHMGET || APR_USE_SHMEM_SHMGET_ANON
78 struct shmid_ds shmbuf;
82 shmkey = ftok(fname, 1);
83 if (shmkey == (key_t)-1) {
86 if ((shmid = shmget(shmkey, 0, SHM_R | SHM_W)) == -1) {
89 #if MODULE_MAGIC_NUMBER_MAJOR > 20081212
90 shmbuf.shm_perm.uid = ap_unixd_config.user_id;
91 shmbuf.shm_perm.gid = ap_unixd_config.group_id;
93 shmbuf.shm_perm.uid = unixd_config.user_id;
94 shmbuf.shm_perm.gid = unixd_config.group_id;
96 shmbuf.shm_perm.mode = 0600;
97 if (shmctl(shmid, IPC_SET, &shmbuf) == -1) {
110 * Persiste the slotmem in a file
111 * slotmem name and file name.
112 * anonymous : $server_root/logs/anonymous.slotmem
113 * :module.c : $server_root/logs/module.c.slotmem
114 * abs_name : $abs_name.slotmem
117 static const char *store_filename(apr_pool_t *pool, const char *slotmemname)
119 const char *storename;
121 if (strcmp(slotmemname, "anonymous") == 0)
122 fname = ap_server_root_relative(pool, "logs/anonymous");
123 else if (slotmemname[0] == ':') {
125 tmpname = apr_pstrcat(pool, "logs/", &slotmemname[1], NULL);
126 fname = ap_server_root_relative(pool, tmpname);
131 storename = apr_pstrcat(pool, fname, ".slotmem", NULL);
135 static void store_slotmem(ap_slotmem_instance_t *slotmem)
140 const char *storename;
142 storename = store_filename(slotmem->gpool, slotmem->name);
144 rv = apr_file_open(&fp, storename, APR_CREATE | APR_READ | APR_WRITE, APR_OS_DEFAULT, slotmem->gpool);
145 if (APR_STATUS_IS_EEXIST(rv)) {
146 apr_file_remove(storename, slotmem->gpool);
147 rv = apr_file_open(&fp, storename, APR_CREATE | APR_READ | APR_WRITE, APR_OS_DEFAULT, slotmem->gpool);
149 if (rv != APR_SUCCESS) {
152 nbytes = (slotmem->size * slotmem->num) + (slotmem->num * sizeof(char));
153 apr_file_write(fp, slotmem->base, &nbytes);
157 static void restore_slotmem(void *ptr, const char *name, apr_size_t size, apr_pool_t *pool)
159 const char *storename;
161 apr_size_t nbytes = size;
164 storename = store_filename(pool, name);
165 rv = apr_file_open(&fp, storename, APR_READ | APR_WRITE, APR_OS_DEFAULT, pool);
166 if (rv == APR_SUCCESS) {
168 if (apr_file_info_get(&fi, APR_FINFO_SIZE, fp) == APR_SUCCESS) {
169 if (fi.size == nbytes) {
170 apr_file_read(fp, ptr, &nbytes);
174 apr_file_remove(storename, pool);
182 static apr_status_t cleanup_slotmem(void *param)
184 ap_slotmem_instance_t **mem = param;
186 apr_pool_t *pool = NULL;
189 ap_slotmem_instance_t *next = *mem;
193 rv = apr_shm_destroy((apr_shm_t *)next->shm);
196 apr_pool_destroy(pool);
201 static apr_status_t slotmem_doall(ap_slotmem_instance_t *mem, ap_slotmem_callback_fn_t *func, void *data, apr_pool_t *pool)
208 return APR_ENOSHMAVAIL;
213 for (i = 0; i < mem->num; i++, inuse++) {
214 if (!AP_SLOTMEM_IS_PREGRAB(mem) ||
215 (AP_SLOTMEM_IS_PREGRAB(mem) && *inuse)) {
216 func((void *) ptr, data, pool);
223 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)
225 /* void *slotmem = NULL; */
227 struct sharedslotdesc desc;
228 ap_slotmem_instance_t *res;
229 ap_slotmem_instance_t *next = globallistmem;
232 apr_size_t basesize = (item_size * item_num);
233 apr_size_t size = sizeof(struct sharedslotdesc) + (item_num * sizeof(char)) + basesize;
237 return APR_ENOSHMAVAIL;
239 if (name[0] == ':') {
243 fname = ap_server_root_relative(pool, name);
246 /* first try to attach to existing slotmem */
248 if (strcmp(next->name, fname) == 0) {
249 /* we already have it */
260 /* first try to attach to existing shared memory */
261 if (name && name[0] != ':') {
262 rv = apr_shm_attach(&shm, fname, gpool);
267 if (rv == APR_SUCCESS) {
269 if (apr_shm_size_get(shm) != size) {
273 ptr = apr_shm_baseaddr_get(shm);
274 memcpy(&desc, ptr, sizeof(desc));
275 if (desc.item_size != item_size || desc.item_num != item_num) {
279 ptr = ptr + sizeof(desc);
282 apr_size_t dsize = size - sizeof(struct sharedslotdesc);
283 if (name && name[0] != ':') {
284 apr_shm_remove(fname, gpool);
285 rv = apr_shm_create(&shm, size, fname, gpool);
288 rv = apr_shm_create(&shm, size, NULL, gpool);
290 if (rv != APR_SUCCESS) {
293 if (name && name[0] != ':') {
294 /* Set permissions to shared memory
295 * so it can be attached by child process
296 * having different user credentials
298 * See apr:shmem/unix/shm.c
300 unixd_set_shm_perms(fname);
302 ptr = apr_shm_baseaddr_get(shm);
303 desc.item_size = item_size;
304 desc.item_num = item_num;
306 memcpy(ptr, &desc, sizeof(desc));
307 ptr = ptr + sizeof(desc);
308 memset(ptr, 0, dsize);
309 if (type & AP_SLOTMEM_TYPE_PERSIST)
310 restore_slotmem(ptr, fname, dsize, pool);
313 /* For the chained slotmem stuff */
314 res = (ap_slotmem_instance_t *) apr_pcalloc(gpool, sizeof(ap_slotmem_instance_t));
315 res->name = apr_pstrdup(gpool, fname);
318 res->size = item_size;
323 res->inuse = ptr + basesize;
324 if (globallistmem == NULL) {
335 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)
337 /* void *slotmem = NULL; */
339 ap_slotmem_instance_t *res;
340 ap_slotmem_instance_t *next = globallistmem;
341 struct sharedslotdesc desc;
347 return APR_ENOSHMAVAIL;
350 if (name[0] == ':') {
354 fname = ap_server_root_relative(pool, name);
358 return APR_ENOSHMAVAIL;
361 /* first try to attach to existing slotmem */
363 if (strcmp(next->name, fname) == 0) {
364 /* we already have it */
366 *item_size = next->size;
367 *item_num = next->num;
373 /* first try to attach to existing shared memory */
374 rv = apr_shm_attach(&shm, fname, gpool);
375 if (rv != APR_SUCCESS) {
379 /* Read the description of the slotmem */
380 ptr = apr_shm_baseaddr_get(shm);
381 memcpy(&desc, ptr, sizeof(desc));
382 ptr = ptr + sizeof(desc);
384 /* For the chained slotmem stuff */
385 res = (ap_slotmem_instance_t *) apr_pcalloc(gpool, sizeof(ap_slotmem_instance_t));
386 res->name = apr_pstrdup(gpool, fname);
389 res->size = desc.item_size;
390 res->num = desc.item_num;
391 res->type = desc.type;
393 res->inuse = ptr + (desc.item_size * desc.item_num);
395 if (globallistmem == NULL) {
403 *item_size = desc.item_size;
404 *item_num = desc.item_num;
408 static apr_status_t slotmem_dptr(ap_slotmem_instance_t *slot, unsigned int id, void **mem)
413 return APR_ENOSHMAVAIL;
415 if (id < 0 || id >= slot->num) {
416 return APR_ENOSHMAVAIL;
419 ptr = slot->base + slot->size * id;
421 return APR_ENOSHMAVAIL;
427 static apr_status_t slotmem_get(ap_slotmem_instance_t *slot, unsigned int id, unsigned char *dest, apr_size_t dest_len)
434 return APR_ENOSHMAVAIL;
437 inuse = slot->inuse + id;
438 if (id >= slot->num || (AP_SLOTMEM_IS_PREGRAB(slot) && !*inuse)) {
441 ret = slotmem_dptr(slot, id, &ptr);
442 if (ret != APR_SUCCESS) {
445 memcpy(dest, ptr, dest_len); /* bounds check? */
449 static apr_status_t slotmem_put(ap_slotmem_instance_t *slot, unsigned int id, unsigned char *src, apr_size_t src_len)
456 return APR_ENOSHMAVAIL;
459 inuse = slot->inuse + id;
460 if (id >= slot->num || (AP_SLOTMEM_IS_PREGRAB(slot) && !*inuse)) {
463 ret = slotmem_dptr(slot, id, &ptr);
464 if (ret != APR_SUCCESS) {
467 memcpy(ptr, src, src_len); /* bounds check? */
471 static unsigned int slotmem_num_slots(ap_slotmem_instance_t *slot)
476 static apr_size_t slotmem_slot_size(ap_slotmem_instance_t *slot)
482 * XXXX: if !AP_SLOTMEM_IS_PREGRAB, then still worry about
483 * inuse for grab and return?
485 static apr_status_t slotmem_grab(ap_slotmem_instance_t *slot, unsigned int *id)
491 return APR_ENOSHMAVAIL;
496 for (i = 0; i < slot->num; i++, inuse++) {
501 if (i >= slot->num) {
502 return APR_ENOSHMAVAIL;
509 static apr_status_t slotmem_release(ap_slotmem_instance_t *slot, unsigned int id)
514 return APR_ENOSHMAVAIL;
519 if (id >= slot->num || !inuse[id] ) {
526 static const ap_slotmem_provider_t storage = {
538 /* make the storage usuable from outside */
539 static const ap_slotmem_provider_t *slotmem_shm_getstorage(void)
544 /* initialise the global pool */
545 static void slotmem_shm_initgpool(apr_pool_t *p)
550 /* Add the pool_clean routine */
551 static void slotmem_shm_initialize_cleanup(apr_pool_t *p)
553 apr_pool_cleanup_register(p, &globallistmem, cleanup_slotmem, apr_pool_cleanup_null);
557 * Make sure the shared memory is cleaned
559 static int post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
562 const char *userdata_key = "slotmem_shm_post_config";
564 apr_pool_userdata_get(&data, userdata_key, s->process->pool);
566 apr_pool_userdata_set((const void *)1, userdata_key,
567 apr_pool_cleanup_null, s->process->pool);
571 slotmem_shm_initialize_cleanup(p);
575 static int pre_config(apr_pool_t *p, apr_pool_t *plog,
578 apr_pool_t *global_pool;
581 rv = apr_pool_create(&global_pool, NULL);
582 if (rv != APR_SUCCESS) {
583 ap_log_error(APLOG_MARK, APLOG_CRIT, rv, NULL,
584 "Fatal error: unable to create global pool for shared slotmem");
587 slotmem_shm_initgpool(global_pool);
591 static void ap_slotmem_shm_register_hook(apr_pool_t *p)
593 const ap_slotmem_provider_t *storage = slotmem_shm_getstorage();
594 ap_register_provider(p, AP_SLOTMEM_PROVIDER_GROUP, "shared", "0", storage);
595 ap_hook_post_config(post_config, NULL, NULL, APR_HOOK_LAST);
596 ap_hook_pre_config(pre_config, NULL, NULL, APR_HOOK_MIDDLE);
599 module AP_MODULE_DECLARE_DATA slotmem_shm_module = {
600 STANDARD20_MODULE_STUFF,
601 NULL, /* create per-directory config structure */
602 NULL, /* merge per-directory config structures */
603 NULL, /* create per-server config structure */
604 NULL, /* merge per-server config structures */
605 NULL, /* command apr_table_t */
606 ap_slotmem_shm_register_hook /* register hooks */