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