15184Sek110237 /* 25184Sek110237 * CDDL HEADER START 35184Sek110237 * 45184Sek110237 * The contents of this file are subject to the terms of the 55184Sek110237 * Common Development and Distribution License (the "License"). 65184Sek110237 * You may not use this file except in compliance with the License. 75184Sek110237 * 85184Sek110237 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95184Sek110237 * or http://www.opensolaris.org/os/licensing. 105184Sek110237 * See the License for the specific language governing permissions 115184Sek110237 * and limitations under the License. 125184Sek110237 * 135184Sek110237 * When distributing Covered Code, include this CDDL HEADER in each 145184Sek110237 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155184Sek110237 * If applicable, add the following below this CDDL HEADER, with the 165184Sek110237 * fields enclosed by brackets "[]" replaced with your own identifying 175184Sek110237 * information: Portions Copyright [yyyy] [name of copyright owner] 185184Sek110237 * 195184Sek110237 * CDDL HEADER END 205184Sek110237 */ 215184Sek110237 /* 226084Saw148015 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 235184Sek110237 * Use is subject to license terms. 245184Sek110237 */ 255184Sek110237 265184Sek110237 #pragma ident "%Z%%M% %I% %E% SMI" 275184Sek110237 285184Sek110237 #include "config.h" 295184Sek110237 305184Sek110237 #include <stdio.h> 315184Sek110237 #include <fcntl.h> 325184Sek110237 #include <sys/mman.h> 335184Sek110237 #include <sys/ipc.h> 345184Sek110237 #include <sys/sem.h> 355184Sek110237 #include <sys/errno.h> 365184Sek110237 #include <signal.h> 375184Sek110237 #include <pthread.h> 385184Sek110237 #include <sys/shm.h> 395184Sek110237 #include "filebench.h" 405184Sek110237 415184Sek110237 /* IPC Hub and Simple memory allocator */ 425184Sek110237 435184Sek110237 static int shmfd; 445184Sek110237 filebench_shm_t *filebench_shm = NULL; 455184Sek110237 static pthread_mutexattr_t *mutexattr = NULL; 465184Sek110237 475184Sek110237 /* 485184Sek110237 * Interprocess Communication mechanisms. If multiple processes 495184Sek110237 * are used, filebench opens a shared file in memory mapped mode to hold 505184Sek110237 * a variety of global variables and data structures. If only using 515184Sek110237 * multiple threads, it just allocates a region of local memory. A 525184Sek110237 * region of interprocess shared memory and a set of shared semaphores 535184Sek110237 * are also created. Routines are provided to manage the creation, 545184Sek110237 * destruction, and allocation of these resoures. 555184Sek110237 */ 565184Sek110237 575184Sek110237 585184Sek110237 /* 595184Sek110237 * Locks a mutex and logs any errors. 605184Sek110237 */ 615184Sek110237 int 625184Sek110237 ipc_mutex_lock(pthread_mutex_t *mutex) 635184Sek110237 { 645184Sek110237 int error; 655184Sek110237 665184Sek110237 error = pthread_mutex_lock(mutex); 675184Sek110237 685184Sek110237 #ifdef HAVE_ROBUST_MUTEX 695184Sek110237 if (error == EOWNERDEAD) { 705184Sek110237 if (pthread_mutex_consistent_np(mutex) != 0) { 715184Sek110237 filebench_log(LOG_FATAL, "mutex make consistent " 725184Sek110237 "failed: %s", strerror(error)); 735184Sek110237 return (-1); 745184Sek110237 } 755184Sek110237 return (0); 765184Sek110237 } 775184Sek110237 #endif /* HAVE_ROBUST_MUTEX */ 785184Sek110237 795184Sek110237 if (error != 0) { 805184Sek110237 filebench_log(LOG_FATAL, "mutex lock failed: %s", 815184Sek110237 strerror(error)); 825184Sek110237 } 835184Sek110237 845184Sek110237 return (error); 855184Sek110237 } 865184Sek110237 875184Sek110237 /* 885184Sek110237 * Unlocks a mutex and logs any errors. 895184Sek110237 */ 905184Sek110237 int 915184Sek110237 ipc_mutex_unlock(pthread_mutex_t *mutex) 925184Sek110237 { 935184Sek110237 int error; 945184Sek110237 955184Sek110237 error = pthread_mutex_unlock(mutex); 965184Sek110237 975184Sek110237 #ifdef HAVE_ROBUST_MUTEX 985184Sek110237 if (error == EOWNERDEAD) { 995184Sek110237 if (pthread_mutex_consistent_np(mutex) != 0) { 1005184Sek110237 filebench_log(LOG_FATAL, "mutex make consistent " 1015184Sek110237 "failed: %s", strerror(error)); 1025184Sek110237 return (-1); 1035184Sek110237 } 1045184Sek110237 return (0); 1055184Sek110237 } 1065184Sek110237 #endif /* HAVE_ROBUST_MUTEX */ 1075184Sek110237 1085184Sek110237 if (error != 0) { 1095184Sek110237 filebench_log(LOG_FATAL, "mutex unlock failed: %s", 1105184Sek110237 strerror(error)); 1115184Sek110237 } 1125184Sek110237 1135184Sek110237 return (error); 1145184Sek110237 } 1155184Sek110237 1165184Sek110237 /* 1175184Sek110237 * On first invocation, allocates a mutex attributes structure 1185184Sek110237 * and initializes it with appropriate attributes. In all cases, 1195184Sek110237 * returns a pointer to the structure. 1205184Sek110237 */ 1215184Sek110237 pthread_mutexattr_t * 1225184Sek110237 ipc_mutexattr(void) 1235184Sek110237 { 1245184Sek110237 #ifdef USE_PROCESS_MODEL 1255184Sek110237 if (mutexattr == NULL) { 1265184Sek110237 if ((mutexattr = 1275184Sek110237 malloc(sizeof (pthread_mutexattr_t))) == NULL) { 1285184Sek110237 filebench_log(LOG_ERROR, "cannot alloc mutex attr"); 1295184Sek110237 filebench_shutdown(1); 1305184Sek110237 } 1315184Sek110237 #ifdef HAVE_PROCSCOPE_PTHREADS 1325184Sek110237 (void) pthread_mutexattr_init(mutexattr); 1335184Sek110237 if (pthread_mutexattr_setpshared(mutexattr, 1345184Sek110237 PTHREAD_PROCESS_SHARED) != 0) { 1355184Sek110237 filebench_log(LOG_ERROR, "cannot set mutex attr " 1365184Sek110237 "PROCESS_SHARED on this platform"); 1375184Sek110237 filebench_shutdown(1); 1385184Sek110237 } 1395184Sek110237 #ifdef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL 1405184Sek110237 if (pthread_mutexattr_setprotocol(mutexattr, 1415184Sek110237 PTHREAD_PRIO_INHERIT) != 0) { 1425184Sek110237 filebench_log(LOG_ERROR, "cannot set mutex attr " 1435184Sek110237 "PTHREAD_PRIO_INHERIT on this platform"); 1445184Sek110237 filebench_shutdown(1); 1455184Sek110237 } 1465184Sek110237 #endif /* HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL */ 1475184Sek110237 #endif /* HAVE_PROCSCOPE_PTHREADS */ 1485184Sek110237 #ifdef HAVE_ROBUST_MUTEX 1495184Sek110237 if (pthread_mutexattr_setrobust_np(mutexattr, 1505184Sek110237 PTHREAD_MUTEX_ROBUST_NP) != 0) { 1515184Sek110237 filebench_log(LOG_ERROR, "cannot set mutex attr " 1525184Sek110237 "PTHREAD_MUTEX_ROBUST_NP on this platform"); 1535184Sek110237 filebench_shutdown(1); 1545184Sek110237 } 1555184Sek110237 if (pthread_mutexattr_settype(mutexattr, 1565184Sek110237 PTHREAD_MUTEX_ERRORCHECK) != 0) { 1575184Sek110237 filebench_log(LOG_ERROR, "cannot set mutex attr " 1585184Sek110237 "PTHREAD_MUTEX_ERRORCHECK on this platform"); 1595184Sek110237 filebench_shutdown(1); 1605184Sek110237 } 1615184Sek110237 #endif /* HAVE_ROBUST_MUTEX */ 1625184Sek110237 1635184Sek110237 } 1645184Sek110237 #endif /* USE_PROCESS_MODEL */ 1655184Sek110237 return (mutexattr); 1665184Sek110237 } 1675184Sek110237 1685184Sek110237 static pthread_condattr_t *condattr = NULL; 1695184Sek110237 1705184Sek110237 /* 1715184Sek110237 * On first invocation, allocates a condition variable attributes 1725184Sek110237 * structure and initializes it with appropriate attributes. In 1735184Sek110237 * all cases, returns a pointer to the structure. 1745184Sek110237 */ 1755184Sek110237 pthread_condattr_t * 1765184Sek110237 ipc_condattr(void) 1775184Sek110237 { 1785184Sek110237 #ifdef USE_PROCESS_MODEL 1795184Sek110237 if (condattr == NULL) { 1805184Sek110237 if ((condattr = malloc(sizeof (pthread_condattr_t))) == NULL) { 1815184Sek110237 filebench_log(LOG_ERROR, "cannot alloc cond attr"); 1825184Sek110237 filebench_shutdown(1); 1835184Sek110237 } 1845184Sek110237 #ifdef HAVE_PROCSCOPE_PTHREADS 1855184Sek110237 (void) pthread_condattr_init(condattr); 1865184Sek110237 if (pthread_condattr_setpshared(condattr, 1875184Sek110237 PTHREAD_PROCESS_SHARED) != 0) { 1885184Sek110237 filebench_log(LOG_ERROR, 1895184Sek110237 "cannot set cond attr PROCESS_SHARED"); 1905184Sek110237 filebench_shutdown(1); 1915184Sek110237 } 1925184Sek110237 #endif /* HAVE_PROCSCOPE_PTHREADS */ 1935184Sek110237 } 1945184Sek110237 #endif /* USE_PROCESS_MODEL */ 1955184Sek110237 return (condattr); 1965184Sek110237 } 1975184Sek110237 1985184Sek110237 static pthread_rwlockattr_t *rwlockattr = NULL; 1995184Sek110237 2005184Sek110237 /* 2015184Sek110237 * On first invocation, allocates a readers/writers attributes 2025184Sek110237 * structure and initializes it with appropriate attributes. 2035184Sek110237 * In all cases, returns a pointer to the structure. 2045184Sek110237 */ 2055184Sek110237 static pthread_rwlockattr_t * 2065184Sek110237 ipc_rwlockattr(void) 2075184Sek110237 { 2085184Sek110237 #ifdef USE_PROCESS_MODEL 2095184Sek110237 if (rwlockattr == NULL) { 2105184Sek110237 if ((rwlockattr = 2115184Sek110237 malloc(sizeof (pthread_rwlockattr_t))) == NULL) { 2125184Sek110237 filebench_log(LOG_ERROR, "cannot alloc rwlock attr"); 2135184Sek110237 filebench_shutdown(1); 2145184Sek110237 } 2155184Sek110237 #ifdef HAVE_PROCSCOPE_PTHREADS 2165184Sek110237 (void) pthread_rwlockattr_init(rwlockattr); 2175184Sek110237 if (pthread_rwlockattr_setpshared(rwlockattr, 2185184Sek110237 PTHREAD_PROCESS_SHARED) != 0) { 2195184Sek110237 filebench_log(LOG_ERROR, 2205184Sek110237 "cannot set rwlock attr PROCESS_SHARED"); 2215184Sek110237 filebench_shutdown(1); 2225184Sek110237 } 2235184Sek110237 #endif /* HAVE_PROCSCOPE_PTHREADS */ 2245184Sek110237 } 2255184Sek110237 #endif /* USE_PROCESS_MODEL */ 2265184Sek110237 return (rwlockattr); 2275184Sek110237 } 2285184Sek110237 2295184Sek110237 char *shmpath = NULL; 2305184Sek110237 2315184Sek110237 /* 2325184Sek110237 * Calls semget() to get a set of shared system V semaphores. 2335184Sek110237 */ 2345184Sek110237 void 2355184Sek110237 ipc_seminit(void) 2365184Sek110237 { 2375184Sek110237 key_t key = filebench_shm->semkey; 2385184Sek110237 2395184Sek110237 /* Already done? */ 2405184Sek110237 if (filebench_shm->seminit) 2415184Sek110237 return; 2425184Sek110237 2435184Sek110237 if ((semget(key, FILEBENCH_NSEMS, IPC_CREAT | 2445184Sek110237 S_IRUSR | S_IWUSR)) == -1) { 2455184Sek110237 filebench_log(LOG_ERROR, 2465184Sek110237 "could not create sysv semaphore set " 2475184Sek110237 "(need to increase sems?): %s", 2485184Sek110237 strerror(errno)); 2495184Sek110237 exit(1); 2505184Sek110237 } 2515184Sek110237 } 2525184Sek110237 2535184Sek110237 /* 2545184Sek110237 * Initialize the Interprocess Communication system and its 2555184Sek110237 * associated shared memory structure. It first creates a 2565184Sek110237 * temporary file using either the mkstemp() function or the 2575184Sek110237 * tempnam() and open() functions. If the process model is in 2585184Sek110237 * use,it than sets the file large enough to hold the 2595184Sek110237 * filebench_shm and an additional Megabyte. The file is then 2605184Sek110237 * memory mapped. If the process model is not in use, it simply 2615184Sek110237 * mallocs a region of sizeof (filebench_shm_t). 2625184Sek110237 * 2635184Sek110237 * Once the shared memory region / file is created, ipc_init 2645184Sek110237 * initializes various locks pointers, and variables in the 2655184Sek110237 * shared memory. It also uses ftok() to get a shared memory 2665184Sek110237 * semaphore key for later use in allocating shared semaphores. 2675184Sek110237 */ 2685184Sek110237 void 2695184Sek110237 ipc_init(void) 2705184Sek110237 { 2715184Sek110237 filebench_shm_t *buf = malloc(MB); 2725184Sek110237 key_t key; 2735184Sek110237 caddr_t c1; 2745184Sek110237 caddr_t c2; 2755184Sek110237 #ifdef HAVE_SEM_RMID 2765184Sek110237 int semid; 2775184Sek110237 #endif 2785184Sek110237 2795184Sek110237 #ifdef HAVE_MKSTEMP 2805184Sek110237 shmpath = (char *)malloc(128); 2815184Sek110237 (void) strcpy(shmpath, "/var/tmp/fbenchXXXXXX"); 2825184Sek110237 shmfd = mkstemp(shmpath); 2835184Sek110237 #else 2845184Sek110237 shmfd = open(shmpath, O_CREAT | O_RDWR | O_TRUNC, 0666); 2855184Sek110237 shmpath = tempnam("/var/tmp", "fbench"); 2865184Sek110237 #endif /* HAVE_MKSTEMP */ 2875184Sek110237 2885184Sek110237 #ifdef USE_PROCESS_MODEL 2895184Sek110237 2905184Sek110237 if (shmfd < 0) { 2915184Sek110237 filebench_log(LOG_FATAL, "Cannot open shm %s: %s", 2925184Sek110237 shmpath, 2935184Sek110237 strerror(errno)); 2945184Sek110237 exit(1); 2955184Sek110237 } 2965184Sek110237 2975184Sek110237 (void) lseek(shmfd, sizeof (filebench_shm_t), SEEK_SET); 2985184Sek110237 if (write(shmfd, buf, MB) != MB) { 2995184Sek110237 filebench_log(LOG_FATAL, 3005184Sek110237 "Cannot allocate shm: %s", strerror(errno)); 3015184Sek110237 exit(1); 3025184Sek110237 } 3035184Sek110237 3045184Sek110237 /* LINTED E_BAD_PTR_CAST_ALIGN */ 3055184Sek110237 if ((filebench_shm = (filebench_shm_t *)mmap((caddr_t)0, 3065673Saw148015 sizeof (filebench_shm_t), PROT_READ | PROT_WRITE, 3075673Saw148015 MAP_SHARED, shmfd, 0)) == NULL) { 3085184Sek110237 filebench_log(LOG_FATAL, "Cannot mmap shm"); 3095184Sek110237 exit(1); 3105184Sek110237 } 3115184Sek110237 3125184Sek110237 #else 3135184Sek110237 if ((filebench_shm = 3145184Sek110237 (filebench_shm_t *)malloc(sizeof (filebench_shm_t))) == NULL) { 3155184Sek110237 filebench_log(LOG_FATAL, "Cannot malloc shm"); 3165184Sek110237 exit(1); 3175184Sek110237 } 3185184Sek110237 #endif /* USE_PROCESS_MODEL */ 3195184Sek110237 3205184Sek110237 c1 = (caddr_t)filebench_shm; 3215184Sek110237 c2 = (caddr_t)&filebench_shm->marker; 3225184Sek110237 3235184Sek110237 (void) memset(filebench_shm, 0, c2 - c1); 3245184Sek110237 filebench_shm->epoch = gethrtime(); 3256084Saw148015 filebench_shm->debug_level = LOG_VERBOSE; 3266084Saw148015 filebench_shm->shm_rmode = FILEBENCH_MODE_TIMEOUT; 3275184Sek110237 filebench_shm->string_ptr = &filebench_shm->strings[0]; 3285184Sek110237 filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr; 3295184Sek110237 filebench_shm->path_ptr = &filebench_shm->filesetpaths[0]; 3305184Sek110237 3315184Sek110237 /* Setup mutexes for object lists */ 3325184Sek110237 (void) pthread_mutex_init(&filebench_shm->fileset_lock, 3335184Sek110237 ipc_mutexattr()); 3345184Sek110237 (void) pthread_mutex_init(&filebench_shm->procflow_lock, 3355184Sek110237 ipc_mutexattr()); 3365184Sek110237 (void) pthread_mutex_init(&filebench_shm->threadflow_lock, 3375184Sek110237 ipc_mutexattr()); 3385184Sek110237 (void) pthread_mutex_init(&filebench_shm->flowop_lock, ipc_mutexattr()); 3395184Sek110237 (void) pthread_mutex_init(&filebench_shm->msg_lock, ipc_mutexattr()); 3405184Sek110237 (void) pthread_mutex_init(&filebench_shm->eventgen_lock, 3415184Sek110237 ipc_mutexattr()); 3425184Sek110237 (void) pthread_mutex_init(&filebench_shm->malloc_lock, ipc_mutexattr()); 3435184Sek110237 (void) pthread_mutex_init(&filebench_shm->ism_lock, ipc_mutexattr()); 3445184Sek110237 (void) pthread_cond_init(&filebench_shm->eventgen_cv, ipc_condattr()); 3455184Sek110237 (void) pthread_rwlock_init(&filebench_shm->flowop_find_lock, 3465184Sek110237 ipc_rwlockattr()); 3475184Sek110237 (void) pthread_rwlock_init(&filebench_shm->run_lock, ipc_rwlockattr()); 3485184Sek110237 (void) pthread_rwlock_rdlock(&filebench_shm->run_lock); 3495184Sek110237 3505184Sek110237 (void) ipc_mutex_lock(&filebench_shm->ism_lock); 3515184Sek110237 3525184Sek110237 /* Create semaphore */ 3535184Sek110237 if ((key = ftok(shmpath, 1)) < 0) { 3545184Sek110237 filebench_log(LOG_ERROR, "cannot create sem: %s", 3555184Sek110237 strerror(errno)); 3565184Sek110237 exit(1); 3575184Sek110237 } 3585184Sek110237 3595184Sek110237 #ifdef HAVE_SEM_RMID 3605184Sek110237 if ((semid = semget(key, 0, 0)) != -1) 3615184Sek110237 (void) semctl(semid, 0, IPC_RMID); 3625184Sek110237 #endif 3635184Sek110237 3645184Sek110237 filebench_shm->semkey = key; 3655184Sek110237 filebench_shm->log_fd = -1; 3665184Sek110237 filebench_shm->dump_fd = -1; 3675184Sek110237 filebench_shm->eventgen_hz = 0; 3685184Sek110237 filebench_shm->shm_id = -1; 3695184Sek110237 3705184Sek110237 free(buf); 3715184Sek110237 } 3725184Sek110237 3735184Sek110237 /* 3745184Sek110237 * If compiled to use process model, just unlinks the shmpath. 3755184Sek110237 * Otherwise a no-op. 3765184Sek110237 */ 3775184Sek110237 void 3785184Sek110237 ipc_cleanup(void) 3795184Sek110237 { 3805184Sek110237 #ifdef USE_PROCESS_MODEL 3815184Sek110237 (void) unlink(shmpath); 3825184Sek110237 #endif /* USE_PROCESS_MODEL */ 3835184Sek110237 } 3845184Sek110237 3855184Sek110237 /* 3865184Sek110237 * Attach to shared memory. Used by worker processes to open 3875184Sek110237 * and mmap the shared memory region. If successful, it 3885184Sek110237 * initializes the worker process' filebench_shm to point to 3895184Sek110237 * the region and returns 0. Otherwise it returns -1. 3905184Sek110237 */ 3915184Sek110237 int 3925184Sek110237 ipc_attach(caddr_t shmaddr) 3935184Sek110237 { 3945184Sek110237 if ((shmfd = open(shmpath, O_RDWR, 0666)) < 0) { 3955184Sek110237 filebench_log(LOG_ERROR, "Cannot open shm"); 3965184Sek110237 return (-1); 3975184Sek110237 } 3985184Sek110237 3995184Sek110237 /* LINTED E_BAD_PTR_CAST_ALIGN */ 4005184Sek110237 if ((filebench_shm = (filebench_shm_t *)mmap(shmaddr, 4015184Sek110237 sizeof (filebench_shm_t), PROT_READ | PROT_WRITE, 4025184Sek110237 MAP_SHARED | MAP_FIXED, shmfd, 0)) == NULL) { 4035184Sek110237 filebench_log(LOG_ERROR, "Cannot mmap shm"); 4045184Sek110237 return (-1); 4055184Sek110237 } 4065184Sek110237 4075184Sek110237 filebench_log(LOG_DEBUG_IMPL, "addr = %zx", filebench_shm); 4085184Sek110237 4095184Sek110237 return (0); 4105184Sek110237 } 4115184Sek110237 4125184Sek110237 static int filebench_sizes[] = { 413*6212Saw148015 FILEBENCH_NPROCFLOWS, /* number of procflows */ 414*6212Saw148015 FILEBENCH_NTHREADFLOWS, /* number of threadflows */ 415*6212Saw148015 FILEBENCH_NFLOWOPS, /* number of flowops */ 416*6212Saw148015 (FILEBENCH_NVARS * 2), /* number of attribute value dscrs */ 417*6212Saw148015 FILEBENCH_NVARS, /* number of variables */ 418*6212Saw148015 FILEBENCH_NFILESETS, /* number of filesets */ 419*6212Saw148015 FILEBENCH_NFILESETENTRIES, /* number of fileset entries */ 420*6212Saw148015 FILEBENCH_NRANDDISTS}; /* number of random distributions */ 4215184Sek110237 4225184Sek110237 /* 4235184Sek110237 * Allocates filebench objects from pre allocated region of 4245184Sek110237 * shareable memory. The memory region is partitioned into sets 4255184Sek110237 * of objects during initialization. This routine scans for 4265184Sek110237 * the first unallocated object of type "type" in the set of 4275184Sek110237 * available objects, and makes it as allocated. The routine 4285184Sek110237 * returns a pointer to the object, or NULL if all objects have 4295184Sek110237 * been allocated. 4305184Sek110237 */ 4315184Sek110237 void * 4325184Sek110237 ipc_malloc(int type) 4335184Sek110237 { 4345184Sek110237 int i; 4355184Sek110237 int max = filebench_sizes[type]; 4365184Sek110237 4375184Sek110237 (void) ipc_mutex_lock(&filebench_shm->malloc_lock); 4385184Sek110237 4395184Sek110237 for (i = 0; i < max; i++) { 4405184Sek110237 if (filebench_shm->bitmap[type][i] == 0) 4415184Sek110237 break; 4425184Sek110237 } 4435184Sek110237 4445184Sek110237 if (i >= max) { 4455184Sek110237 filebench_log(LOG_ERROR, "Out of shared memory (%d)!", type); 4465184Sek110237 (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); 4475184Sek110237 return (NULL); 4485184Sek110237 } 4495184Sek110237 4505184Sek110237 filebench_shm->bitmap[type][i] = 1; 4515184Sek110237 4525184Sek110237 switch (type) { 4535184Sek110237 case FILEBENCH_FILESET: 4545184Sek110237 (void) memset((char *)&filebench_shm->fileset[i], 0, 4555184Sek110237 sizeof (fileset_t)); 4565184Sek110237 (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); 4575184Sek110237 return ((char *)&filebench_shm->fileset[i]); 4585184Sek110237 4595184Sek110237 case FILEBENCH_FILESETENTRY: 4605184Sek110237 (void) memset((char *)&filebench_shm->filesetentry[i], 0, 4615184Sek110237 sizeof (filesetentry_t)); 4625184Sek110237 (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); 4635184Sek110237 return ((char *)&filebench_shm->filesetentry[i]); 4645184Sek110237 4655184Sek110237 case FILEBENCH_PROCFLOW: 4665184Sek110237 (void) memset((char *)&filebench_shm->procflow[i], 0, 4675184Sek110237 sizeof (procflow_t)); 4685184Sek110237 (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); 4695184Sek110237 return ((char *)&filebench_shm->procflow[i]); 4705184Sek110237 4715184Sek110237 case FILEBENCH_THREADFLOW: 4725184Sek110237 (void) memset((char *)&filebench_shm->threadflow[i], 0, 4735184Sek110237 sizeof (threadflow_t)); 4745184Sek110237 (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); 4755184Sek110237 return ((char *)&filebench_shm->threadflow[i]); 4765184Sek110237 4775184Sek110237 case FILEBENCH_FLOWOP: 4785184Sek110237 (void) memset((char *)&filebench_shm->flowop[i], 0, 4795184Sek110237 sizeof (flowop_t)); 4805184Sek110237 (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); 4815184Sek110237 return ((char *)&filebench_shm->flowop[i]); 4825184Sek110237 483*6212Saw148015 case FILEBENCH_AVD: 484*6212Saw148015 filebench_shm->shm_avd_ptrs[i].avd_type = AVD_INVALID; 485*6212Saw148015 filebench_shm->shm_avd_ptrs[i].avd_val.varptr = NULL; 4865184Sek110237 (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); 487*6212Saw148015 return ((char *)&filebench_shm->shm_avd_ptrs[i]); 4885184Sek110237 4895184Sek110237 case FILEBENCH_VARIABLE: 4905184Sek110237 (void) memset((char *)&filebench_shm->var[i], 0, 4915184Sek110237 sizeof (var_t)); 4925184Sek110237 (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); 4935184Sek110237 return ((char *)&filebench_shm->var[i]); 494*6212Saw148015 495*6212Saw148015 case FILEBENCH_RANDDIST: 496*6212Saw148015 (void) memset((char *)&filebench_shm->shm_randdist[i], 0, 497*6212Saw148015 sizeof (randdist_t)); 498*6212Saw148015 (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); 499*6212Saw148015 return ((char *)&filebench_shm->shm_randdist[i]); 5005184Sek110237 } 5015184Sek110237 5025184Sek110237 filebench_log(LOG_ERROR, "Attempt to ipc_malloc unknown type (%d)!", 5035184Sek110237 type); 5045184Sek110237 return (NULL); 5055184Sek110237 } 5065184Sek110237 5075184Sek110237 /* 5085184Sek110237 * Frees a filebench object of type "type" at the location 5095184Sek110237 * pointed to by "addr". It uses the type and address to 5105184Sek110237 * calculate which object is being freed, and clears its 5115184Sek110237 * allocation map entry. 5125184Sek110237 */ 5135184Sek110237 void 5145184Sek110237 ipc_free(int type, char *addr) 5155184Sek110237 { 5165184Sek110237 int item; 5175184Sek110237 caddr_t base; 5185184Sek110237 size_t offset; 5195184Sek110237 size_t size; 5205184Sek110237 5215184Sek110237 if (addr == NULL) { 5225184Sek110237 filebench_log(LOG_ERROR, "Freeing type %d %zx", type, addr); 5235184Sek110237 return; 5245184Sek110237 } 5255184Sek110237 5265184Sek110237 switch (type) { 5275184Sek110237 5285184Sek110237 case FILEBENCH_FILESET: 5295184Sek110237 base = (caddr_t)&filebench_shm->fileset[0]; 5305184Sek110237 size = sizeof (fileset_t); 5315184Sek110237 break; 5325184Sek110237 5335184Sek110237 case FILEBENCH_FILESETENTRY: 5345184Sek110237 base = (caddr_t)&filebench_shm->filesetentry[0]; 5355184Sek110237 size = sizeof (filesetentry_t); 5365184Sek110237 break; 5375184Sek110237 5385184Sek110237 case FILEBENCH_PROCFLOW: 5395184Sek110237 base = (caddr_t)&filebench_shm->procflow[0]; 5405184Sek110237 size = sizeof (procflow_t); 5415184Sek110237 break; 5425184Sek110237 5435184Sek110237 case FILEBENCH_THREADFLOW: 5445184Sek110237 base = (caddr_t)&filebench_shm->threadflow[0]; 5455184Sek110237 size = sizeof (threadflow_t); 5465184Sek110237 break; 5475184Sek110237 5485184Sek110237 case FILEBENCH_FLOWOP: 5495184Sek110237 base = (caddr_t)&filebench_shm->flowop[0]; 5505184Sek110237 size = sizeof (flowop_t); 5515184Sek110237 break; 5525184Sek110237 553*6212Saw148015 case FILEBENCH_AVD: 554*6212Saw148015 base = (caddr_t)&filebench_shm->shm_avd_ptrs[0]; 555*6212Saw148015 size = sizeof (avd_t); 5565184Sek110237 break; 5575184Sek110237 5585184Sek110237 case FILEBENCH_VARIABLE: 5595184Sek110237 base = (caddr_t)&filebench_shm->var[0]; 5605184Sek110237 size = sizeof (var_t); 5615184Sek110237 break; 562*6212Saw148015 563*6212Saw148015 case FILEBENCH_RANDDIST: 564*6212Saw148015 base = (caddr_t)&filebench_shm->shm_randdist[0]; 565*6212Saw148015 size = sizeof (randdist_t); 566*6212Saw148015 break; 5675184Sek110237 } 5685184Sek110237 5695184Sek110237 offset = ((size_t)addr - (size_t)base); 5705184Sek110237 item = offset / size; 5715184Sek110237 5725184Sek110237 (void) ipc_mutex_lock(&filebench_shm->malloc_lock); 5735184Sek110237 filebench_shm->bitmap[type][item] = 0; 5745184Sek110237 (void) ipc_mutex_unlock(&filebench_shm->malloc_lock); 5755184Sek110237 } 5765184Sek110237 5775184Sek110237 /* 5785184Sek110237 * Allocate a string from filebench string memory. The length 5795184Sek110237 * of the allocated string is the same as the length of the 5805184Sek110237 * supplied string "string", and the contents of string are 5815184Sek110237 * copied to the newly allocated string. 5825184Sek110237 */ 5835184Sek110237 char * 5845184Sek110237 ipc_stralloc(char *string) 5855184Sek110237 { 5865184Sek110237 char *allocstr = filebench_shm->string_ptr; 5875184Sek110237 5885184Sek110237 filebench_shm->string_ptr += strlen(string) + 1; 5895184Sek110237 5905184Sek110237 if ((filebench_shm->string_ptr - &filebench_shm->strings[0]) > 5915184Sek110237 FILEBENCH_STRINGMEMORY) { 5925184Sek110237 filebench_log(LOG_ERROR, "Out of ipc string memory"); 5935184Sek110237 return (NULL); 5945184Sek110237 } 5955184Sek110237 5965184Sek110237 (void) strncpy(allocstr, string, strlen(string)); 5975184Sek110237 5985184Sek110237 return (allocstr); 5995184Sek110237 } 6005184Sek110237 6015184Sek110237 /* 6025184Sek110237 * Allocate a path string from filebench path string memory. 6035184Sek110237 * Specifically used for allocating fileset paths. The length 6045184Sek110237 * of the allocated path string is the same as the length of 6055184Sek110237 * the supplied path string "path", and the contents of path 6065184Sek110237 * are copied to the newly allocated path string. Checks for 6075184Sek110237 * out-of-path-string-memory condition and returns NULL if so. 6085184Sek110237 * Otherwise it returns a pointer to the newly allocated path 6095184Sek110237 * string. 6105184Sek110237 */ 6115184Sek110237 char * 6125184Sek110237 ipc_pathalloc(char *path) 6135184Sek110237 { 6145184Sek110237 char *allocpath = filebench_shm->path_ptr; 6155184Sek110237 6165184Sek110237 filebench_shm->path_ptr += strlen(path) + 1; 6175184Sek110237 6185184Sek110237 if ((filebench_shm->path_ptr - &filebench_shm->filesetpaths[0]) > 6195184Sek110237 FILEBENCH_FILESETPATHMEMORY) { 6205184Sek110237 filebench_log(LOG_ERROR, "Out of fileset path memory"); 6215184Sek110237 return (NULL); 6225184Sek110237 } 6235184Sek110237 6245184Sek110237 (void) strncpy(allocpath, path, strlen(path)); 6255184Sek110237 6265184Sek110237 return (allocpath); 6275184Sek110237 } 6285184Sek110237 6295184Sek110237 /* 6305184Sek110237 * This is a limited functionality deallocator for path 6315184Sek110237 * strings - it can only free all path strings at once, 6325184Sek110237 * in order to avoid fragmentation. 6335184Sek110237 */ 6345184Sek110237 void 6355184Sek110237 ipc_freepaths(void) 6365184Sek110237 { 6375184Sek110237 filebench_shm->path_ptr = &filebench_shm->filesetpaths[0]; 6385184Sek110237 } 6395184Sek110237 6405184Sek110237 /* 6415184Sek110237 * Allocates a semid from the table of semids for pre intialized 6425184Sek110237 * semaphores. Searches for the first available semaphore, and 6435184Sek110237 * sets the entry in the table to "1" to indicate allocation. 6445184Sek110237 * Returns the allocated semid. Stops the run if all semaphores 6455184Sek110237 * are already in use. 6465184Sek110237 */ 6475184Sek110237 int 6485184Sek110237 ipc_semidalloc(void) 6495184Sek110237 { 6505184Sek110237 int semid; 6515184Sek110237 6525184Sek110237 for (semid = 0; filebench_shm->semids[semid] == 1; semid++) 6535184Sek110237 ; 6545184Sek110237 if (semid == FILEBENCH_NSEMS) { 6555184Sek110237 filebench_log(LOG_ERROR, 6565184Sek110237 "Out of semaphores, increase system tunable limit"); 6575184Sek110237 filebench_shutdown(1); 6585184Sek110237 } 6595184Sek110237 filebench_shm->semids[semid] = 1; 6605184Sek110237 return (semid); 6615184Sek110237 } 6625184Sek110237 6635184Sek110237 /* 6645184Sek110237 * Frees up the supplied semid by seting its position in the 6655184Sek110237 * allocation table to "0". 6665184Sek110237 */ 6675184Sek110237 void 6685184Sek110237 ipc_semidfree(int semid) 6695184Sek110237 { 6705184Sek110237 filebench_shm->semids[semid] = 0; 6715184Sek110237 } 6725184Sek110237 6735184Sek110237 /* 6745184Sek110237 * Create a pool of shared memory to fit the per-thread 6755184Sek110237 * allocations. Uses shmget() to create a shared memory region 6765184Sek110237 * of size "size", attaches to it using shmat(), and stores 6775184Sek110237 * the returned address of the region in filebench_shm->shm_addr. 6785184Sek110237 * The pool is only created on the first call. The routine 6795184Sek110237 * returns 0 if successful or the pool already exists, 6805184Sek110237 * -1 otherwise. 6815184Sek110237 */ 6825184Sek110237 int 6835184Sek110237 ipc_ismcreate(size_t size) 6845184Sek110237 { 6855184Sek110237 #ifdef HAVE_SHM_SHARE_MMU 6865184Sek110237 int flag = SHM_SHARE_MMU; 6875184Sek110237 #else 6885184Sek110237 int flag = 0; 6895184Sek110237 #endif /* HAVE_SHM_SHARE_MMU */ 6905184Sek110237 6915184Sek110237 /* Already done? */ 6925184Sek110237 if (filebench_shm->shm_id != -1) 6935184Sek110237 return (0); 6945184Sek110237 6955184Sek110237 filebench_log(LOG_VERBOSE, 6965184Sek110237 "Creating %zd bytes of ISM Shared Memory...", size); 6975184Sek110237 6985184Sek110237 if ((filebench_shm->shm_id = 6995184Sek110237 shmget(0, size, IPC_CREAT | 0666)) == -1) { 7005184Sek110237 filebench_log(LOG_ERROR, 7015184Sek110237 "Failed to create %zd bytes of ISM shared memory", size); 7025184Sek110237 return (-1); 7035184Sek110237 } 7045184Sek110237 7055184Sek110237 if ((filebench_shm->shm_addr = (caddr_t)shmat(filebench_shm->shm_id, 7065184Sek110237 0, flag)) == (void *)-1) { 7075184Sek110237 filebench_log(LOG_ERROR, 7085184Sek110237 "Failed to attach %zd bytes of created ISM shared memory", 7095184Sek110237 size); 7105184Sek110237 return (-1); 7115184Sek110237 } 7125184Sek110237 7135184Sek110237 filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr; 7145184Sek110237 7155184Sek110237 filebench_log(LOG_VERBOSE, 7165184Sek110237 "Allocated %zd bytes of ISM Shared Memory... at %zx", 7175184Sek110237 size, filebench_shm->shm_addr); 7185184Sek110237 7195184Sek110237 /* Locked until allocated to block allocs */ 7205184Sek110237 (void) ipc_mutex_unlock(&filebench_shm->ism_lock); 7215184Sek110237 7225184Sek110237 return (0); 7235184Sek110237 } 7245184Sek110237 7255184Sek110237 /* Per addr space ism */ 7265184Sek110237 static int ism_attached = 0; 7275184Sek110237 7285184Sek110237 /* 7295184Sek110237 * Attach to interprocess shared memory. If already attached 7305184Sek110237 * just return, otherwise use shmat() to attached to the region 7315184Sek110237 * with ID of filebench_shm->shm_id. Returns -1 if shmat() 7325184Sek110237 * fails, otherwise 0. 7335184Sek110237 */ 7345184Sek110237 static int 7355184Sek110237 ipc_ismattach(void) 7365184Sek110237 { 7375184Sek110237 #ifdef HAVE_SHM_SHARE_MMU 7385184Sek110237 int flag = SHM_SHARE_MMU; 7395184Sek110237 #else 7405184Sek110237 int flag = 0; 7415184Sek110237 #endif /* HAVE_SHM_SHARE_MMU */ 7425184Sek110237 7435184Sek110237 7445184Sek110237 if (ism_attached) 7455184Sek110237 return (0); 7465184Sek110237 7475184Sek110237 /* Does it exist? */ 7485184Sek110237 if (filebench_shm->shm_id == 999) 7495184Sek110237 return (0); 7505184Sek110237 7515184Sek110237 if (shmat(filebench_shm->shm_id, filebench_shm->shm_addr, 7525184Sek110237 flag) == NULL) 7535184Sek110237 return (-1); 7545184Sek110237 7555184Sek110237 ism_attached = 1; 7565184Sek110237 7575184Sek110237 return (0); 7585184Sek110237 } 7595184Sek110237 7605184Sek110237 /* 7615184Sek110237 * Allocate from interprocess shared memory. Attaches to ism 7625184Sek110237 * if necessary, then allocates "size" bytes, updates allocation 7635184Sek110237 * information and returns a pointer to the allocated memory. 7645184Sek110237 */ 7655184Sek110237 /* 7665184Sek110237 * XXX No check is made for out-of-memory condition 7675184Sek110237 */ 7685184Sek110237 char * 7695184Sek110237 ipc_ismmalloc(size_t size) 7705184Sek110237 { 7715184Sek110237 char *allocstr; 7725184Sek110237 7735184Sek110237 (void) ipc_mutex_lock(&filebench_shm->ism_lock); 7745184Sek110237 7755184Sek110237 /* Map in shared memory */ 7765184Sek110237 (void) ipc_ismattach(); 7775184Sek110237 7785184Sek110237 allocstr = filebench_shm->shm_ptr; 7795184Sek110237 7805184Sek110237 filebench_shm->shm_ptr += size; 7815184Sek110237 filebench_shm->shm_allocated += size; 7825184Sek110237 7835184Sek110237 (void) ipc_mutex_unlock(&filebench_shm->ism_lock); 7845184Sek110237 7855184Sek110237 return (allocstr); 7865184Sek110237 } 7875184Sek110237 7885184Sek110237 /* 7895184Sek110237 * Deletes shared memory region and resets shared memory region 7905184Sek110237 * information in filebench_shm. 7915184Sek110237 */ 7925184Sek110237 void 7935184Sek110237 ipc_ismdelete(void) 7945184Sek110237 { 7955184Sek110237 if (filebench_shm->shm_id == -1) 7965184Sek110237 return; 7975184Sek110237 7985184Sek110237 filebench_log(LOG_VERBOSE, "Deleting ISM..."); 7995184Sek110237 8005184Sek110237 (void) ipc_mutex_lock(&filebench_shm->ism_lock); 8015184Sek110237 #ifdef HAVE_SEM_RMID 8025184Sek110237 (void) shmctl(filebench_shm->shm_id, IPC_RMID, 0); 8035184Sek110237 #endif 8045184Sek110237 filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr; 8055184Sek110237 filebench_shm->shm_id = -1; 8065184Sek110237 filebench_shm->shm_allocated = 0; 8075184Sek110237 (void) ipc_mutex_unlock(&filebench_shm->ism_lock); 8085184Sek110237 } 809