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