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