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