/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* Memory handler for a plain memory divided in slot. * This one uses plain memory. */ #include "ap_slotmem.h" #define AP_SLOTMEM_IS_PREGRAB(t) (t->type & AP_SLOTMEM_TYPE_PREGRAB) struct ap_slotmem_instance_t { char *name; /* per segment name */ void *base; /* data set start */ apr_size_t size; /* size of each memory slot */ unsigned int num; /* number of mem slots */ apr_pool_t *gpool; /* per segment global pool */ char *inuse; /* in-use flag table*/ ap_slotmem_type_t type; /* type-specific flags */ struct ap_slotmem_instance_t *next; /* location of next allocated segment */ }; /* global pool and list of slotmem we are handling */ static struct ap_slotmem_instance_t *globallistmem = NULL; static apr_pool_t *gpool = NULL; static apr_status_t slotmem_do(ap_slotmem_instance_t *mem, ap_slotmem_callback_fn_t *func, void *data, apr_pool_t *pool) { unsigned int i; char *ptr; char *inuse; apr_status_t retval = APR_SUCCESS; if (!mem) return APR_ENOSHMAVAIL; ptr = (char *)mem->base; inuse = mem->inuse; for (i = 0; i < mem->num; i++, inuse++) { if (!AP_SLOTMEM_IS_PREGRAB(mem) || (AP_SLOTMEM_IS_PREGRAB(mem) && *inuse)) { retval = func((void *) ptr, data, pool); if (retval != APR_SUCCESS) break; } ptr += mem->size; } return retval; } 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) { ap_slotmem_instance_t *res; ap_slotmem_instance_t *next = globallistmem; apr_size_t basesize = (item_size * item_num); const char *fname; if (name) { if (name[0] == ':') fname = name; else fname = ap_runtime_dir_relative(pool, name); /* first try to attach to existing slotmem */ if (next) { for (;;) { if (strcmp(next->name, fname) == 0) { /* we already have it */ *new = next; return APR_SUCCESS; } if (!next->next) { break; } next = next->next; } } } else fname = "anonymous"; /* create the memory using the gpool */ res = (ap_slotmem_instance_t *) apr_pcalloc(gpool, sizeof(ap_slotmem_instance_t)); res->base = apr_pcalloc(gpool, basesize + (item_num * sizeof(char))); if (!res->base) return APR_ENOSHMAVAIL; /* For the chained slotmem stuff */ res->name = apr_pstrdup(gpool, fname); res->size = item_size; res->num = item_num; res->next = NULL; res->type = type; res->inuse = (char *)res->base + basesize; if (globallistmem == NULL) globallistmem = res; else next->next = res; *new = res; return APR_SUCCESS; } 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) { ap_slotmem_instance_t *next = globallistmem; const char *fname; if (name) { if (name[0] == ':') fname = name; else fname = ap_runtime_dir_relative(pool, name); } else return APR_ENOSHMAVAIL; /* first try to attach to existing slotmem */ while (next) { if (strcmp(next->name, fname) == 0) { /* we already have it */ *new = next; *item_size = next->size; *item_num = next->num; return APR_SUCCESS; } next = next->next; } return APR_ENOSHMAVAIL; } static apr_status_t slotmem_dptr(ap_slotmem_instance_t *score, unsigned int id, void **mem) { char *ptr; if (!score) return APR_ENOSHMAVAIL; if (id >= score->num) return APR_EINVAL; ptr = (char *)score->base + score->size * id; if (!ptr) return APR_ENOSHMAVAIL; *mem = ptr; return APR_SUCCESS; } static apr_status_t slotmem_get(ap_slotmem_instance_t *slot, unsigned int id, unsigned char *dest, apr_size_t dest_len) { void *ptr; char *inuse; apr_status_t ret; if (!slot) { return APR_ENOSHMAVAIL; } inuse = slot->inuse + id; if (id >= slot->num) { return APR_EINVAL; } if (AP_SLOTMEM_IS_PREGRAB(slot) && !*inuse) { return APR_NOTFOUND; } ret = slotmem_dptr(slot, id, &ptr); if (ret != APR_SUCCESS) { return ret; } *inuse=1; memcpy(dest, ptr, dest_len); /* bounds check? */ return APR_SUCCESS; } static apr_status_t slotmem_put(ap_slotmem_instance_t *slot, unsigned int id, unsigned char *src, apr_size_t src_len) { void *ptr; char *inuse; apr_status_t ret; if (!slot) { return APR_ENOSHMAVAIL; } inuse = slot->inuse + id; if (id >= slot->num) { return APR_EINVAL; } if (AP_SLOTMEM_IS_PREGRAB(slot) && !*inuse) { return APR_NOTFOUND; } ret = slotmem_dptr(slot, id, &ptr); if (ret != APR_SUCCESS) { return ret; } *inuse=1; memcpy(ptr, src, src_len); /* bounds check? */ return APR_SUCCESS; } static unsigned int slotmem_num_slots(ap_slotmem_instance_t *slot) { return slot->num; } static unsigned int slotmem_num_free_slots(ap_slotmem_instance_t *slot) { unsigned int i, counter=0; char *inuse = slot->inuse; for (i = 0; i < slot->num; i++, inuse++) { if (!*inuse) counter++; } return counter; } static apr_size_t slotmem_slot_size(ap_slotmem_instance_t *slot) { return slot->size; } /* * XXXX: if !AP_SLOTMEM_IS_PREGRAB, then still worry about * inuse for grab and return? */ static apr_status_t slotmem_grab(ap_slotmem_instance_t *slot, unsigned int *id) { unsigned int i; char *inuse; if (!slot) { return APR_ENOSHMAVAIL; } inuse = slot->inuse; for (i = 0; i < slot->num; i++, inuse++) { if (!*inuse) { break; } } if (i >= slot->num) { return APR_EINVAL; } *inuse = 1; *id = i; return APR_SUCCESS; } static apr_status_t slotmem_fgrab(ap_slotmem_instance_t *slot, unsigned int id) { char *inuse; if (!slot) { return APR_ENOSHMAVAIL; } if (id >= slot->num) { return APR_EINVAL; } inuse = slot->inuse + id; *inuse = 1; return APR_SUCCESS; } static apr_status_t slotmem_release(ap_slotmem_instance_t *slot, unsigned int id) { char *inuse; if (!slot) { return APR_ENOSHMAVAIL; } inuse = slot->inuse; if (id >= slot->num) { return APR_EINVAL; } if (!inuse[id] ) { return APR_NOTFOUND; } inuse[id] = 0; return APR_SUCCESS; } static const ap_slotmem_provider_t storage = { "plainmem", &slotmem_do, &slotmem_create, &slotmem_attach, &slotmem_dptr, &slotmem_get, &slotmem_put, &slotmem_num_slots, &slotmem_num_free_slots, &slotmem_slot_size, &slotmem_grab, &slotmem_release, &slotmem_fgrab }; static int pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp) { gpool = p; return OK; } static void ap_slotmem_plain_register_hook(apr_pool_t *p) { /* XXX: static const char * const prePos[] = { "mod_slotmem.c", NULL }; */ ap_register_provider(p, AP_SLOTMEM_PROVIDER_GROUP, "plain", AP_SLOTMEM_PROVIDER_VERSION, &storage); ap_hook_pre_config(pre_config, NULL, NULL, APR_HOOK_MIDDLE); } AP_DECLARE_MODULE(slotmem_plain) = { STANDARD20_MODULE_STUFF, NULL, /* create per-directory config structure */ NULL, /* merge per-directory config structures */ NULL, /* create per-server config structure */ NULL, /* merge per-server config structures */ NULL, /* command apr_table_t */ ap_slotmem_plain_register_hook /* register hooks */ };