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 */ 51typedef 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 60struct 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 */ 82static struct ap_slotmem_instance_t *globallistmem = NULL; 83static 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 */ 90static 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 = { { 0 } }; 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 132static 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 156static 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 175static 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 unsigned char digest[APR_MD5_DIGESTSIZE]; 182 183 storename = slotmem_filename(slotmem->gpool, slotmem->name, 1); 184 185 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02334) 186 "storing %s", storename); 187 188 if (storename) { 189 rv = apr_file_open(&fp, storename, APR_CREATE | APR_READ | APR_WRITE, 190 APR_OS_DEFAULT, slotmem->gpool); 191 if (APR_STATUS_IS_EEXIST(rv)) { 192 apr_file_remove(storename, slotmem->gpool); 193 rv = apr_file_open(&fp, storename, APR_CREATE | APR_READ | APR_WRITE, 194 APR_OS_DEFAULT, slotmem->gpool); 195 } 196 if (rv != APR_SUCCESS) { 197 return; 198 } 199 if (AP_SLOTMEM_IS_CLEARINUSE(slotmem)) { 200 slotmem_clearinuse(slotmem); 201 } 202 nbytes = (slotmem->desc.size * slotmem->desc.num) + 203 (slotmem->desc.num * sizeof(char)) + AP_UNSIGNEDINT_OFFSET; 204 apr_md5(digest, slotmem->persist, nbytes); 205 rv = apr_file_write_full(fp, slotmem->persist, nbytes, NULL); 206 if (rv == APR_SUCCESS) { 207 rv = apr_file_write_full(fp, digest, APR_MD5_DIGESTSIZE, NULL); 208 } 209 apr_file_close(fp); 210 if (rv != APR_SUCCESS) { 211 apr_file_remove(storename, slotmem->gpool); 212 } 213 } 214} 215 216static apr_status_t restore_slotmem(void *ptr, const char *name, apr_size_t size, 217 apr_pool_t *pool) 218{ 219 const char *storename; 220 apr_file_t *fp; 221 apr_size_t nbytes = size; 222 apr_status_t rv = APR_SUCCESS; 223 unsigned char digest[APR_MD5_DIGESTSIZE]; 224 unsigned char digest2[APR_MD5_DIGESTSIZE]; 225 226 storename = slotmem_filename(pool, name, 1); 227 228 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02335) 229 "restoring %s", storename); 230 231 if (storename) { 232 rv = apr_file_open(&fp, storename, APR_READ | APR_WRITE, APR_OS_DEFAULT, 233 pool); 234 if (rv == APR_SUCCESS) { 235 rv = apr_file_read(fp, ptr, &nbytes); 236 if ((rv == APR_SUCCESS || rv == APR_EOF) && nbytes == size) { 237 rv = APR_SUCCESS; /* for successful return @ EOF */ 238 /* 239 * if at EOF, don't bother checking md5 240 * - backwards compatibility 241 * */ 242 if (apr_file_eof(fp) != APR_EOF) { 243 apr_size_t ds = APR_MD5_DIGESTSIZE; 244 rv = apr_file_read(fp, digest, &ds); 245 if ((rv == APR_SUCCESS || rv == APR_EOF) && 246 ds == APR_MD5_DIGESTSIZE) { 247 rv = APR_SUCCESS; 248 apr_md5(digest2, ptr, nbytes); 249 if (memcmp(digest, digest2, APR_MD5_DIGESTSIZE)) { 250 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 251 APLOGNO(02551) "bad md5 match"); 252 rv = APR_EGENERAL; 253 } 254 } 255 } 256 else { 257 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 258 APLOGNO(02552) "at EOF... bypassing md5 match check (old persist file?)"); 259 } 260 } 261 else if (nbytes != size) { 262 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 263 APLOGNO(02553) "Expected %" APR_SIZE_T_FMT ": Read %" APR_SIZE_T_FMT, 264 size, nbytes); 265 rv = APR_EGENERAL; 266 } 267 apr_file_close(fp); 268 } 269 } 270 return rv; 271} 272 273static apr_status_t cleanup_slotmem(void *param) 274{ 275 ap_slotmem_instance_t **mem = param; 276 277 if (*mem) { 278 ap_slotmem_instance_t *next = *mem; 279 while (next) { 280 if (AP_SLOTMEM_IS_PERSIST(next)) { 281 store_slotmem(next); 282 } 283 if (next->fbased) { 284 const char *name; 285 apr_shm_remove(next->name, next->gpool); 286 name = slotmem_filename(next->gpool, next->name, 0); 287 if (name) { 288 apr_file_remove(name, next->gpool); 289 } 290 } 291 apr_shm_destroy((apr_shm_t *)next->shm); 292 next = next->next; 293 } 294 } 295 /* apr_pool_destroy(gpool); */ 296 globallistmem = NULL; 297 return APR_SUCCESS; 298} 299 300static apr_status_t slotmem_doall(ap_slotmem_instance_t *mem, 301 ap_slotmem_callback_fn_t *func, 302 void *data, apr_pool_t *pool) 303{ 304 unsigned int i; 305 char *ptr; 306 char *inuse; 307 apr_status_t retval = APR_SUCCESS; 308 309 if (!mem) { 310 return APR_ENOSHMAVAIL; 311 } 312 313 ptr = (char *)mem->base; 314 inuse = mem->inuse; 315 for (i = 0; i < mem->desc.num; i++, inuse++) { 316 if (!AP_SLOTMEM_IS_PREGRAB(mem) || 317 (AP_SLOTMEM_IS_PREGRAB(mem) && *inuse)) { 318 retval = func((void *) ptr, data, pool); 319 if (retval != APR_SUCCESS) 320 break; 321 } 322 ptr += mem->desc.size; 323 } 324 return retval; 325} 326 327static apr_status_t slotmem_create(ap_slotmem_instance_t **new, 328 const char *name, apr_size_t item_size, 329 unsigned int item_num, 330 ap_slotmem_type_t type, apr_pool_t *pool) 331{ 332/* void *slotmem = NULL; */ 333 int fbased = 1; 334 int restored = 0; 335 char *ptr; 336 sharedslotdesc_t desc; 337 ap_slotmem_instance_t *res; 338 ap_slotmem_instance_t *next = globallistmem; 339 const char *fname; 340 apr_shm_t *shm; 341 apr_size_t basesize = (item_size * item_num); 342 apr_size_t size = AP_SLOTMEM_OFFSET + AP_UNSIGNEDINT_OFFSET + 343 (item_num * sizeof(char)) + basesize; 344 apr_status_t rv; 345 346 if (gpool == NULL) { 347 return APR_ENOSHMAVAIL; 348 } 349 fname = slotmem_filename(pool, name, 0); 350 if (fname) { 351 /* first try to attach to existing slotmem */ 352 if (next) { 353 for (;;) { 354 if (strcmp(next->name, fname) == 0) { 355 /* we already have it */ 356 *new = next; 357 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02603) 358 "create found %s in global list", fname); 359 return APR_SUCCESS; 360 } 361 if (!next->next) { 362 break; 363 } 364 next = next->next; 365 } 366 } 367 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02602) 368 "create didn't find %s in global list", fname); 369 } 370 else { 371 fbased = 0; 372 fname = "none"; 373 } 374 375 /* first try to attach to existing shared memory */ 376 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02300) 377 "create %s: %"APR_SIZE_T_FMT"/%u", fname, item_size, 378 item_num); 379 if (fbased) { 380 rv = apr_shm_attach(&shm, fname, gpool); 381 } 382 else { 383 rv = APR_EINVAL; 384 } 385 if (rv == APR_SUCCESS) { 386 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02598) 387 "apr_shm_attach() succeeded"); 388 389 /* check size */ 390 if (apr_shm_size_get(shm) != size) { 391 apr_shm_detach(shm); 392 ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, APLOGNO(02599) 393 "existing shared memory for %s could not be used (failed size check)", 394 fname); 395 return APR_EINVAL; 396 } 397 ptr = (char *)apr_shm_baseaddr_get(shm); 398 memcpy(&desc, ptr, sizeof(desc)); 399 if (desc.size != item_size || desc.num != item_num) { 400 apr_shm_detach(shm); 401 ap_log_error(APLOG_MARK, APLOG_ERR, 0, ap_server_conf, APLOGNO(02600) 402 "existing shared memory for %s could not be used (failed contents check)", 403 fname); 404 return APR_EINVAL; 405 } 406 ptr += AP_SLOTMEM_OFFSET; 407 } 408 else { 409 apr_size_t dsize = size - AP_SLOTMEM_OFFSET; 410 if (fbased) { 411 apr_shm_remove(fname, gpool); 412 rv = apr_shm_create(&shm, size, fname, gpool); 413 } 414 else { 415 rv = apr_shm_create(&shm, size, NULL, gpool); 416 } 417 ap_log_error(APLOG_MARK, rv == APR_SUCCESS ? APLOG_DEBUG : APLOG_ERR, 418 rv, ap_server_conf, APLOGNO(02611) 419 "create: apr_shm_create(%s) %s", 420 fname ? fname : "", 421 rv == APR_SUCCESS ? "succeeded" : "failed"); 422 if (rv != APR_SUCCESS) { 423 return rv; 424 } 425 if (fbased) { 426 /* Set permissions to shared memory 427 * so it can be attached by child process 428 * having different user credentials 429 * 430 * See apr:shmem/unix/shm.c 431 */ 432 unixd_set_shm_perms(fname); 433 } 434 ptr = (char *)apr_shm_baseaddr_get(shm); 435 desc.size = item_size; 436 desc.num = item_num; 437 desc.type = type; 438 memcpy(ptr, &desc, sizeof(desc)); 439 ptr += AP_SLOTMEM_OFFSET; 440 memset(ptr, 0, dsize); 441 /* 442 * TODO: Error check the below... What error makes 443 * sense if the restore fails? Any? 444 */ 445 if (type & AP_SLOTMEM_TYPE_PERSIST) { 446 rv = restore_slotmem(ptr, fname, dsize, pool); 447 if (rv == APR_SUCCESS) { 448 restored = 1; 449 } 450 else { 451 /* just in case, re-zero */ 452 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 453 APLOGNO(02554) "could not restore %s", fname); 454 memset(ptr, 0, dsize); 455 } 456 } 457 } 458 459 /* For the chained slotmem stuff */ 460 res = (ap_slotmem_instance_t *) apr_pcalloc(gpool, 461 sizeof(ap_slotmem_instance_t)); 462 res->name = apr_pstrdup(gpool, fname); 463 res->fbased = fbased; 464 res->shm = shm; 465 res->num_free = (unsigned int *)ptr; 466 if (!restored) { 467 *res->num_free = item_num; 468 } 469 res->persist = (void *)ptr; 470 ptr += AP_UNSIGNEDINT_OFFSET; 471 res->base = (void *)ptr; 472 res->desc = desc; 473 res->gpool = gpool; 474 res->next = NULL; 475 res->inuse = ptr + basesize; 476 if (globallistmem == NULL) { 477 globallistmem = res; 478 } 479 else { 480 next->next = res; 481 } 482 483 *new = res; 484 return APR_SUCCESS; 485} 486 487static apr_status_t slotmem_attach(ap_slotmem_instance_t **new, 488 const char *name, apr_size_t *item_size, 489 unsigned int *item_num, apr_pool_t *pool) 490{ 491/* void *slotmem = NULL; */ 492 char *ptr; 493 ap_slotmem_instance_t *res; 494 ap_slotmem_instance_t *next = globallistmem; 495 sharedslotdesc_t desc; 496 const char *fname; 497 apr_shm_t *shm; 498 apr_status_t rv; 499 500 if (gpool == NULL) { 501 return APR_ENOSHMAVAIL; 502 } 503 fname = slotmem_filename(pool, name, 0); 504 if (!fname) { 505 return APR_ENOSHMAVAIL; 506 } 507 508 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02301) 509 "attach looking for %s", fname); 510 511 /* first try to attach to existing slotmem */ 512 if (next) { 513 for (;;) { 514 if (strcmp(next->name, fname) == 0) { 515 /* we already have it */ 516 *new = next; 517 *item_size = next->desc.size; 518 *item_num = next->desc.num; 519 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 520 APLOGNO(02302) 521 "attach found %s: %"APR_SIZE_T_FMT"/%u", fname, 522 *item_size, *item_num); 523 return APR_SUCCESS; 524 } 525 if (!next->next) { 526 break; 527 } 528 next = next->next; 529 } 530 } 531 532 /* next try to attach to existing shared memory */ 533 rv = apr_shm_attach(&shm, fname, gpool); 534 if (rv != APR_SUCCESS) { 535 return rv; 536 } 537 538 /* Read the description of the slotmem */ 539 ptr = (char *)apr_shm_baseaddr_get(shm); 540 memcpy(&desc, ptr, sizeof(desc)); 541 ptr += AP_SLOTMEM_OFFSET; 542 543 /* For the chained slotmem stuff */ 544 res = (ap_slotmem_instance_t *) apr_pcalloc(gpool, 545 sizeof(ap_slotmem_instance_t)); 546 res->name = apr_pstrdup(gpool, fname); 547 res->fbased = 1; 548 res->shm = shm; 549 res->num_free = (unsigned int *)ptr; 550 res->persist = (void *)ptr; 551 ptr += AP_UNSIGNEDINT_OFFSET; 552 res->base = (void *)ptr; 553 res->desc = desc; 554 res->gpool = gpool; 555 res->inuse = ptr + (desc.size * desc.num); 556 res->next = NULL; 557 if (globallistmem == NULL) { 558 globallistmem = res; 559 } 560 else { 561 next->next = res; 562 } 563 564 *new = res; 565 *item_size = desc.size; 566 *item_num = desc.num; 567 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, 568 APLOGNO(02303) 569 "attach found %s: %"APR_SIZE_T_FMT"/%u", fname, 570 *item_size, *item_num); 571 return APR_SUCCESS; 572} 573 574static apr_status_t slotmem_dptr(ap_slotmem_instance_t *slot, 575 unsigned int id, void **mem) 576{ 577 char *ptr; 578 579 if (!slot) { 580 return APR_ENOSHMAVAIL; 581 } 582 if (id >= slot->desc.num) { 583 return APR_EINVAL; 584 } 585 586 ptr = (char *)slot->base + slot->desc.size * id; 587 if (!ptr) { 588 return APR_ENOSHMAVAIL; 589 } 590 *mem = (void *)ptr; 591 return APR_SUCCESS; 592} 593 594static apr_status_t slotmem_get(ap_slotmem_instance_t *slot, unsigned int id, 595 unsigned char *dest, apr_size_t dest_len) 596{ 597 void *ptr; 598 char *inuse; 599 apr_status_t ret; 600 601 if (!slot) { 602 return APR_ENOSHMAVAIL; 603 } 604 605 inuse = slot->inuse + id; 606 if (id >= slot->desc.num) { 607 return APR_EINVAL; 608 } 609 if (AP_SLOTMEM_IS_PREGRAB(slot) && !*inuse) { 610 return APR_NOTFOUND; 611 } 612 ret = slotmem_dptr(slot, id, &ptr); 613 if (ret != APR_SUCCESS) { 614 return ret; 615 } 616 *inuse = 1; 617 memcpy(dest, ptr, dest_len); /* bounds check? */ 618 return APR_SUCCESS; 619} 620 621static apr_status_t slotmem_put(ap_slotmem_instance_t *slot, unsigned int id, 622 unsigned char *src, apr_size_t src_len) 623{ 624 void *ptr; 625 char *inuse; 626 apr_status_t ret; 627 628 if (!slot) { 629 return APR_ENOSHMAVAIL; 630 } 631 632 inuse = slot->inuse + id; 633 if (id >= slot->desc.num) { 634 return APR_EINVAL; 635 } 636 if (AP_SLOTMEM_IS_PREGRAB(slot) && !*inuse) { 637 return APR_NOTFOUND; 638 } 639 ret = slotmem_dptr(slot, id, &ptr); 640 if (ret != APR_SUCCESS) { 641 return ret; 642 } 643 *inuse=1; 644 memcpy(ptr, src, src_len); /* bounds check? */ 645 return APR_SUCCESS; 646} 647 648static unsigned int slotmem_num_slots(ap_slotmem_instance_t *slot) 649{ 650 return slot->desc.num; 651} 652 653static unsigned int slotmem_num_free_slots(ap_slotmem_instance_t *slot) 654{ 655 if (AP_SLOTMEM_IS_PREGRAB(slot)) 656 return *slot->num_free; 657 else { 658 unsigned int i, counter=0; 659 char *inuse = slot->inuse; 660 for (i=0; i<slot->desc.num; i++, inuse++) { 661 if (!*inuse) 662 counter++; 663 } 664 return counter; 665 } 666} 667 668static apr_size_t slotmem_slot_size(ap_slotmem_instance_t *slot) 669{ 670 return slot->desc.size; 671} 672 673static apr_status_t slotmem_grab(ap_slotmem_instance_t *slot, unsigned int *id) 674{ 675 unsigned int i; 676 char *inuse; 677 678 if (!slot) { 679 return APR_ENOSHMAVAIL; 680 } 681 682 inuse = slot->inuse; 683 684 for (i = 0; i < slot->desc.num; i++, inuse++) { 685 if (!*inuse) { 686 break; 687 } 688 } 689 if (i >= slot->desc.num) { 690 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02293) 691 "slotmem(%s) grab failed. Num %u/num_free %u", 692 slot->name, slotmem_num_slots(slot), 693 slotmem_num_free_slots(slot)); 694 return APR_EINVAL; 695 } 696 *inuse = 1; 697 *id = i; 698 (*slot->num_free)--; 699 return APR_SUCCESS; 700} 701 702static apr_status_t slotmem_fgrab(ap_slotmem_instance_t *slot, unsigned int id) 703{ 704 char *inuse; 705 706 if (!slot) { 707 return APR_ENOSHMAVAIL; 708 } 709 710 if (id >= slot->desc.num) { 711 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02397) 712 "slotmem(%s) fgrab failed. Num %u/num_free %u", 713 slot->name, slotmem_num_slots(slot), 714 slotmem_num_free_slots(slot)); 715 return APR_EINVAL; 716 } 717 inuse = slot->inuse + id; 718 719 if (!*inuse) { 720 *inuse = 1; 721 (*slot->num_free)--; 722 } 723 return APR_SUCCESS; 724} 725 726static apr_status_t slotmem_release(ap_slotmem_instance_t *slot, 727 unsigned int id) 728{ 729 char *inuse; 730 731 if (!slot) { 732 return APR_ENOSHMAVAIL; 733 } 734 735 inuse = slot->inuse; 736 737 if (id >= slot->desc.num || !inuse[id] ) { 738 ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf, APLOGNO(02294) 739 "slotmem(%s) release failed. Num %u/inuse[%u] %d", 740 slot->name, slotmem_num_slots(slot), 741 id, (int)inuse[id]); 742 if (id >= slot->desc.num) { 743 return APR_EINVAL; 744 } else { 745 return APR_NOTFOUND; 746 } 747 } 748 inuse[id] = 0; 749 (*slot->num_free)++; 750 return APR_SUCCESS; 751} 752 753static const ap_slotmem_provider_t storage = { 754 "sharedmem", 755 &slotmem_doall, 756 &slotmem_create, 757 &slotmem_attach, 758 &slotmem_dptr, 759 &slotmem_get, 760 &slotmem_put, 761 &slotmem_num_slots, 762 &slotmem_num_free_slots, 763 &slotmem_slot_size, 764 &slotmem_grab, 765 &slotmem_release, 766 &slotmem_fgrab 767}; 768 769/* make the storage usuable from outside */ 770static const ap_slotmem_provider_t *slotmem_shm_getstorage(void) 771{ 772 return (&storage); 773} 774 775/* initialise the global pool */ 776static void slotmem_shm_initgpool(apr_pool_t *p) 777{ 778 gpool = p; 779} 780 781/* Add the pool_clean routine */ 782static void slotmem_shm_initialize_cleanup(apr_pool_t *p) 783{ 784 apr_pool_cleanup_register(p, &globallistmem, cleanup_slotmem, 785 apr_pool_cleanup_null); 786} 787 788/* 789 * Make sure the shared memory is cleaned 790 */ 791static int post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, 792 server_rec *s) 793{ 794 slotmem_shm_initialize_cleanup(p); 795 return OK; 796} 797 798static int pre_config(apr_pool_t *p, apr_pool_t *plog, 799 apr_pool_t *ptemp) 800{ 801 slotmem_shm_initgpool(p); 802 return OK; 803} 804 805static void ap_slotmem_shm_register_hook(apr_pool_t *p) 806{ 807 const ap_slotmem_provider_t *storage = slotmem_shm_getstorage(); 808 ap_register_provider(p, AP_SLOTMEM_PROVIDER_GROUP, "shm", 809 AP_SLOTMEM_PROVIDER_VERSION, storage); 810 ap_hook_post_config(post_config, NULL, NULL, APR_HOOK_LAST); 811 ap_hook_pre_config(pre_config, NULL, NULL, APR_HOOK_MIDDLE); 812} 813 814AP_DECLARE_MODULE(slotmem_shm) = { 815 STANDARD20_MODULE_STUFF, 816 NULL, /* create per-directory config structure */ 817 NULL, /* merge per-directory config structures */ 818 NULL, /* create per-server config structure */ 819 NULL, /* merge per-server config structures */ 820 NULL, /* command apr_table_t */ 821 ap_slotmem_shm_register_hook /* register hooks */ 822}; 823