1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include "config.h" 29 30 #include <stdio.h> 31 #include <fcntl.h> 32 #include <sys/mman.h> 33 #include <sys/ipc.h> 34 #include <sys/sem.h> 35 #include <sys/errno.h> 36 #include <signal.h> 37 #include <pthread.h> 38 #include <sys/shm.h> 39 #include "filebench.h" 40 41 /* IPC Hub and Simple memory allocator */ 42 43 static int shmfd; 44 filebench_shm_t *filebench_shm = NULL; 45 static pthread_mutexattr_t *mutexattr = NULL; 46 47 /* 48 * Interprocess Communication mechanisms. If multiple processes 49 * are used, filebench opens a shared file in memory mapped mode to hold 50 * a variety of global variables and data structures. If only using 51 * multiple threads, it just allocates a region of local memory. A 52 * region of interprocess shared memory and a set of shared semaphores 53 * are also created. Routines are provided to manage the creation, 54 * destruction, and allocation of these resoures. 55 */ 56 57 58 /* 59 * Locks a mutex and logs any errors. 60 */ 61 int 62 ipc_mutex_lock(pthread_mutex_t *mutex) 63 { 64 int error; 65 66 error = pthread_mutex_lock(mutex); 67 68 #ifdef HAVE_ROBUST_MUTEX 69 if (error == EOWNERDEAD) { 70 if (pthread_mutex_consistent_np(mutex) != 0) { 71 filebench_log(LOG_FATAL, "mutex make consistent " 72 "failed: %s", strerror(error)); 73 return (-1); 74 } 75 return (0); 76 } 77 #endif /* HAVE_ROBUST_MUTEX */ 78 79 if (error != 0) { 80 filebench_log(LOG_FATAL, "mutex lock failed: %s", 81 strerror(error)); 82 } 83 84 return (error); 85 } 86 87 /* 88 * Unlocks a mutex and logs any errors. 89 */ 90 int 91 ipc_mutex_unlock(pthread_mutex_t *mutex) 92 { 93 int error; 94 95 error = pthread_mutex_unlock(mutex); 96 97 #ifdef HAVE_ROBUST_MUTEX 98 if (error == EOWNERDEAD) { 99 if (pthread_mutex_consistent_np(mutex) != 0) { 100 filebench_log(LOG_FATAL, "mutex make consistent " 101 "failed: %s", strerror(error)); 102 return (-1); 103 } 104 return (0); 105 } 106 #endif /* HAVE_ROBUST_MUTEX */ 107 108 if (error != 0) { 109 filebench_log(LOG_FATAL, "mutex unlock failed: %s", 110 strerror(error)); 111 } 112 113 return (error); 114 } 115 116 /* 117 * On first invocation, allocates a mutex attributes structure 118 * and initializes it with appropriate attributes. In all cases, 119 * returns a pointer to the structure. 120 */ 121 pthread_mutexattr_t * 122 ipc_mutexattr(void) 123 { 124 #ifdef USE_PROCESS_MODEL 125 if (mutexattr == NULL) { 126 if ((mutexattr = 127 malloc(sizeof (pthread_mutexattr_t))) == NULL) { 128 filebench_log(LOG_ERROR, "cannot alloc mutex attr"); 129 filebench_shutdown(1); 130 } 131 #ifdef HAVE_PROCSCOPE_PTHREADS 132 (void) pthread_mutexattr_init(mutexattr); 133 if (pthread_mutexattr_setpshared(mutexattr, 134 PTHREAD_PROCESS_SHARED) != 0) { 135 filebench_log(LOG_ERROR, "cannot set mutex attr " 136 "PROCESS_SHARED on this platform"); 137 filebench_shutdown(1); 138 } 139 #ifdef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL 140 if (pthread_mutexattr_setprotocol(mutexattr, 141 PTHREAD_PRIO_INHERIT) != 0) { 142 filebench_log(LOG_ERROR, "cannot set mutex attr " 143 "PTHREAD_PRIO_INHERIT on this platform"); 144 filebench_shutdown(1); 145 } 146 #endif /* HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL */ 147 #endif /* HAVE_PROCSCOPE_PTHREADS */ 148 #ifdef HAVE_ROBUST_MUTEX 149 if (pthread_mutexattr_setrobust_np(mutexattr, 150 PTHREAD_MUTEX_ROBUST_NP) != 0) { 151 filebench_log(LOG_ERROR, "cannot set mutex attr " 152 "PTHREAD_MUTEX_ROBUST_NP on this platform"); 153 filebench_shutdown(1); 154 } 155 if (pthread_mutexattr_settype(mutexattr, 156 PTHREAD_MUTEX_ERRORCHECK) != 0) { 157 filebench_log(LOG_ERROR, "cannot set mutex attr " 158 "PTHREAD_MUTEX_ERRORCHECK on this platform"); 159 filebench_shutdown(1); 160 } 161 #endif /* HAVE_ROBUST_MUTEX */ 162 163 } 164 #endif /* USE_PROCESS_MODEL */ 165 return (mutexattr); 166 } 167 168 static pthread_condattr_t *condattr = NULL; 169 170 /* 171 * On first invocation, allocates a condition variable attributes 172 * structure and initializes it with appropriate attributes. In 173 * all cases, returns a pointer to the structure. 174 */ 175 pthread_condattr_t * 176 ipc_condattr(void) 177 { 178 #ifdef USE_PROCESS_MODEL 179 if (condattr == NULL) { 180 if ((condattr = malloc(sizeof (pthread_condattr_t))) == NULL) { 181 filebench_log(LOG_ERROR, "cannot alloc cond attr"); 182 filebench_shutdown(1); 183 } 184 #ifdef HAVE_PROCSCOPE_PTHREADS 185 (void) pthread_condattr_init(condattr); 186 if (pthread_condattr_setpshared(condattr, 187 PTHREAD_PROCESS_SHARED) != 0) { 188 filebench_log(LOG_ERROR, 189 "cannot set cond attr PROCESS_SHARED"); 190 filebench_shutdown(1); 191 } 192 #endif /* HAVE_PROCSCOPE_PTHREADS */ 193 } 194 #endif /* USE_PROCESS_MODEL */ 195 return (condattr); 196 } 197 198 static pthread_rwlockattr_t *rwlockattr = NULL; 199 200 /* 201 * On first invocation, allocates a readers/writers attributes 202 * structure and initializes it with appropriate attributes. 203 * In all cases, returns a pointer to the structure. 204 */ 205 static pthread_rwlockattr_t * 206 ipc_rwlockattr(void) 207 { 208 #ifdef USE_PROCESS_MODEL 209 if (rwlockattr == NULL) { 210 if ((rwlockattr = 211 malloc(sizeof (pthread_rwlockattr_t))) == NULL) { 212 filebench_log(LOG_ERROR, "cannot alloc rwlock attr"); 213 filebench_shutdown(1); 214 } 215 #ifdef HAVE_PROCSCOPE_PTHREADS 216 (void) pthread_rwlockattr_init(rwlockattr); 217 if (pthread_rwlockattr_setpshared(rwlockattr, 218 PTHREAD_PROCESS_SHARED) != 0) { 219 filebench_log(LOG_ERROR, 220 "cannot set rwlock attr PROCESS_SHARED"); 221 filebench_shutdown(1); 222 } 223 #endif /* HAVE_PROCSCOPE_PTHREADS */ 224 } 225 #endif /* USE_PROCESS_MODEL */ 226 return (rwlockattr); 227 } 228 229 char *shmpath = NULL; 230 231 /* 232 * Calls semget() to get a set of shared system V semaphores. 233 */ 234 void 235 ipc_seminit(void) 236 { 237 key_t key = filebench_shm->semkey; 238 239 /* Already done? */ 240 if (filebench_shm->seminit) 241 return; 242 243 if ((semget(key, FILEBENCH_NSEMS, IPC_CREAT | 244 S_IRUSR | S_IWUSR)) == -1) { 245 filebench_log(LOG_ERROR, 246 "could not create sysv semaphore set " 247 "(need to increase sems?): %s", 248 strerror(errno)); 249 exit(1); 250 } 251 } 252 253 /* 254 * Initialize the Interprocess Communication system and its 255 * associated shared memory structure. It first creates a 256 * temporary file using either the mkstemp() function or the 257 * tempnam() and open() functions. If the process model is in 258 * use,it than sets the file large enough to hold the 259 * filebench_shm and an additional Megabyte. The file is then 260 * memory mapped. If the process model is not in use, it simply 261 * mallocs a region of sizeof (filebench_shm_t). 262 * 263 * Once the shared memory region / file is created, ipc_init 264 * initializes various locks pointers, and variables in the 265 * shared memory. It also uses ftok() to get a shared memory 266 * semaphore key for later use in allocating shared semaphores. 267 */ 268 void 269 ipc_init(void) 270 { 271 filebench_shm_t *buf = malloc(MB); 272 key_t key; 273 caddr_t c1; 274 caddr_t c2; 275 #ifdef HAVE_SEM_RMID 276 int semid; 277 #endif 278 279 #ifdef HAVE_MKSTEMP 280 shmpath = (char *)malloc(128); 281 (void) strcpy(shmpath, "/var/tmp/fbenchXXXXXX"); 282 shmfd = mkstemp(shmpath); 283 #else 284 shmfd = open(shmpath, O_CREAT | O_RDWR | O_TRUNC, 0666); 285 shmpath = tempnam("/var/tmp", "fbench"); 286 #endif /* HAVE_MKSTEMP */ 287 288 #ifdef USE_PROCESS_MODEL 289 290 if (shmfd < 0) { 291 filebench_log(LOG_FATAL, "Cannot open shm %s: %s", 292 shmpath, 293 strerror(errno)); 294 exit(1); 295 } 296 297 (void) lseek(shmfd, sizeof (filebench_shm_t), SEEK_SET); 298 if (write(shmfd, buf, MB) != MB) { 299 filebench_log(LOG_FATAL, 300 "Cannot allocate shm: %s", strerror(errno)); 301 exit(1); 302 } 303 304 /* LINTED E_BAD_PTR_CAST_ALIGN */ 305 if ((filebench_shm = (filebench_shm_t *)mmap((caddr_t)0, 306 sizeof (filebench_shm_t), PROT_READ | PROT_WRITE, 307 MAP_SHARED, shmfd, 0)) == NULL) { 308 filebench_log(LOG_FATAL, "Cannot mmap shm"); 309 exit(1); 310 } 311 312 #else 313 if ((filebench_shm = 314 (filebench_shm_t *)malloc(sizeof (filebench_shm_t))) == NULL) { 315 filebench_log(LOG_FATAL, "Cannot malloc shm"); 316 exit(1); 317 } 318 #endif /* USE_PROCESS_MODEL */ 319 320 c1 = (caddr_t)filebench_shm; 321 c2 = (caddr_t)&filebench_shm->marker; 322 323 (void) memset(filebench_shm, 0, c2 - c1); 324 filebench_shm->epoch = gethrtime(); 325 filebench_shm->debug_level = LOG_VERBOSE; 326 filebench_shm->shm_rmode = FILEBENCH_MODE_TIMEOUT; 327 filebench_shm->string_ptr = &filebench_shm->strings[0]; 328 filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr; 329 filebench_shm->path_ptr = &filebench_shm->filesetpaths[0]; 330 331 /* Setup mutexes for object lists */ 332 (void) pthread_mutex_init(&filebench_shm->fileset_lock, 333 ipc_mutexattr()); 334 (void) pthread_mutex_init(&filebench_shm->procflow_lock, 335 ipc_mutexattr()); 336 (void) pthread_mutex_init(&filebench_shm->threadflow_lock, 337 ipc_mutexattr()); 338 (void) pthread_mutex_init(&filebench_shm->flowop_lock, ipc_mutexattr()); 339 (void) pthread_mutex_init(&filebench_shm->msg_lock, ipc_mutexattr()); 340 (void) pthread_mutex_init(&filebench_shm->eventgen_lock, 341 ipc_mutexattr()); 342 (void) pthread_mutex_init(&filebench_shm->malloc_lock, ipc_mutexattr()); 343 (void) pthread_mutex_init(&filebench_shm->ism_lock, ipc_mutexattr()); 344 (void) pthread_cond_init(&filebench_shm->eventgen_cv, ipc_condattr()); 345 (void) pthread_rwlock_init(&filebench_shm->flowop_find_lock, 346 ipc_rwlockattr()); 347 (void) pthread_rwlock_init(&filebench_shm->run_lock, ipc_rwlockattr()); 348 (void) pthread_rwlock_rdlock(&filebench_shm->run_lock); 349 350 (void) ipc_mutex_lock(&filebench_shm->ism_lock); 351 352 /* Create semaphore */ 353 if ((key = ftok(shmpath, 1)) < 0) { 354 filebench_log(LOG_ERROR, "cannot create sem: %s", 355 strerror(errno)); 356 exit(1); 357 } 358 359 #ifdef HAVE_SEM_RMID 360 if ((semid = semget(key, 0, 0)) != -1) 361 (void) semctl(semid, 0, IPC_RMID); 362 #endif 363 364 filebench_shm->semkey = key; 365 filebench_shm->log_fd = -1; 366 filebench_shm->dump_fd = -1; 367 filebench_shm->eventgen_hz = 0; 368 filebench_shm->shm_id = -1; 369 370 free(buf); 371 } 372 373 /* 374 * If compiled to use process model, just unlinks the shmpath. 375 * Otherwise a no-op. 376 */ 377 void 378 ipc_cleanup(void) 379 { 380 #ifdef USE_PROCESS_MODEL 381 (void) unlink(shmpath); 382 #endif /* USE_PROCESS_MODEL */ 383 } 384 385 /* 386 * Attach to shared memory. Used by worker processes to open 387 * and mmap the shared memory region. If successful, it 388 * initializes the worker process' filebench_shm to point to 389 * the region and returns 0. Otherwise it returns -1. 390 */ 391 int 392 ipc_attach(caddr_t shmaddr) 393 { 394 if ((shmfd = open(shmpath, O_RDWR, 0666)) < 0) { 395 filebench_log(LOG_ERROR, "Cannot open shm"); 396 return (-1); 397 } 398 399 /* LINTED E_BAD_PTR_CAST_ALIGN */ 400 if ((filebench_shm = (filebench_shm_t *)mmap(shmaddr, 401 sizeof (filebench_shm_t), PROT_READ | PROT_WRITE, 402 MAP_SHARED | MAP_FIXED, shmfd, 0)) == NULL) { 403 filebench_log(LOG_ERROR, "Cannot mmap shm"); 404 return (-1); 405 } 406 407 filebench_log(LOG_DEBUG_IMPL, "addr = %zx", filebench_shm); 408 409 return (0); 410 } 411 412 static int filebench_sizes[] = { 413 FILEBENCH_NPROCFLOWS, /* number of procflows */ 414 FILEBENCH_NTHREADFLOWS, /* number of threadflows */ 415 FILEBENCH_NFLOWOPS, /* number of flowops */ 416 (FILEBENCH_NVARS * 2), /* number of attribute value dscrs */ 417 FILEBENCH_NVARS, /* number of variables */ 418 FILEBENCH_NFILESETS, /* number of filesets */ 419 FILEBENCH_NFILESETENTRIES, /* number of fileset entries */ 420 FILEBENCH_NRANDDISTS}; /* number of random distributions */ 421 422 /* 423 * Allocates filebench objects from pre allocated region of 424 * shareable memory. The memory region is partitioned into sets 425 * of objects during initialization. This routine scans for 426 * the first unallocated object of type "type" in the set of 427 * available objects, and makes it as allocated. The routine 428 * returns a pointer to the object, or NULL if all objects have 429 * been allocated. 430 */ 431 void * 432 ipc_malloc(int type) 433 { 434 int i; 435 int max = filebench_sizes[type]; 436 437 (void) ipc_mutex_lock(&filebench_shm->malloc_lock); 438 439 for (i = 0; i < max; i++) { 440 if (filebench_shm->bitmap[type][i] == 0) 441 break; 442 } 443 444 if (i >= max) { 445 filebench_log(LOG_ERROR, "Out of shared memory (%d)!", type); 446 (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); 447 return (NULL); 448 } 449 450 filebench_shm->bitmap[type][i] = 1; 451 452 switch (type) { 453 case FILEBENCH_FILESET: 454 (void) memset((char *)&filebench_shm->fileset[i], 0, 455 sizeof (fileset_t)); 456 (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); 457 return ((char *)&filebench_shm->fileset[i]); 458 459 case FILEBENCH_FILESETENTRY: 460 (void) memset((char *)&filebench_shm->filesetentry[i], 0, 461 sizeof (filesetentry_t)); 462 (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); 463 return ((char *)&filebench_shm->filesetentry[i]); 464 465 case FILEBENCH_PROCFLOW: 466 (void) memset((char *)&filebench_shm->procflow[i], 0, 467 sizeof (procflow_t)); 468 (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); 469 return ((char *)&filebench_shm->procflow[i]); 470 471 case FILEBENCH_THREADFLOW: 472 (void) memset((char *)&filebench_shm->threadflow[i], 0, 473 sizeof (threadflow_t)); 474 (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); 475 return ((char *)&filebench_shm->threadflow[i]); 476 477 case FILEBENCH_FLOWOP: 478 (void) memset((char *)&filebench_shm->flowop[i], 0, 479 sizeof (flowop_t)); 480 (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); 481 return ((char *)&filebench_shm->flowop[i]); 482 483 case FILEBENCH_AVD: 484 filebench_shm->shm_avd_ptrs[i].avd_type = AVD_INVALID; 485 filebench_shm->shm_avd_ptrs[i].avd_val.varptr = NULL; 486 (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); 487 return ((char *)&filebench_shm->shm_avd_ptrs[i]); 488 489 case FILEBENCH_VARIABLE: 490 (void) memset((char *)&filebench_shm->var[i], 0, 491 sizeof (var_t)); 492 (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); 493 return ((char *)&filebench_shm->var[i]); 494 495 case FILEBENCH_RANDDIST: 496 (void) memset((char *)&filebench_shm->shm_randdist[i], 0, 497 sizeof (randdist_t)); 498 (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); 499 return ((char *)&filebench_shm->shm_randdist[i]); 500 } 501 502 filebench_log(LOG_ERROR, "Attempt to ipc_malloc unknown type (%d)!", 503 type); 504 return (NULL); 505 } 506 507 /* 508 * Frees a filebench object of type "type" at the location 509 * pointed to by "addr". It uses the type and address to 510 * calculate which object is being freed, and clears its 511 * allocation map entry. 512 */ 513 void 514 ipc_free(int type, char *addr) 515 { 516 int item; 517 caddr_t base; 518 size_t offset; 519 size_t size; 520 521 if (addr == NULL) { 522 filebench_log(LOG_ERROR, "Freeing type %d %zx", type, addr); 523 return; 524 } 525 526 switch (type) { 527 528 case FILEBENCH_FILESET: 529 base = (caddr_t)&filebench_shm->fileset[0]; 530 size = sizeof (fileset_t); 531 break; 532 533 case FILEBENCH_FILESETENTRY: 534 base = (caddr_t)&filebench_shm->filesetentry[0]; 535 size = sizeof (filesetentry_t); 536 break; 537 538 case FILEBENCH_PROCFLOW: 539 base = (caddr_t)&filebench_shm->procflow[0]; 540 size = sizeof (procflow_t); 541 break; 542 543 case FILEBENCH_THREADFLOW: 544 base = (caddr_t)&filebench_shm->threadflow[0]; 545 size = sizeof (threadflow_t); 546 break; 547 548 case FILEBENCH_FLOWOP: 549 base = (caddr_t)&filebench_shm->flowop[0]; 550 size = sizeof (flowop_t); 551 break; 552 553 case FILEBENCH_AVD: 554 base = (caddr_t)&filebench_shm->shm_avd_ptrs[0]; 555 size = sizeof (avd_t); 556 break; 557 558 case FILEBENCH_VARIABLE: 559 base = (caddr_t)&filebench_shm->var[0]; 560 size = sizeof (var_t); 561 break; 562 563 case FILEBENCH_RANDDIST: 564 base = (caddr_t)&filebench_shm->shm_randdist[0]; 565 size = sizeof (randdist_t); 566 break; 567 } 568 569 offset = ((size_t)addr - (size_t)base); 570 item = offset / size; 571 572 (void) ipc_mutex_lock(&filebench_shm->malloc_lock); 573 filebench_shm->bitmap[type][item] = 0; 574 (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); 575 } 576 577 /* 578 * Allocate a string from filebench string memory. The length 579 * of the allocated string is the same as the length of the 580 * supplied string "string", and the contents of string are 581 * copied to the newly allocated string. 582 */ 583 char * 584 ipc_stralloc(char *string) 585 { 586 char *allocstr = filebench_shm->string_ptr; 587 588 filebench_shm->string_ptr += strlen(string) + 1; 589 590 if ((filebench_shm->string_ptr - &filebench_shm->strings[0]) > 591 FILEBENCH_STRINGMEMORY) { 592 filebench_log(LOG_ERROR, "Out of ipc string memory"); 593 return (NULL); 594 } 595 596 (void) strncpy(allocstr, string, strlen(string)); 597 598 return (allocstr); 599 } 600 601 /* 602 * Allocate a path string from filebench path string memory. 603 * Specifically used for allocating fileset paths. The length 604 * of the allocated path string is the same as the length of 605 * the supplied path string "path", and the contents of path 606 * are copied to the newly allocated path string. Checks for 607 * out-of-path-string-memory condition and returns NULL if so. 608 * Otherwise it returns a pointer to the newly allocated path 609 * string. 610 */ 611 char * 612 ipc_pathalloc(char *path) 613 { 614 char *allocpath = filebench_shm->path_ptr; 615 616 filebench_shm->path_ptr += strlen(path) + 1; 617 618 if ((filebench_shm->path_ptr - &filebench_shm->filesetpaths[0]) > 619 FILEBENCH_FILESETPATHMEMORY) { 620 filebench_log(LOG_ERROR, "Out of fileset path memory"); 621 return (NULL); 622 } 623 624 (void) strncpy(allocpath, path, strlen(path)); 625 626 return (allocpath); 627 } 628 629 /* 630 * This is a limited functionality deallocator for path 631 * strings - it can only free all path strings at once, 632 * in order to avoid fragmentation. 633 */ 634 void 635 ipc_freepaths(void) 636 { 637 filebench_shm->path_ptr = &filebench_shm->filesetpaths[0]; 638 } 639 640 /* 641 * Allocates a semid from the table of semids for pre intialized 642 * semaphores. Searches for the first available semaphore, and 643 * sets the entry in the table to "1" to indicate allocation. 644 * Returns the allocated semid. Stops the run if all semaphores 645 * are already in use. 646 */ 647 int 648 ipc_semidalloc(void) 649 { 650 int semid; 651 652 for (semid = 0; filebench_shm->semids[semid] == 1; semid++) 653 ; 654 if (semid == FILEBENCH_NSEMS) { 655 filebench_log(LOG_ERROR, 656 "Out of semaphores, increase system tunable limit"); 657 filebench_shutdown(1); 658 } 659 filebench_shm->semids[semid] = 1; 660 return (semid); 661 } 662 663 /* 664 * Frees up the supplied semid by seting its position in the 665 * allocation table to "0". 666 */ 667 void 668 ipc_semidfree(int semid) 669 { 670 filebench_shm->semids[semid] = 0; 671 } 672 673 /* 674 * Create a pool of shared memory to fit the per-thread 675 * allocations. Uses shmget() to create a shared memory region 676 * of size "size", attaches to it using shmat(), and stores 677 * the returned address of the region in filebench_shm->shm_addr. 678 * The pool is only created on the first call. The routine 679 * returns 0 if successful or the pool already exists, 680 * -1 otherwise. 681 */ 682 int 683 ipc_ismcreate(size_t size) 684 { 685 #ifdef HAVE_SHM_SHARE_MMU 686 int flag = SHM_SHARE_MMU; 687 #else 688 int flag = 0; 689 #endif /* HAVE_SHM_SHARE_MMU */ 690 691 /* Already done? */ 692 if (filebench_shm->shm_id != -1) 693 return (0); 694 695 filebench_log(LOG_VERBOSE, 696 "Creating %zd bytes of ISM Shared Memory...", size); 697 698 if ((filebench_shm->shm_id = 699 shmget(0, size, IPC_CREAT | 0666)) == -1) { 700 filebench_log(LOG_ERROR, 701 "Failed to create %zd bytes of ISM shared memory", size); 702 return (-1); 703 } 704 705 if ((filebench_shm->shm_addr = (caddr_t)shmat(filebench_shm->shm_id, 706 0, flag)) == (void *)-1) { 707 filebench_log(LOG_ERROR, 708 "Failed to attach %zd bytes of created ISM shared memory", 709 size); 710 return (-1); 711 } 712 713 filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr; 714 715 filebench_log(LOG_VERBOSE, 716 "Allocated %zd bytes of ISM Shared Memory... at %zx", 717 size, filebench_shm->shm_addr); 718 719 /* Locked until allocated to block allocs */ 720 (void) ipc_mutex_unlock(&filebench_shm->ism_lock); 721 722 return (0); 723 } 724 725 /* Per addr space ism */ 726 static int ism_attached = 0; 727 728 /* 729 * Attach to interprocess shared memory. If already attached 730 * just return, otherwise use shmat() to attached to the region 731 * with ID of filebench_shm->shm_id. Returns -1 if shmat() 732 * fails, otherwise 0. 733 */ 734 static int 735 ipc_ismattach(void) 736 { 737 #ifdef HAVE_SHM_SHARE_MMU 738 int flag = SHM_SHARE_MMU; 739 #else 740 int flag = 0; 741 #endif /* HAVE_SHM_SHARE_MMU */ 742 743 744 if (ism_attached) 745 return (0); 746 747 /* Does it exist? */ 748 if (filebench_shm->shm_id == 999) 749 return (0); 750 751 if (shmat(filebench_shm->shm_id, filebench_shm->shm_addr, 752 flag) == NULL) 753 return (-1); 754 755 ism_attached = 1; 756 757 return (0); 758 } 759 760 /* 761 * Allocate from interprocess shared memory. Attaches to ism 762 * if necessary, then allocates "size" bytes, updates allocation 763 * information and returns a pointer to the allocated memory. 764 */ 765 /* 766 * XXX No check is made for out-of-memory condition 767 */ 768 char * 769 ipc_ismmalloc(size_t size) 770 { 771 char *allocstr; 772 773 (void) ipc_mutex_lock(&filebench_shm->ism_lock); 774 775 /* Map in shared memory */ 776 (void) ipc_ismattach(); 777 778 allocstr = filebench_shm->shm_ptr; 779 780 filebench_shm->shm_ptr += size; 781 filebench_shm->shm_allocated += size; 782 783 (void) ipc_mutex_unlock(&filebench_shm->ism_lock); 784 785 return (allocstr); 786 } 787 788 /* 789 * Deletes shared memory region and resets shared memory region 790 * information in filebench_shm. 791 */ 792 void 793 ipc_ismdelete(void) 794 { 795 if (filebench_shm->shm_id == -1) 796 return; 797 798 filebench_log(LOG_VERBOSE, "Deleting ISM..."); 799 800 (void) ipc_mutex_lock(&filebench_shm->ism_lock); 801 #ifdef HAVE_SEM_RMID 802 (void) shmctl(filebench_shm->shm_id, IPC_RMID, 0); 803 #endif 804 filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr; 805 filebench_shm->shm_id = -1; 806 filebench_shm->shm_allocated = 0; 807 (void) ipc_mutex_unlock(&filebench_shm->ism_lock); 808 } 809