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 plain memory divided in slot. 18 * This one uses plain memory. 19 */ 20 21#include "ap_slotmem.h" 22 23#define AP_SLOTMEM_IS_PREGRAB(t) (t->type & AP_SLOTMEM_TYPE_PREGRAB) 24 25struct ap_slotmem_instance_t { 26 char *name; /* per segment name */ 27 void *base; /* data set start */ 28 apr_size_t size; /* size of each memory slot */ 29 unsigned int num; /* number of mem slots */ 30 apr_pool_t *gpool; /* per segment global pool */ 31 char *inuse; /* in-use flag table*/ 32 ap_slotmem_type_t type; /* type-specific flags */ 33 struct ap_slotmem_instance_t *next; /* location of next allocated segment */ 34}; 35 36 37/* global pool and list of slotmem we are handling */ 38static struct ap_slotmem_instance_t *globallistmem = NULL; 39static apr_pool_t *gpool = NULL; 40 41static apr_status_t slotmem_do(ap_slotmem_instance_t *mem, ap_slotmem_callback_fn_t *func, void *data, apr_pool_t *pool) 42{ 43 unsigned int i; 44 char *ptr; 45 char *inuse; 46 apr_status_t retval = APR_SUCCESS; 47 48 49 if (!mem) 50 return APR_ENOSHMAVAIL; 51 52 ptr = (char *)mem->base; 53 inuse = mem->inuse; 54 for (i = 0; i < mem->num; i++, inuse++) { 55 if (!AP_SLOTMEM_IS_PREGRAB(mem) || 56 (AP_SLOTMEM_IS_PREGRAB(mem) && *inuse)) { 57 retval = func((void *) ptr, data, pool); 58 if (retval != APR_SUCCESS) 59 break; 60 } 61 ptr += mem->size; 62 } 63 return retval; 64} 65 66static 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) 67{ 68 ap_slotmem_instance_t *res; 69 ap_slotmem_instance_t *next = globallistmem; 70 apr_size_t basesize = (item_size * item_num); 71 72 const char *fname; 73 74 if (name) { 75 if (name[0] == ':') 76 fname = name; 77 else 78 fname = ap_runtime_dir_relative(pool, name); 79 80 /* first try to attach to existing slotmem */ 81 if (next) { 82 for (;;) { 83 if (strcmp(next->name, fname) == 0) { 84 /* we already have it */ 85 *new = next; 86 return APR_SUCCESS; 87 } 88 if (!next->next) { 89 break; 90 } 91 next = next->next; 92 } 93 } 94 } 95 else 96 fname = "anonymous"; 97 98 /* create the memory using the gpool */ 99 res = (ap_slotmem_instance_t *) apr_pcalloc(gpool, sizeof(ap_slotmem_instance_t)); 100 res->base = apr_pcalloc(gpool, basesize + (item_num * sizeof(char))); 101 if (!res->base) 102 return APR_ENOSHMAVAIL; 103 104 /* For the chained slotmem stuff */ 105 res->name = apr_pstrdup(gpool, fname); 106 res->size = item_size; 107 res->num = item_num; 108 res->next = NULL; 109 res->type = type; 110 res->inuse = (char *)res->base + basesize; 111 if (globallistmem == NULL) 112 globallistmem = res; 113 else 114 next->next = res; 115 116 *new = res; 117 return APR_SUCCESS; 118} 119 120static 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) 121{ 122 ap_slotmem_instance_t *next = globallistmem; 123 const char *fname; 124 125 if (name) { 126 if (name[0] == ':') 127 fname = name; 128 else 129 fname = ap_runtime_dir_relative(pool, name); 130 } 131 else 132 return APR_ENOSHMAVAIL; 133 134 /* first try to attach to existing slotmem */ 135 while (next) { 136 if (strcmp(next->name, fname) == 0) { 137 /* we already have it */ 138 *new = next; 139 *item_size = next->size; 140 *item_num = next->num; 141 return APR_SUCCESS; 142 } 143 next = next->next; 144 } 145 146 return APR_ENOSHMAVAIL; 147} 148 149static apr_status_t slotmem_dptr(ap_slotmem_instance_t *score, unsigned int id, void **mem) 150{ 151 152 char *ptr; 153 154 if (!score) 155 return APR_ENOSHMAVAIL; 156 if (id >= score->num) 157 return APR_EINVAL; 158 159 ptr = (char *)score->base + score->size * id; 160 if (!ptr) 161 return APR_ENOSHMAVAIL; 162 *mem = ptr; 163 return APR_SUCCESS; 164} 165 166static apr_status_t slotmem_get(ap_slotmem_instance_t *slot, unsigned int id, unsigned char *dest, apr_size_t dest_len) 167{ 168 void *ptr; 169 char *inuse; 170 apr_status_t ret; 171 172 if (!slot) { 173 return APR_ENOSHMAVAIL; 174 } 175 176 inuse = slot->inuse + id; 177 if (id >= slot->num) { 178 return APR_EINVAL; 179 } 180 if (AP_SLOTMEM_IS_PREGRAB(slot) && !*inuse) { 181 return APR_NOTFOUND; 182 } 183 ret = slotmem_dptr(slot, id, &ptr); 184 if (ret != APR_SUCCESS) { 185 return ret; 186 } 187 *inuse=1; 188 memcpy(dest, ptr, dest_len); /* bounds check? */ 189 return APR_SUCCESS; 190} 191 192static apr_status_t slotmem_put(ap_slotmem_instance_t *slot, unsigned int id, unsigned char *src, apr_size_t src_len) 193{ 194 void *ptr; 195 char *inuse; 196 apr_status_t ret; 197 198 if (!slot) { 199 return APR_ENOSHMAVAIL; 200 } 201 202 inuse = slot->inuse + id; 203 if (id >= slot->num) { 204 return APR_EINVAL; 205 } 206 if (AP_SLOTMEM_IS_PREGRAB(slot) && !*inuse) { 207 return APR_NOTFOUND; 208 } 209 ret = slotmem_dptr(slot, id, &ptr); 210 if (ret != APR_SUCCESS) { 211 return ret; 212 } 213 *inuse=1; 214 memcpy(ptr, src, src_len); /* bounds check? */ 215 return APR_SUCCESS; 216} 217 218static unsigned int slotmem_num_slots(ap_slotmem_instance_t *slot) 219{ 220 return slot->num; 221} 222 223static unsigned int slotmem_num_free_slots(ap_slotmem_instance_t *slot) 224{ 225 unsigned int i, counter=0; 226 char *inuse = slot->inuse; 227 for (i = 0; i < slot->num; i++, inuse++) { 228 if (!*inuse) 229 counter++; 230 } 231 return counter; 232} 233 234static apr_size_t slotmem_slot_size(ap_slotmem_instance_t *slot) 235{ 236 return slot->size; 237} 238 239/* 240 * XXXX: if !AP_SLOTMEM_IS_PREGRAB, then still worry about 241 * inuse for grab and return? 242 */ 243static apr_status_t slotmem_grab(ap_slotmem_instance_t *slot, unsigned int *id) 244{ 245 unsigned int i; 246 char *inuse; 247 248 if (!slot) { 249 return APR_ENOSHMAVAIL; 250 } 251 252 inuse = slot->inuse; 253 254 for (i = 0; i < slot->num; i++, inuse++) { 255 if (!*inuse) { 256 break; 257 } 258 } 259 if (i >= slot->num) { 260 return APR_EINVAL; 261 } 262 *inuse = 1; 263 *id = i; 264 return APR_SUCCESS; 265} 266 267static apr_status_t slotmem_fgrab(ap_slotmem_instance_t *slot, unsigned int id) 268{ 269 char *inuse; 270 271 if (!slot) { 272 return APR_ENOSHMAVAIL; 273 } 274 275 if (id >= slot->num) { 276 return APR_EINVAL; 277 } 278 inuse = slot->inuse + id; 279 *inuse = 1; 280 return APR_SUCCESS; 281} 282 283static apr_status_t slotmem_release(ap_slotmem_instance_t *slot, unsigned int id) 284{ 285 char *inuse; 286 287 if (!slot) { 288 return APR_ENOSHMAVAIL; 289 } 290 291 inuse = slot->inuse; 292 293 if (id >= slot->num) { 294 return APR_EINVAL; 295 } 296 if (!inuse[id] ) { 297 return APR_NOTFOUND; 298 } 299 inuse[id] = 0; 300 return APR_SUCCESS; 301} 302 303static const ap_slotmem_provider_t storage = { 304 "plainmem", 305 &slotmem_do, 306 &slotmem_create, 307 &slotmem_attach, 308 &slotmem_dptr, 309 &slotmem_get, 310 &slotmem_put, 311 &slotmem_num_slots, 312 &slotmem_num_free_slots, 313 &slotmem_slot_size, 314 &slotmem_grab, 315 &slotmem_release, 316 &slotmem_fgrab 317}; 318 319static int pre_config(apr_pool_t *p, apr_pool_t *plog, 320 apr_pool_t *ptemp) 321{ 322 gpool = p; 323 return OK; 324} 325 326static void ap_slotmem_plain_register_hook(apr_pool_t *p) 327{ 328 /* XXX: static const char * const prePos[] = { "mod_slotmem.c", NULL }; */ 329 ap_register_provider(p, AP_SLOTMEM_PROVIDER_GROUP, "plain", 330 AP_SLOTMEM_PROVIDER_VERSION, &storage); 331 ap_hook_pre_config(pre_config, NULL, NULL, APR_HOOK_MIDDLE); 332} 333 334AP_DECLARE_MODULE(slotmem_plain) = { 335 STANDARD20_MODULE_STUFF, 336 NULL, /* create per-directory config structure */ 337 NULL, /* merge per-directory config structures */ 338 NULL, /* create per-server config structure */ 339 NULL, /* merge per-server config structures */ 340 NULL, /* command apr_table_t */ 341 ap_slotmem_plain_register_hook /* register hooks */ 342}; 343 344