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->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->shm_string_ptr = &filebench_shm->shm_strings[0]; 328 filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr; 329 filebench_shm->shm_path_ptr = &filebench_shm->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->shm_malloc_lock, 343 ipc_mutexattr()); 344 (void) pthread_mutex_init(&filebench_shm->shm_ism_lock, 345 ipc_mutexattr()); 346 (void) pthread_cond_init(&filebench_shm->eventgen_cv, ipc_condattr()); 347 (void) pthread_rwlock_init(&filebench_shm->flowop_find_lock, 348 ipc_rwlockattr()); 349 (void) pthread_rwlock_init(&filebench_shm->run_lock, ipc_rwlockattr()); 350 (void) pthread_rwlock_rdlock(&filebench_shm->run_lock); 351 352 (void) ipc_mutex_lock(&filebench_shm->shm_ism_lock); 353 354 /* Create semaphore */ 355 if ((key = ftok(shmpath, 1)) < 0) { 356 filebench_log(LOG_ERROR, "cannot create sem: %s", 357 strerror(errno)); 358 exit(1); 359 } 360 361 #ifdef HAVE_SEM_RMID 362 if ((semid = semget(key, 0, 0)) != -1) 363 (void) semctl(semid, 0, IPC_RMID); 364 #endif 365 366 filebench_shm->semkey = key; 367 filebench_shm->log_fd = -1; 368 filebench_shm->dump_fd = -1; 369 filebench_shm->eventgen_hz = 0; 370 filebench_shm->shm_id = -1; 371 372 free(buf); 373 } 374 375 /* 376 * If compiled to use process model, just unlinks the shmpath. 377 * Otherwise a no-op. 378 */ 379 void 380 ipc_cleanup(void) 381 { 382 #ifdef USE_PROCESS_MODEL 383 (void) unlink(shmpath); 384 #endif /* USE_PROCESS_MODEL */ 385 } 386 387 /* 388 * Attach to shared memory. Used by worker processes to open 389 * and mmap the shared memory region. If successful, it 390 * initializes the worker process' filebench_shm to point to 391 * the region and returns 0. Otherwise it returns -1. 392 */ 393 int 394 ipc_attach(caddr_t shmaddr) 395 { 396 if ((shmfd = open(shmpath, O_RDWR, 0666)) < 0) { 397 filebench_log(LOG_ERROR, "Cannot open shm"); 398 return (-1); 399 } 400 401 /* LINTED E_BAD_PTR_CAST_ALIGN */ 402 if ((filebench_shm = (filebench_shm_t *)mmap(shmaddr, 403 sizeof (filebench_shm_t), PROT_READ | PROT_WRITE, 404 MAP_SHARED | MAP_FIXED, shmfd, 0)) == NULL) { 405 filebench_log(LOG_ERROR, "Cannot mmap shm"); 406 return (-1); 407 } 408 409 filebench_log(LOG_DEBUG_IMPL, "addr = %zx", filebench_shm); 410 411 return (0); 412 } 413 414 static int filebench_sizes[] = { 415 FILEBENCH_NPROCFLOWS, /* number of procflows */ 416 FILEBENCH_NTHREADFLOWS, /* number of threadflows */ 417 FILEBENCH_NFLOWOPS, /* number of flowops */ 418 (FILEBENCH_NVARS * 2), /* number of attribute value dscrs */ 419 FILEBENCH_NVARS, /* number of variables */ 420 FILEBENCH_NFILESETS, /* number of filesets */ 421 FILEBENCH_NFILESETENTRIES, /* number of fileset entries */ 422 FILEBENCH_NRANDDISTS}; /* number of random distributions */ 423 424 /* 425 * Allocates filebench objects from pre allocated region of 426 * shareable memory. The memory region is partitioned into sets 427 * of objects during initialization. This routine scans for 428 * the first unallocated object of type "type" in the set of 429 * available objects, and makes it as allocated. The routine 430 * returns a pointer to the object, or NULL if all objects have 431 * been allocated. 432 */ 433 void * 434 ipc_malloc(int type) 435 { 436 int i; 437 int max = filebench_sizes[type]; 438 int start_idx = filebench_shm->shm_lastbitmapindex[type]; 439 440 (void) ipc_mutex_lock(&filebench_shm->shm_malloc_lock); 441 442 i = start_idx; 443 do { 444 i++; 445 if (i >= max) 446 i = 0; 447 448 if (filebench_shm->shm_bitmap[type][i] == 0) 449 break; 450 451 } while (i != start_idx); 452 453 if (i == start_idx) { 454 filebench_log(LOG_ERROR, "Out of shared memory (%d)!", type); 455 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 456 return (NULL); 457 } 458 459 filebench_shm->shm_bitmap[type][i] = 1; 460 filebench_shm->shm_lastbitmapindex[type] = i; 461 462 switch (type) { 463 case FILEBENCH_FILESET: 464 (void) memset((char *)&filebench_shm->shm_fileset[i], 0, 465 sizeof (fileset_t)); 466 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 467 return ((char *)&filebench_shm->shm_fileset[i]); 468 469 case FILEBENCH_FILESETENTRY: 470 (void) memset((char *)&filebench_shm->shm_filesetentry[i], 0, 471 sizeof (filesetentry_t)); 472 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 473 return ((char *)&filebench_shm->shm_filesetentry[i]); 474 475 case FILEBENCH_PROCFLOW: 476 (void) memset((char *)&filebench_shm->shm_procflow[i], 0, 477 sizeof (procflow_t)); 478 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 479 return ((char *)&filebench_shm->shm_procflow[i]); 480 481 case FILEBENCH_THREADFLOW: 482 (void) memset((char *)&filebench_shm->shm_threadflow[i], 0, 483 sizeof (threadflow_t)); 484 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 485 return ((char *)&filebench_shm->shm_threadflow[i]); 486 487 case FILEBENCH_FLOWOP: 488 (void) memset((char *)&filebench_shm->shm_flowop[i], 0, 489 sizeof (flowop_t)); 490 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 491 return ((char *)&filebench_shm->shm_flowop[i]); 492 493 case FILEBENCH_AVD: 494 filebench_shm->shm_avd_ptrs[i].avd_type = AVD_INVALID; 495 filebench_shm->shm_avd_ptrs[i].avd_val.varptr = NULL; 496 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 497 return ((char *)&filebench_shm->shm_avd_ptrs[i]); 498 499 case FILEBENCH_VARIABLE: 500 (void) memset((char *)&filebench_shm->shm_var[i], 0, 501 sizeof (var_t)); 502 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 503 return ((char *)&filebench_shm->shm_var[i]); 504 505 case FILEBENCH_RANDDIST: 506 (void) memset((char *)&filebench_shm->shm_randdist[i], 0, 507 sizeof (randdist_t)); 508 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 509 return ((char *)&filebench_shm->shm_randdist[i]); 510 } 511 512 filebench_log(LOG_ERROR, "Attempt to ipc_malloc unknown type (%d)!", 513 type); 514 return (NULL); 515 } 516 517 /* 518 * Frees a filebench object of type "type" at the location 519 * pointed to by "addr". It uses the type and address to 520 * calculate which object is being freed, and clears its 521 * allocation map entry. 522 */ 523 void 524 ipc_free(int type, char *addr) 525 { 526 int item; 527 caddr_t base; 528 size_t offset; 529 size_t size; 530 531 if (addr == NULL) { 532 filebench_log(LOG_ERROR, "Freeing type %d %zx", type, addr); 533 return; 534 } 535 536 switch (type) { 537 538 case FILEBENCH_FILESET: 539 base = (caddr_t)&filebench_shm->shm_fileset[0]; 540 size = sizeof (fileset_t); 541 break; 542 543 case FILEBENCH_FILESETENTRY: 544 base = (caddr_t)&filebench_shm->shm_filesetentry[0]; 545 size = sizeof (filesetentry_t); 546 break; 547 548 case FILEBENCH_PROCFLOW: 549 base = (caddr_t)&filebench_shm->shm_procflow[0]; 550 size = sizeof (procflow_t); 551 break; 552 553 case FILEBENCH_THREADFLOW: 554 base = (caddr_t)&filebench_shm->shm_threadflow[0]; 555 size = sizeof (threadflow_t); 556 break; 557 558 case FILEBENCH_FLOWOP: 559 base = (caddr_t)&filebench_shm->shm_flowop[0]; 560 size = sizeof (flowop_t); 561 break; 562 563 case FILEBENCH_AVD: 564 base = (caddr_t)&filebench_shm->shm_avd_ptrs[0]; 565 size = sizeof (avd_t); 566 break; 567 568 case FILEBENCH_VARIABLE: 569 base = (caddr_t)&filebench_shm->shm_var[0]; 570 size = sizeof (var_t); 571 break; 572 573 case FILEBENCH_RANDDIST: 574 base = (caddr_t)&filebench_shm->shm_randdist[0]; 575 size = sizeof (randdist_t); 576 break; 577 } 578 579 offset = ((size_t)addr - (size_t)base); 580 item = offset / size; 581 582 (void) ipc_mutex_lock(&filebench_shm->shm_malloc_lock); 583 filebench_shm->shm_bitmap[type][item] = 0; 584 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 585 } 586 587 /* 588 * Allocate a string from filebench string memory. The length 589 * of the allocated string is the same as the length of the 590 * supplied string "string", and the contents of string are 591 * copied to the newly allocated string. 592 */ 593 char * 594 ipc_stralloc(char *string) 595 { 596 char *allocstr = filebench_shm->shm_string_ptr; 597 598 filebench_shm->shm_string_ptr += strlen(string) + 1; 599 600 if ((filebench_shm->shm_string_ptr - &filebench_shm->shm_strings[0]) > 601 FILEBENCH_STRINGMEMORY) { 602 filebench_log(LOG_ERROR, "Out of ipc string memory"); 603 return (NULL); 604 } 605 606 (void) strncpy(allocstr, string, strlen(string)); 607 608 return (allocstr); 609 } 610 611 /* 612 * Allocate a path string from filebench path string memory. 613 * Specifically used for allocating fileset paths. The length 614 * of the allocated path string is the same as the length of 615 * the supplied path string "path", and the contents of path 616 * are copied to the newly allocated path string. Checks for 617 * out-of-path-string-memory condition and returns NULL if so. 618 * Otherwise it returns a pointer to the newly allocated path 619 * string. 620 */ 621 char * 622 ipc_pathalloc(char *path) 623 { 624 char *allocpath = filebench_shm->shm_path_ptr; 625 626 filebench_shm->shm_path_ptr += strlen(path) + 1; 627 628 if ((filebench_shm->shm_path_ptr - 629 &filebench_shm->shm_filesetpaths[0]) > 630 FILEBENCH_FILESETPATHMEMORY) { 631 filebench_log(LOG_ERROR, "Out of fileset path memory"); 632 return (NULL); 633 } 634 635 (void) strncpy(allocpath, path, strlen(path)); 636 637 return (allocpath); 638 } 639 640 /* 641 * This is a limited functionality deallocator for path 642 * strings - it can only free all path strings at once, 643 * in order to avoid fragmentation. 644 */ 645 void 646 ipc_freepaths(void) 647 { 648 filebench_shm->shm_path_ptr = &filebench_shm->shm_filesetpaths[0]; 649 } 650 651 /* 652 * Allocates a semid from the table of semids for pre intialized 653 * semaphores. Searches for the first available semaphore, and 654 * sets the entry in the table to "1" to indicate allocation. 655 * Returns the allocated semid. Stops the run if all semaphores 656 * are already in use. 657 */ 658 int 659 ipc_semidalloc(void) 660 { 661 int semid; 662 663 for (semid = 0; filebench_shm->semids[semid] == 1; semid++) 664 ; 665 if (semid == FILEBENCH_NSEMS) { 666 filebench_log(LOG_ERROR, 667 "Out of semaphores, increase system tunable limit"); 668 filebench_shutdown(1); 669 } 670 filebench_shm->semids[semid] = 1; 671 return (semid); 672 } 673 674 /* 675 * Frees up the supplied semid by seting its position in the 676 * allocation table to "0". 677 */ 678 void 679 ipc_semidfree(int semid) 680 { 681 filebench_shm->semids[semid] = 0; 682 } 683 684 /* 685 * Create a pool of shared memory to fit the per-thread 686 * allocations. Uses shmget() to create a shared memory region 687 * of size "size", attaches to it using shmat(), and stores 688 * the returned address of the region in filebench_shm->shm_addr. 689 * The pool is only created on the first call. The routine 690 * returns 0 if successful or the pool already exists, 691 * -1 otherwise. 692 */ 693 int 694 ipc_ismcreate(size_t size) 695 { 696 #ifdef HAVE_SHM_SHARE_MMU 697 int flag = SHM_SHARE_MMU; 698 #else 699 int flag = 0; 700 #endif /* HAVE_SHM_SHARE_MMU */ 701 702 /* Already done? */ 703 if (filebench_shm->shm_id != -1) 704 return (0); 705 706 filebench_log(LOG_VERBOSE, 707 "Creating %zd bytes of ISM Shared Memory...", size); 708 709 if ((filebench_shm->shm_id = 710 shmget(0, size, IPC_CREAT | 0666)) == -1) { 711 filebench_log(LOG_ERROR, 712 "Failed to create %zd bytes of ISM shared memory", size); 713 return (-1); 714 } 715 716 if ((filebench_shm->shm_addr = (caddr_t)shmat(filebench_shm->shm_id, 717 0, flag)) == (void *)-1) { 718 filebench_log(LOG_ERROR, 719 "Failed to attach %zd bytes of created ISM shared memory", 720 size); 721 return (-1); 722 } 723 724 filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr; 725 726 filebench_log(LOG_VERBOSE, 727 "Allocated %zd bytes of ISM Shared Memory... at %zx", 728 size, filebench_shm->shm_addr); 729 730 /* Locked until allocated to block allocs */ 731 (void) ipc_mutex_unlock(&filebench_shm->shm_ism_lock); 732 733 return (0); 734 } 735 736 /* Per addr space ism */ 737 static int ism_attached = 0; 738 739 /* 740 * Attach to interprocess shared memory. If already attached 741 * just return, otherwise use shmat() to attached to the region 742 * with ID of filebench_shm->shm_id. Returns -1 if shmat() 743 * fails, otherwise 0. 744 */ 745 static int 746 ipc_ismattach(void) 747 { 748 #ifdef HAVE_SHM_SHARE_MMU 749 int flag = SHM_SHARE_MMU; 750 #else 751 int flag = 0; 752 #endif /* HAVE_SHM_SHARE_MMU */ 753 754 755 if (ism_attached) 756 return (0); 757 758 /* Does it exist? */ 759 if (filebench_shm->shm_id == 999) 760 return (0); 761 762 if (shmat(filebench_shm->shm_id, filebench_shm->shm_addr, 763 flag) == NULL) 764 return (-1); 765 766 ism_attached = 1; 767 768 return (0); 769 } 770 771 /* 772 * Allocate from interprocess shared memory. Attaches to ism 773 * if necessary, then allocates "size" bytes, updates allocation 774 * information and returns a pointer to the allocated memory. 775 */ 776 /* 777 * XXX No check is made for out-of-memory condition 778 */ 779 char * 780 ipc_ismmalloc(size_t size) 781 { 782 char *allocstr; 783 784 (void) ipc_mutex_lock(&filebench_shm->shm_ism_lock); 785 786 /* Map in shared memory */ 787 (void) ipc_ismattach(); 788 789 allocstr = filebench_shm->shm_ptr; 790 791 filebench_shm->shm_ptr += size; 792 filebench_shm->shm_allocated += size; 793 794 (void) ipc_mutex_unlock(&filebench_shm->shm_ism_lock); 795 796 return (allocstr); 797 } 798 799 /* 800 * Deletes shared memory region and resets shared memory region 801 * information in filebench_shm. 802 */ 803 void 804 ipc_ismdelete(void) 805 { 806 if (filebench_shm->shm_id == -1) 807 return; 808 809 filebench_log(LOG_VERBOSE, "Deleting ISM..."); 810 811 (void) ipc_mutex_lock(&filebench_shm->shm_ism_lock); 812 #ifdef HAVE_SEM_RMID 813 (void) shmctl(filebench_shm->shm_id, IPC_RMID, 0); 814 #endif 815 filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr; 816 filebench_shm->shm_id = -1; 817 filebench_shm->shm_allocated = 0; 818 (void) ipc_mutex_unlock(&filebench_shm->shm_ism_lock); 819 } 820