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 { 2376391Saw148015 key_t key = filebench_shm->shm_semkey; 2386391Saw148015 int sys_semid; 2395184Sek110237 2405184Sek110237 /* Already done? */ 2416391Saw148015 if (filebench_shm->shm_sys_semid >= 0) 2425184Sek110237 return; 2435184Sek110237 2446391Saw148015 if ((sys_semid = semget(key, FILEBENCH_NSEMS, IPC_CREAT | 2455184Sek110237 S_IRUSR | S_IWUSR)) == -1) { 2465184Sek110237 filebench_log(LOG_ERROR, 2475184Sek110237 "could not create sysv semaphore set " 2485184Sek110237 "(need to increase sems?): %s", 2495184Sek110237 strerror(errno)); 2506391Saw148015 filebench_shutdown(1); 2515184Sek110237 } 2526391Saw148015 2536391Saw148015 filebench_shm->shm_sys_semid = sys_semid; 2545184Sek110237 } 2555184Sek110237 2565184Sek110237 /* 2575184Sek110237 * Initialize the Interprocess Communication system and its 2585184Sek110237 * associated shared memory structure. It first creates a 2595184Sek110237 * temporary file using either the mkstemp() function or the 2605184Sek110237 * tempnam() and open() functions. If the process model is in 2615184Sek110237 * use,it than sets the file large enough to hold the 2625184Sek110237 * filebench_shm and an additional Megabyte. The file is then 2635184Sek110237 * memory mapped. If the process model is not in use, it simply 2645184Sek110237 * mallocs a region of sizeof (filebench_shm_t). 2655184Sek110237 * 2665184Sek110237 * Once the shared memory region / file is created, ipc_init 2675184Sek110237 * initializes various locks pointers, and variables in the 2685184Sek110237 * shared memory. It also uses ftok() to get a shared memory 2695184Sek110237 * semaphore key for later use in allocating shared semaphores. 2705184Sek110237 */ 2715184Sek110237 void 2725184Sek110237 ipc_init(void) 2735184Sek110237 { 2745184Sek110237 filebench_shm_t *buf = malloc(MB); 2755184Sek110237 key_t key; 2765184Sek110237 caddr_t c1; 2775184Sek110237 caddr_t c2; 2785184Sek110237 #ifdef HAVE_SEM_RMID 2796391Saw148015 int sys_semid; 2805184Sek110237 #endif 2815184Sek110237 2825184Sek110237 #ifdef HAVE_MKSTEMP 2835184Sek110237 shmpath = (char *)malloc(128); 2845184Sek110237 (void) strcpy(shmpath, "/var/tmp/fbenchXXXXXX"); 2855184Sek110237 shmfd = mkstemp(shmpath); 2865184Sek110237 #else 2875184Sek110237 shmfd = open(shmpath, O_CREAT | O_RDWR | O_TRUNC, 0666); 2885184Sek110237 shmpath = tempnam("/var/tmp", "fbench"); 2895184Sek110237 #endif /* HAVE_MKSTEMP */ 2905184Sek110237 2915184Sek110237 #ifdef USE_PROCESS_MODEL 2925184Sek110237 2935184Sek110237 if (shmfd < 0) { 2945184Sek110237 filebench_log(LOG_FATAL, "Cannot open shm %s: %s", 2955184Sek110237 shmpath, 2965184Sek110237 strerror(errno)); 2975184Sek110237 exit(1); 2985184Sek110237 } 2995184Sek110237 3005184Sek110237 (void) lseek(shmfd, sizeof (filebench_shm_t), SEEK_SET); 3015184Sek110237 if (write(shmfd, buf, MB) != MB) { 3025184Sek110237 filebench_log(LOG_FATAL, 3035184Sek110237 "Cannot allocate shm: %s", strerror(errno)); 3045184Sek110237 exit(1); 3055184Sek110237 } 3065184Sek110237 3075184Sek110237 /* LINTED E_BAD_PTR_CAST_ALIGN */ 3085184Sek110237 if ((filebench_shm = (filebench_shm_t *)mmap((caddr_t)0, 3095673Saw148015 sizeof (filebench_shm_t), PROT_READ | PROT_WRITE, 3105673Saw148015 MAP_SHARED, shmfd, 0)) == NULL) { 3115184Sek110237 filebench_log(LOG_FATAL, "Cannot mmap shm"); 3125184Sek110237 exit(1); 3135184Sek110237 } 3145184Sek110237 3155184Sek110237 #else 3165184Sek110237 if ((filebench_shm = 3175184Sek110237 (filebench_shm_t *)malloc(sizeof (filebench_shm_t))) == NULL) { 3185184Sek110237 filebench_log(LOG_FATAL, "Cannot malloc shm"); 3195184Sek110237 exit(1); 3205184Sek110237 } 3215184Sek110237 #endif /* USE_PROCESS_MODEL */ 3225184Sek110237 3235184Sek110237 c1 = (caddr_t)filebench_shm; 3246305Saw148015 c2 = (caddr_t)&filebench_shm->shm_marker; 3255184Sek110237 3265184Sek110237 (void) memset(filebench_shm, 0, c2 - c1); 3276391Saw148015 filebench_shm->shm_epoch = gethrtime(); 3286391Saw148015 filebench_shm->shm_debug_level = LOG_VERBOSE; 3296084Saw148015 filebench_shm->shm_rmode = FILEBENCH_MODE_TIMEOUT; 3306305Saw148015 filebench_shm->shm_string_ptr = &filebench_shm->shm_strings[0]; 3315184Sek110237 filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr; 3326305Saw148015 filebench_shm->shm_path_ptr = &filebench_shm->shm_filesetpaths[0]; 3335184Sek110237 3345184Sek110237 /* Setup mutexes for object lists */ 3356391Saw148015 (void) pthread_mutex_init(&filebench_shm->shm_fileset_lock, 3365184Sek110237 ipc_mutexattr()); 3376391Saw148015 (void) pthread_mutex_init(&filebench_shm->shm_procflow_lock, 3386391Saw148015 ipc_mutexattr()); 339*6701Saw148015 (void) pthread_mutex_init(&filebench_shm->shm_procs_running_lock, 340*6701Saw148015 ipc_mutexattr()); 3416391Saw148015 (void) pthread_mutex_init(&filebench_shm->shm_threadflow_lock, 3425184Sek110237 ipc_mutexattr()); 3436391Saw148015 (void) pthread_mutex_init(&filebench_shm->shm_flowop_lock, 3445184Sek110237 ipc_mutexattr()); 3456391Saw148015 (void) pthread_mutex_init(&filebench_shm->shm_msg_lock, 3466391Saw148015 ipc_mutexattr()); 3476391Saw148015 (void) pthread_mutex_init(&filebench_shm->shm_eventgen_lock, 3485184Sek110237 ipc_mutexattr()); 3496305Saw148015 (void) pthread_mutex_init(&filebench_shm->shm_malloc_lock, 3506305Saw148015 ipc_mutexattr()); 3516305Saw148015 (void) pthread_mutex_init(&filebench_shm->shm_ism_lock, 3526305Saw148015 ipc_mutexattr()); 3536391Saw148015 (void) pthread_cond_init(&filebench_shm->shm_eventgen_cv, 3546391Saw148015 ipc_condattr()); 3556391Saw148015 (void) pthread_rwlock_init(&filebench_shm->shm_flowop_find_lock, 3565184Sek110237 ipc_rwlockattr()); 3576391Saw148015 (void) pthread_rwlock_init(&filebench_shm->shm_run_lock, 3586391Saw148015 ipc_rwlockattr()); 3596391Saw148015 (void) pthread_rwlock_rdlock(&filebench_shm->shm_run_lock); 3605184Sek110237 3616305Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_ism_lock); 3625184Sek110237 3635184Sek110237 /* Create semaphore */ 3645184Sek110237 if ((key = ftok(shmpath, 1)) < 0) { 3655184Sek110237 filebench_log(LOG_ERROR, "cannot create sem: %s", 3665184Sek110237 strerror(errno)); 3675184Sek110237 exit(1); 3685184Sek110237 } 3695184Sek110237 3705184Sek110237 #ifdef HAVE_SEM_RMID 3716391Saw148015 if ((sys_semid = semget(key, 0, 0)) != -1) 3726391Saw148015 (void) semctl(sys_semid, 0, IPC_RMID); 3735184Sek110237 #endif 3745184Sek110237 3756391Saw148015 filebench_shm->shm_semkey = key; 3766391Saw148015 filebench_shm->shm_sys_semid = -1; 3776391Saw148015 filebench_shm->shm_log_fd = -1; 3786391Saw148015 filebench_shm->shm_dump_fd = -1; 3796391Saw148015 filebench_shm->shm_eventgen_hz = 0; 3805184Sek110237 filebench_shm->shm_id = -1; 3815184Sek110237 3825184Sek110237 free(buf); 3835184Sek110237 } 3845184Sek110237 3855184Sek110237 /* 3865184Sek110237 * If compiled to use process model, just unlinks the shmpath. 3875184Sek110237 * Otherwise a no-op. 3885184Sek110237 */ 3895184Sek110237 void 3905184Sek110237 ipc_cleanup(void) 3915184Sek110237 { 3925184Sek110237 #ifdef USE_PROCESS_MODEL 3935184Sek110237 (void) unlink(shmpath); 3945184Sek110237 #endif /* USE_PROCESS_MODEL */ 3955184Sek110237 } 3965184Sek110237 3975184Sek110237 /* 3985184Sek110237 * Attach to shared memory. Used by worker processes to open 3995184Sek110237 * and mmap the shared memory region. If successful, it 4005184Sek110237 * initializes the worker process' filebench_shm to point to 4015184Sek110237 * the region and returns 0. Otherwise it returns -1. 4025184Sek110237 */ 4035184Sek110237 int 4045184Sek110237 ipc_attach(caddr_t shmaddr) 4055184Sek110237 { 4065184Sek110237 if ((shmfd = open(shmpath, O_RDWR, 0666)) < 0) { 4075184Sek110237 filebench_log(LOG_ERROR, "Cannot open shm"); 4085184Sek110237 return (-1); 4095184Sek110237 } 4105184Sek110237 4115184Sek110237 /* LINTED E_BAD_PTR_CAST_ALIGN */ 4125184Sek110237 if ((filebench_shm = (filebench_shm_t *)mmap(shmaddr, 4135184Sek110237 sizeof (filebench_shm_t), PROT_READ | PROT_WRITE, 4145184Sek110237 MAP_SHARED | MAP_FIXED, shmfd, 0)) == NULL) { 4155184Sek110237 filebench_log(LOG_ERROR, "Cannot mmap shm"); 4165184Sek110237 return (-1); 4175184Sek110237 } 4185184Sek110237 4195184Sek110237 filebench_log(LOG_DEBUG_IMPL, "addr = %zx", filebench_shm); 4205184Sek110237 4215184Sek110237 return (0); 4225184Sek110237 } 4235184Sek110237 4245184Sek110237 static int filebench_sizes[] = { 4256212Saw148015 FILEBENCH_NPROCFLOWS, /* number of procflows */ 4266212Saw148015 FILEBENCH_NTHREADFLOWS, /* number of threadflows */ 4276212Saw148015 FILEBENCH_NFLOWOPS, /* number of flowops */ 4286212Saw148015 (FILEBENCH_NVARS * 2), /* number of attribute value dscrs */ 4296212Saw148015 FILEBENCH_NVARS, /* number of variables */ 4306212Saw148015 FILEBENCH_NFILESETS, /* number of filesets */ 4316212Saw148015 FILEBENCH_NFILESETENTRIES, /* number of fileset entries */ 4326212Saw148015 FILEBENCH_NRANDDISTS}; /* number of random distributions */ 4335184Sek110237 4345184Sek110237 /* 4355184Sek110237 * Allocates filebench objects from pre allocated region of 4365184Sek110237 * shareable memory. The memory region is partitioned into sets 4375184Sek110237 * of objects during initialization. This routine scans for 4385184Sek110237 * the first unallocated object of type "type" in the set of 4395184Sek110237 * available objects, and makes it as allocated. The routine 4405184Sek110237 * returns a pointer to the object, or NULL if all objects have 4415184Sek110237 * been allocated. 4425184Sek110237 */ 4435184Sek110237 void * 4445184Sek110237 ipc_malloc(int type) 4455184Sek110237 { 4465184Sek110237 int i; 4475184Sek110237 int max = filebench_sizes[type]; 4486305Saw148015 int start_idx = filebench_shm->shm_lastbitmapindex[type]; 4495184Sek110237 4506305Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_malloc_lock); 4515184Sek110237 4526305Saw148015 i = start_idx; 4536305Saw148015 do { 4546305Saw148015 i++; 4556305Saw148015 if (i >= max) 4566305Saw148015 i = 0; 4576305Saw148015 4586305Saw148015 if (filebench_shm->shm_bitmap[type][i] == 0) 4595184Sek110237 break; 4606305Saw148015 4616305Saw148015 } while (i != start_idx); 4625184Sek110237 4636305Saw148015 if (i == start_idx) { 4645184Sek110237 filebench_log(LOG_ERROR, "Out of shared memory (%d)!", type); 4656305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 4665184Sek110237 return (NULL); 4675184Sek110237 } 4685184Sek110237 4696305Saw148015 filebench_shm->shm_bitmap[type][i] = 1; 4706305Saw148015 filebench_shm->shm_lastbitmapindex[type] = i; 4715184Sek110237 4725184Sek110237 switch (type) { 4735184Sek110237 case FILEBENCH_FILESET: 4746305Saw148015 (void) memset((char *)&filebench_shm->shm_fileset[i], 0, 4755184Sek110237 sizeof (fileset_t)); 4766305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 4776305Saw148015 return ((char *)&filebench_shm->shm_fileset[i]); 4785184Sek110237 4795184Sek110237 case FILEBENCH_FILESETENTRY: 4806305Saw148015 (void) memset((char *)&filebench_shm->shm_filesetentry[i], 0, 4815184Sek110237 sizeof (filesetentry_t)); 4826305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 4836305Saw148015 return ((char *)&filebench_shm->shm_filesetentry[i]); 4845184Sek110237 4855184Sek110237 case FILEBENCH_PROCFLOW: 4866305Saw148015 (void) memset((char *)&filebench_shm->shm_procflow[i], 0, 4875184Sek110237 sizeof (procflow_t)); 4886305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 4896305Saw148015 return ((char *)&filebench_shm->shm_procflow[i]); 4905184Sek110237 4915184Sek110237 case FILEBENCH_THREADFLOW: 4926305Saw148015 (void) memset((char *)&filebench_shm->shm_threadflow[i], 0, 4935184Sek110237 sizeof (threadflow_t)); 4946305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 4956305Saw148015 return ((char *)&filebench_shm->shm_threadflow[i]); 4965184Sek110237 4975184Sek110237 case FILEBENCH_FLOWOP: 4986305Saw148015 (void) memset((char *)&filebench_shm->shm_flowop[i], 0, 4995184Sek110237 sizeof (flowop_t)); 5006305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 5016305Saw148015 return ((char *)&filebench_shm->shm_flowop[i]); 5025184Sek110237 5036212Saw148015 case FILEBENCH_AVD: 5046212Saw148015 filebench_shm->shm_avd_ptrs[i].avd_type = AVD_INVALID; 5056212Saw148015 filebench_shm->shm_avd_ptrs[i].avd_val.varptr = NULL; 5066305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 5076212Saw148015 return ((char *)&filebench_shm->shm_avd_ptrs[i]); 5085184Sek110237 5095184Sek110237 case FILEBENCH_VARIABLE: 5106305Saw148015 (void) memset((char *)&filebench_shm->shm_var[i], 0, 5115184Sek110237 sizeof (var_t)); 5126305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 5136305Saw148015 return ((char *)&filebench_shm->shm_var[i]); 5146212Saw148015 5156212Saw148015 case FILEBENCH_RANDDIST: 5166212Saw148015 (void) memset((char *)&filebench_shm->shm_randdist[i], 0, 5176212Saw148015 sizeof (randdist_t)); 5186305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 5196212Saw148015 return ((char *)&filebench_shm->shm_randdist[i]); 5205184Sek110237 } 5215184Sek110237 5225184Sek110237 filebench_log(LOG_ERROR, "Attempt to ipc_malloc unknown type (%d)!", 5235184Sek110237 type); 5245184Sek110237 return (NULL); 5255184Sek110237 } 5265184Sek110237 5275184Sek110237 /* 5285184Sek110237 * Frees a filebench object of type "type" at the location 5295184Sek110237 * pointed to by "addr". It uses the type and address to 5305184Sek110237 * calculate which object is being freed, and clears its 5315184Sek110237 * allocation map entry. 5325184Sek110237 */ 5335184Sek110237 void 5345184Sek110237 ipc_free(int type, char *addr) 5355184Sek110237 { 5365184Sek110237 int item; 5375184Sek110237 caddr_t base; 5385184Sek110237 size_t offset; 5395184Sek110237 size_t size; 5405184Sek110237 5415184Sek110237 if (addr == NULL) { 5425184Sek110237 filebench_log(LOG_ERROR, "Freeing type %d %zx", type, addr); 5435184Sek110237 return; 5445184Sek110237 } 5455184Sek110237 5465184Sek110237 switch (type) { 5475184Sek110237 5485184Sek110237 case FILEBENCH_FILESET: 5496305Saw148015 base = (caddr_t)&filebench_shm->shm_fileset[0]; 5505184Sek110237 size = sizeof (fileset_t); 5515184Sek110237 break; 5525184Sek110237 5535184Sek110237 case FILEBENCH_FILESETENTRY: 5546305Saw148015 base = (caddr_t)&filebench_shm->shm_filesetentry[0]; 5555184Sek110237 size = sizeof (filesetentry_t); 5565184Sek110237 break; 5575184Sek110237 5585184Sek110237 case FILEBENCH_PROCFLOW: 5596305Saw148015 base = (caddr_t)&filebench_shm->shm_procflow[0]; 5605184Sek110237 size = sizeof (procflow_t); 5615184Sek110237 break; 5625184Sek110237 5635184Sek110237 case FILEBENCH_THREADFLOW: 5646305Saw148015 base = (caddr_t)&filebench_shm->shm_threadflow[0]; 5655184Sek110237 size = sizeof (threadflow_t); 5665184Sek110237 break; 5675184Sek110237 5685184Sek110237 case FILEBENCH_FLOWOP: 5696305Saw148015 base = (caddr_t)&filebench_shm->shm_flowop[0]; 5705184Sek110237 size = sizeof (flowop_t); 5715184Sek110237 break; 5725184Sek110237 5736212Saw148015 case FILEBENCH_AVD: 5746212Saw148015 base = (caddr_t)&filebench_shm->shm_avd_ptrs[0]; 5756212Saw148015 size = sizeof (avd_t); 5765184Sek110237 break; 5775184Sek110237 5785184Sek110237 case FILEBENCH_VARIABLE: 5796305Saw148015 base = (caddr_t)&filebench_shm->shm_var[0]; 5805184Sek110237 size = sizeof (var_t); 5815184Sek110237 break; 5826212Saw148015 5836212Saw148015 case FILEBENCH_RANDDIST: 5846212Saw148015 base = (caddr_t)&filebench_shm->shm_randdist[0]; 5856212Saw148015 size = sizeof (randdist_t); 5866212Saw148015 break; 5875184Sek110237 } 5885184Sek110237 5895184Sek110237 offset = ((size_t)addr - (size_t)base); 5905184Sek110237 item = offset / size; 5915184Sek110237 5926305Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_malloc_lock); 5936305Saw148015 filebench_shm->shm_bitmap[type][item] = 0; 5946305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 5955184Sek110237 } 5965184Sek110237 5975184Sek110237 /* 5985184Sek110237 * Allocate a string from filebench string memory. The length 5995184Sek110237 * of the allocated string is the same as the length of the 6005184Sek110237 * supplied string "string", and the contents of string are 6015184Sek110237 * copied to the newly allocated string. 6025184Sek110237 */ 6035184Sek110237 char * 6045184Sek110237 ipc_stralloc(char *string) 6055184Sek110237 { 6066305Saw148015 char *allocstr = filebench_shm->shm_string_ptr; 6075184Sek110237 6086305Saw148015 filebench_shm->shm_string_ptr += strlen(string) + 1; 6095184Sek110237 6106305Saw148015 if ((filebench_shm->shm_string_ptr - &filebench_shm->shm_strings[0]) > 6115184Sek110237 FILEBENCH_STRINGMEMORY) { 6125184Sek110237 filebench_log(LOG_ERROR, "Out of ipc string memory"); 6135184Sek110237 return (NULL); 6145184Sek110237 } 6155184Sek110237 6165184Sek110237 (void) strncpy(allocstr, string, strlen(string)); 6175184Sek110237 6185184Sek110237 return (allocstr); 6195184Sek110237 } 6205184Sek110237 6215184Sek110237 /* 6225184Sek110237 * Allocate a path string from filebench path string memory. 6235184Sek110237 * Specifically used for allocating fileset paths. The length 6245184Sek110237 * of the allocated path string is the same as the length of 6255184Sek110237 * the supplied path string "path", and the contents of path 6265184Sek110237 * are copied to the newly allocated path string. Checks for 6275184Sek110237 * out-of-path-string-memory condition and returns NULL if so. 6285184Sek110237 * Otherwise it returns a pointer to the newly allocated path 6295184Sek110237 * string. 6305184Sek110237 */ 6315184Sek110237 char * 6325184Sek110237 ipc_pathalloc(char *path) 6335184Sek110237 { 6346305Saw148015 char *allocpath = filebench_shm->shm_path_ptr; 6355184Sek110237 6366305Saw148015 filebench_shm->shm_path_ptr += strlen(path) + 1; 6375184Sek110237 6386305Saw148015 if ((filebench_shm->shm_path_ptr - 6396305Saw148015 &filebench_shm->shm_filesetpaths[0]) > 6405184Sek110237 FILEBENCH_FILESETPATHMEMORY) { 6415184Sek110237 filebench_log(LOG_ERROR, "Out of fileset path memory"); 6425184Sek110237 return (NULL); 6435184Sek110237 } 6445184Sek110237 6455184Sek110237 (void) strncpy(allocpath, path, strlen(path)); 6465184Sek110237 6475184Sek110237 return (allocpath); 6485184Sek110237 } 6495184Sek110237 6505184Sek110237 /* 6515184Sek110237 * This is a limited functionality deallocator for path 6525184Sek110237 * strings - it can only free all path strings at once, 6535184Sek110237 * in order to avoid fragmentation. 6545184Sek110237 */ 6555184Sek110237 void 6565184Sek110237 ipc_freepaths(void) 6575184Sek110237 { 6586305Saw148015 filebench_shm->shm_path_ptr = &filebench_shm->shm_filesetpaths[0]; 6595184Sek110237 } 6605184Sek110237 6615184Sek110237 /* 6625184Sek110237 * Allocates a semid from the table of semids for pre intialized 6635184Sek110237 * semaphores. Searches for the first available semaphore, and 6645184Sek110237 * sets the entry in the table to "1" to indicate allocation. 6655184Sek110237 * Returns the allocated semid. Stops the run if all semaphores 6665184Sek110237 * are already in use. 6675184Sek110237 */ 6685184Sek110237 int 6695184Sek110237 ipc_semidalloc(void) 6705184Sek110237 { 6715184Sek110237 int semid; 6725184Sek110237 6736391Saw148015 for (semid = 0; filebench_shm->shm_semids[semid] == 1; semid++) 6745184Sek110237 ; 6755184Sek110237 if (semid == FILEBENCH_NSEMS) { 6765184Sek110237 filebench_log(LOG_ERROR, 6775184Sek110237 "Out of semaphores, increase system tunable limit"); 6785184Sek110237 filebench_shutdown(1); 6795184Sek110237 } 6806391Saw148015 filebench_shm->shm_semids[semid] = 1; 6815184Sek110237 return (semid); 6825184Sek110237 } 6835184Sek110237 6845184Sek110237 /* 6855184Sek110237 * Frees up the supplied semid by seting its position in the 6865184Sek110237 * allocation table to "0". 6875184Sek110237 */ 6885184Sek110237 void 6895184Sek110237 ipc_semidfree(int semid) 6905184Sek110237 { 6916391Saw148015 filebench_shm->shm_semids[semid] = 0; 6925184Sek110237 } 6935184Sek110237 6945184Sek110237 /* 6955184Sek110237 * Create a pool of shared memory to fit the per-thread 6965184Sek110237 * allocations. Uses shmget() to create a shared memory region 6975184Sek110237 * of size "size", attaches to it using shmat(), and stores 6985184Sek110237 * the returned address of the region in filebench_shm->shm_addr. 6995184Sek110237 * The pool is only created on the first call. The routine 7005184Sek110237 * returns 0 if successful or the pool already exists, 7015184Sek110237 * -1 otherwise. 7025184Sek110237 */ 7035184Sek110237 int 7045184Sek110237 ipc_ismcreate(size_t size) 7055184Sek110237 { 7065184Sek110237 #ifdef HAVE_SHM_SHARE_MMU 7075184Sek110237 int flag = SHM_SHARE_MMU; 7085184Sek110237 #else 7095184Sek110237 int flag = 0; 7105184Sek110237 #endif /* HAVE_SHM_SHARE_MMU */ 7115184Sek110237 7125184Sek110237 /* Already done? */ 7135184Sek110237 if (filebench_shm->shm_id != -1) 7145184Sek110237 return (0); 7155184Sek110237 7165184Sek110237 filebench_log(LOG_VERBOSE, 7175184Sek110237 "Creating %zd bytes of ISM Shared Memory...", size); 7185184Sek110237 7195184Sek110237 if ((filebench_shm->shm_id = 7205184Sek110237 shmget(0, size, IPC_CREAT | 0666)) == -1) { 7215184Sek110237 filebench_log(LOG_ERROR, 7225184Sek110237 "Failed to create %zd bytes of ISM shared memory", size); 7235184Sek110237 return (-1); 7245184Sek110237 } 7255184Sek110237 7265184Sek110237 if ((filebench_shm->shm_addr = (caddr_t)shmat(filebench_shm->shm_id, 7275184Sek110237 0, flag)) == (void *)-1) { 7285184Sek110237 filebench_log(LOG_ERROR, 7295184Sek110237 "Failed to attach %zd bytes of created ISM shared memory", 7305184Sek110237 size); 7315184Sek110237 return (-1); 7325184Sek110237 } 7335184Sek110237 7345184Sek110237 filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr; 7355184Sek110237 7365184Sek110237 filebench_log(LOG_VERBOSE, 7375184Sek110237 "Allocated %zd bytes of ISM Shared Memory... at %zx", 7385184Sek110237 size, filebench_shm->shm_addr); 7395184Sek110237 7405184Sek110237 /* Locked until allocated to block allocs */ 7416305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_ism_lock); 7425184Sek110237 7435184Sek110237 return (0); 7445184Sek110237 } 7455184Sek110237 7465184Sek110237 /* Per addr space ism */ 7475184Sek110237 static int ism_attached = 0; 7485184Sek110237 7495184Sek110237 /* 7505184Sek110237 * Attach to interprocess shared memory. If already attached 7515184Sek110237 * just return, otherwise use shmat() to attached to the region 7525184Sek110237 * with ID of filebench_shm->shm_id. Returns -1 if shmat() 7535184Sek110237 * fails, otherwise 0. 7545184Sek110237 */ 7555184Sek110237 static int 7565184Sek110237 ipc_ismattach(void) 7575184Sek110237 { 7585184Sek110237 #ifdef HAVE_SHM_SHARE_MMU 7595184Sek110237 int flag = SHM_SHARE_MMU; 7605184Sek110237 #else 7615184Sek110237 int flag = 0; 7625184Sek110237 #endif /* HAVE_SHM_SHARE_MMU */ 7635184Sek110237 7645184Sek110237 7655184Sek110237 if (ism_attached) 7665184Sek110237 return (0); 7675184Sek110237 7685184Sek110237 /* Does it exist? */ 7695184Sek110237 if (filebench_shm->shm_id == 999) 7705184Sek110237 return (0); 7715184Sek110237 7725184Sek110237 if (shmat(filebench_shm->shm_id, filebench_shm->shm_addr, 7735184Sek110237 flag) == NULL) 7745184Sek110237 return (-1); 7755184Sek110237 7765184Sek110237 ism_attached = 1; 7775184Sek110237 7785184Sek110237 return (0); 7795184Sek110237 } 7805184Sek110237 7815184Sek110237 /* 7825184Sek110237 * Allocate from interprocess shared memory. Attaches to ism 7835184Sek110237 * if necessary, then allocates "size" bytes, updates allocation 7845184Sek110237 * information and returns a pointer to the allocated memory. 7855184Sek110237 */ 7865184Sek110237 /* 7875184Sek110237 * XXX No check is made for out-of-memory condition 7885184Sek110237 */ 7895184Sek110237 char * 7905184Sek110237 ipc_ismmalloc(size_t size) 7915184Sek110237 { 7925184Sek110237 char *allocstr; 7935184Sek110237 7946305Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_ism_lock); 7955184Sek110237 7965184Sek110237 /* Map in shared memory */ 7975184Sek110237 (void) ipc_ismattach(); 7985184Sek110237 7995184Sek110237 allocstr = filebench_shm->shm_ptr; 8005184Sek110237 8015184Sek110237 filebench_shm->shm_ptr += size; 8025184Sek110237 filebench_shm->shm_allocated += size; 8035184Sek110237 8046305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_ism_lock); 8055184Sek110237 8065184Sek110237 return (allocstr); 8075184Sek110237 } 8085184Sek110237 8095184Sek110237 /* 8105184Sek110237 * Deletes shared memory region and resets shared memory region 8115184Sek110237 * information in filebench_shm. 8125184Sek110237 */ 8135184Sek110237 void 8145184Sek110237 ipc_ismdelete(void) 8155184Sek110237 { 8165184Sek110237 if (filebench_shm->shm_id == -1) 8175184Sek110237 return; 8185184Sek110237 8195184Sek110237 filebench_log(LOG_VERBOSE, "Deleting ISM..."); 8205184Sek110237 8216305Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_ism_lock); 8225184Sek110237 #ifdef HAVE_SEM_RMID 8235184Sek110237 (void) shmctl(filebench_shm->shm_id, IPC_RMID, 0); 8245184Sek110237 #endif 8255184Sek110237 filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr; 8265184Sek110237 filebench_shm->shm_id = -1; 8275184Sek110237 filebench_shm->shm_allocated = 0; 8286305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_ism_lock); 8295184Sek110237 } 830