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; 321*6305Saw148015 c2 = (caddr_t)&filebench_shm->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; 327*6305Saw148015 filebench_shm->shm_string_ptr = &filebench_shm->shm_strings[0]; 3285184Sek110237 filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr; 329*6305Saw148015 filebench_shm->shm_path_ptr = &filebench_shm->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()); 342*6305Saw148015 (void) pthread_mutex_init(&filebench_shm->shm_malloc_lock, 343*6305Saw148015 ipc_mutexattr()); 344*6305Saw148015 (void) pthread_mutex_init(&filebench_shm->shm_ism_lock, 345*6305Saw148015 ipc_mutexattr()); 3465184Sek110237 (void) pthread_cond_init(&filebench_shm->eventgen_cv, ipc_condattr()); 3475184Sek110237 (void) pthread_rwlock_init(&filebench_shm->flowop_find_lock, 3485184Sek110237 ipc_rwlockattr()); 3495184Sek110237 (void) pthread_rwlock_init(&filebench_shm->run_lock, ipc_rwlockattr()); 3505184Sek110237 (void) pthread_rwlock_rdlock(&filebench_shm->run_lock); 3515184Sek110237 352*6305Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_ism_lock); 3535184Sek110237 3545184Sek110237 /* Create semaphore */ 3555184Sek110237 if ((key = ftok(shmpath, 1)) < 0) { 3565184Sek110237 filebench_log(LOG_ERROR, "cannot create sem: %s", 3575184Sek110237 strerror(errno)); 3585184Sek110237 exit(1); 3595184Sek110237 } 3605184Sek110237 3615184Sek110237 #ifdef HAVE_SEM_RMID 3625184Sek110237 if ((semid = semget(key, 0, 0)) != -1) 3635184Sek110237 (void) semctl(semid, 0, IPC_RMID); 3645184Sek110237 #endif 3655184Sek110237 3665184Sek110237 filebench_shm->semkey = key; 3675184Sek110237 filebench_shm->log_fd = -1; 3685184Sek110237 filebench_shm->dump_fd = -1; 3695184Sek110237 filebench_shm->eventgen_hz = 0; 3705184Sek110237 filebench_shm->shm_id = -1; 3715184Sek110237 3725184Sek110237 free(buf); 3735184Sek110237 } 3745184Sek110237 3755184Sek110237 /* 3765184Sek110237 * If compiled to use process model, just unlinks the shmpath. 3775184Sek110237 * Otherwise a no-op. 3785184Sek110237 */ 3795184Sek110237 void 3805184Sek110237 ipc_cleanup(void) 3815184Sek110237 { 3825184Sek110237 #ifdef USE_PROCESS_MODEL 3835184Sek110237 (void) unlink(shmpath); 3845184Sek110237 #endif /* USE_PROCESS_MODEL */ 3855184Sek110237 } 3865184Sek110237 3875184Sek110237 /* 3885184Sek110237 * Attach to shared memory. Used by worker processes to open 3895184Sek110237 * and mmap the shared memory region. If successful, it 3905184Sek110237 * initializes the worker process' filebench_shm to point to 3915184Sek110237 * the region and returns 0. Otherwise it returns -1. 3925184Sek110237 */ 3935184Sek110237 int 3945184Sek110237 ipc_attach(caddr_t shmaddr) 3955184Sek110237 { 3965184Sek110237 if ((shmfd = open(shmpath, O_RDWR, 0666)) < 0) { 3975184Sek110237 filebench_log(LOG_ERROR, "Cannot open shm"); 3985184Sek110237 return (-1); 3995184Sek110237 } 4005184Sek110237 4015184Sek110237 /* LINTED E_BAD_PTR_CAST_ALIGN */ 4025184Sek110237 if ((filebench_shm = (filebench_shm_t *)mmap(shmaddr, 4035184Sek110237 sizeof (filebench_shm_t), PROT_READ | PROT_WRITE, 4045184Sek110237 MAP_SHARED | MAP_FIXED, shmfd, 0)) == NULL) { 4055184Sek110237 filebench_log(LOG_ERROR, "Cannot mmap shm"); 4065184Sek110237 return (-1); 4075184Sek110237 } 4085184Sek110237 4095184Sek110237 filebench_log(LOG_DEBUG_IMPL, "addr = %zx", filebench_shm); 4105184Sek110237 4115184Sek110237 return (0); 4125184Sek110237 } 4135184Sek110237 4145184Sek110237 static int filebench_sizes[] = { 4156212Saw148015 FILEBENCH_NPROCFLOWS, /* number of procflows */ 4166212Saw148015 FILEBENCH_NTHREADFLOWS, /* number of threadflows */ 4176212Saw148015 FILEBENCH_NFLOWOPS, /* number of flowops */ 4186212Saw148015 (FILEBENCH_NVARS * 2), /* number of attribute value dscrs */ 4196212Saw148015 FILEBENCH_NVARS, /* number of variables */ 4206212Saw148015 FILEBENCH_NFILESETS, /* number of filesets */ 4216212Saw148015 FILEBENCH_NFILESETENTRIES, /* number of fileset entries */ 4226212Saw148015 FILEBENCH_NRANDDISTS}; /* number of random distributions */ 4235184Sek110237 4245184Sek110237 /* 4255184Sek110237 * Allocates filebench objects from pre allocated region of 4265184Sek110237 * shareable memory. The memory region is partitioned into sets 4275184Sek110237 * of objects during initialization. This routine scans for 4285184Sek110237 * the first unallocated object of type "type" in the set of 4295184Sek110237 * available objects, and makes it as allocated. The routine 4305184Sek110237 * returns a pointer to the object, or NULL if all objects have 4315184Sek110237 * been allocated. 4325184Sek110237 */ 4335184Sek110237 void * 4345184Sek110237 ipc_malloc(int type) 4355184Sek110237 { 4365184Sek110237 int i; 4375184Sek110237 int max = filebench_sizes[type]; 438*6305Saw148015 int start_idx = filebench_shm->shm_lastbitmapindex[type]; 4395184Sek110237 440*6305Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_malloc_lock); 4415184Sek110237 442*6305Saw148015 i = start_idx; 443*6305Saw148015 do { 444*6305Saw148015 i++; 445*6305Saw148015 if (i >= max) 446*6305Saw148015 i = 0; 447*6305Saw148015 448*6305Saw148015 if (filebench_shm->shm_bitmap[type][i] == 0) 4495184Sek110237 break; 450*6305Saw148015 451*6305Saw148015 } while (i != start_idx); 4525184Sek110237 453*6305Saw148015 if (i == start_idx) { 4545184Sek110237 filebench_log(LOG_ERROR, "Out of shared memory (%d)!", type); 455*6305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 4565184Sek110237 return (NULL); 4575184Sek110237 } 4585184Sek110237 459*6305Saw148015 filebench_shm->shm_bitmap[type][i] = 1; 460*6305Saw148015 filebench_shm->shm_lastbitmapindex[type] = i; 4615184Sek110237 4625184Sek110237 switch (type) { 4635184Sek110237 case FILEBENCH_FILESET: 464*6305Saw148015 (void) memset((char *)&filebench_shm->shm_fileset[i], 0, 4655184Sek110237 sizeof (fileset_t)); 466*6305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 467*6305Saw148015 return ((char *)&filebench_shm->shm_fileset[i]); 4685184Sek110237 4695184Sek110237 case FILEBENCH_FILESETENTRY: 470*6305Saw148015 (void) memset((char *)&filebench_shm->shm_filesetentry[i], 0, 4715184Sek110237 sizeof (filesetentry_t)); 472*6305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 473*6305Saw148015 return ((char *)&filebench_shm->shm_filesetentry[i]); 4745184Sek110237 4755184Sek110237 case FILEBENCH_PROCFLOW: 476*6305Saw148015 (void) memset((char *)&filebench_shm->shm_procflow[i], 0, 4775184Sek110237 sizeof (procflow_t)); 478*6305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 479*6305Saw148015 return ((char *)&filebench_shm->shm_procflow[i]); 4805184Sek110237 4815184Sek110237 case FILEBENCH_THREADFLOW: 482*6305Saw148015 (void) memset((char *)&filebench_shm->shm_threadflow[i], 0, 4835184Sek110237 sizeof (threadflow_t)); 484*6305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 485*6305Saw148015 return ((char *)&filebench_shm->shm_threadflow[i]); 4865184Sek110237 4875184Sek110237 case FILEBENCH_FLOWOP: 488*6305Saw148015 (void) memset((char *)&filebench_shm->shm_flowop[i], 0, 4895184Sek110237 sizeof (flowop_t)); 490*6305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 491*6305Saw148015 return ((char *)&filebench_shm->shm_flowop[i]); 4925184Sek110237 4936212Saw148015 case FILEBENCH_AVD: 4946212Saw148015 filebench_shm->shm_avd_ptrs[i].avd_type = AVD_INVALID; 4956212Saw148015 filebench_shm->shm_avd_ptrs[i].avd_val.varptr = NULL; 496*6305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 4976212Saw148015 return ((char *)&filebench_shm->shm_avd_ptrs[i]); 4985184Sek110237 4995184Sek110237 case FILEBENCH_VARIABLE: 500*6305Saw148015 (void) memset((char *)&filebench_shm->shm_var[i], 0, 5015184Sek110237 sizeof (var_t)); 502*6305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 503*6305Saw148015 return ((char *)&filebench_shm->shm_var[i]); 5046212Saw148015 5056212Saw148015 case FILEBENCH_RANDDIST: 5066212Saw148015 (void) memset((char *)&filebench_shm->shm_randdist[i], 0, 5076212Saw148015 sizeof (randdist_t)); 508*6305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 5096212Saw148015 return ((char *)&filebench_shm->shm_randdist[i]); 5105184Sek110237 } 5115184Sek110237 5125184Sek110237 filebench_log(LOG_ERROR, "Attempt to ipc_malloc unknown type (%d)!", 5135184Sek110237 type); 5145184Sek110237 return (NULL); 5155184Sek110237 } 5165184Sek110237 5175184Sek110237 /* 5185184Sek110237 * Frees a filebench object of type "type" at the location 5195184Sek110237 * pointed to by "addr". It uses the type and address to 5205184Sek110237 * calculate which object is being freed, and clears its 5215184Sek110237 * allocation map entry. 5225184Sek110237 */ 5235184Sek110237 void 5245184Sek110237 ipc_free(int type, char *addr) 5255184Sek110237 { 5265184Sek110237 int item; 5275184Sek110237 caddr_t base; 5285184Sek110237 size_t offset; 5295184Sek110237 size_t size; 5305184Sek110237 5315184Sek110237 if (addr == NULL) { 5325184Sek110237 filebench_log(LOG_ERROR, "Freeing type %d %zx", type, addr); 5335184Sek110237 return; 5345184Sek110237 } 5355184Sek110237 5365184Sek110237 switch (type) { 5375184Sek110237 5385184Sek110237 case FILEBENCH_FILESET: 539*6305Saw148015 base = (caddr_t)&filebench_shm->shm_fileset[0]; 5405184Sek110237 size = sizeof (fileset_t); 5415184Sek110237 break; 5425184Sek110237 5435184Sek110237 case FILEBENCH_FILESETENTRY: 544*6305Saw148015 base = (caddr_t)&filebench_shm->shm_filesetentry[0]; 5455184Sek110237 size = sizeof (filesetentry_t); 5465184Sek110237 break; 5475184Sek110237 5485184Sek110237 case FILEBENCH_PROCFLOW: 549*6305Saw148015 base = (caddr_t)&filebench_shm->shm_procflow[0]; 5505184Sek110237 size = sizeof (procflow_t); 5515184Sek110237 break; 5525184Sek110237 5535184Sek110237 case FILEBENCH_THREADFLOW: 554*6305Saw148015 base = (caddr_t)&filebench_shm->shm_threadflow[0]; 5555184Sek110237 size = sizeof (threadflow_t); 5565184Sek110237 break; 5575184Sek110237 5585184Sek110237 case FILEBENCH_FLOWOP: 559*6305Saw148015 base = (caddr_t)&filebench_shm->shm_flowop[0]; 5605184Sek110237 size = sizeof (flowop_t); 5615184Sek110237 break; 5625184Sek110237 5636212Saw148015 case FILEBENCH_AVD: 5646212Saw148015 base = (caddr_t)&filebench_shm->shm_avd_ptrs[0]; 5656212Saw148015 size = sizeof (avd_t); 5665184Sek110237 break; 5675184Sek110237 5685184Sek110237 case FILEBENCH_VARIABLE: 569*6305Saw148015 base = (caddr_t)&filebench_shm->shm_var[0]; 5705184Sek110237 size = sizeof (var_t); 5715184Sek110237 break; 5726212Saw148015 5736212Saw148015 case FILEBENCH_RANDDIST: 5746212Saw148015 base = (caddr_t)&filebench_shm->shm_randdist[0]; 5756212Saw148015 size = sizeof (randdist_t); 5766212Saw148015 break; 5775184Sek110237 } 5785184Sek110237 5795184Sek110237 offset = ((size_t)addr - (size_t)base); 5805184Sek110237 item = offset / size; 5815184Sek110237 582*6305Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_malloc_lock); 583*6305Saw148015 filebench_shm->shm_bitmap[type][item] = 0; 584*6305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock); 5855184Sek110237 } 5865184Sek110237 5875184Sek110237 /* 5885184Sek110237 * Allocate a string from filebench string memory. The length 5895184Sek110237 * of the allocated string is the same as the length of the 5905184Sek110237 * supplied string "string", and the contents of string are 5915184Sek110237 * copied to the newly allocated string. 5925184Sek110237 */ 5935184Sek110237 char * 5945184Sek110237 ipc_stralloc(char *string) 5955184Sek110237 { 596*6305Saw148015 char *allocstr = filebench_shm->shm_string_ptr; 5975184Sek110237 598*6305Saw148015 filebench_shm->shm_string_ptr += strlen(string) + 1; 5995184Sek110237 600*6305Saw148015 if ((filebench_shm->shm_string_ptr - &filebench_shm->shm_strings[0]) > 6015184Sek110237 FILEBENCH_STRINGMEMORY) { 6025184Sek110237 filebench_log(LOG_ERROR, "Out of ipc string memory"); 6035184Sek110237 return (NULL); 6045184Sek110237 } 6055184Sek110237 6065184Sek110237 (void) strncpy(allocstr, string, strlen(string)); 6075184Sek110237 6085184Sek110237 return (allocstr); 6095184Sek110237 } 6105184Sek110237 6115184Sek110237 /* 6125184Sek110237 * Allocate a path string from filebench path string memory. 6135184Sek110237 * Specifically used for allocating fileset paths. The length 6145184Sek110237 * of the allocated path string is the same as the length of 6155184Sek110237 * the supplied path string "path", and the contents of path 6165184Sek110237 * are copied to the newly allocated path string. Checks for 6175184Sek110237 * out-of-path-string-memory condition and returns NULL if so. 6185184Sek110237 * Otherwise it returns a pointer to the newly allocated path 6195184Sek110237 * string. 6205184Sek110237 */ 6215184Sek110237 char * 6225184Sek110237 ipc_pathalloc(char *path) 6235184Sek110237 { 624*6305Saw148015 char *allocpath = filebench_shm->shm_path_ptr; 6255184Sek110237 626*6305Saw148015 filebench_shm->shm_path_ptr += strlen(path) + 1; 6275184Sek110237 628*6305Saw148015 if ((filebench_shm->shm_path_ptr - 629*6305Saw148015 &filebench_shm->shm_filesetpaths[0]) > 6305184Sek110237 FILEBENCH_FILESETPATHMEMORY) { 6315184Sek110237 filebench_log(LOG_ERROR, "Out of fileset path memory"); 6325184Sek110237 return (NULL); 6335184Sek110237 } 6345184Sek110237 6355184Sek110237 (void) strncpy(allocpath, path, strlen(path)); 6365184Sek110237 6375184Sek110237 return (allocpath); 6385184Sek110237 } 6395184Sek110237 6405184Sek110237 /* 6415184Sek110237 * This is a limited functionality deallocator for path 6425184Sek110237 * strings - it can only free all path strings at once, 6435184Sek110237 * in order to avoid fragmentation. 6445184Sek110237 */ 6455184Sek110237 void 6465184Sek110237 ipc_freepaths(void) 6475184Sek110237 { 648*6305Saw148015 filebench_shm->shm_path_ptr = &filebench_shm->shm_filesetpaths[0]; 6495184Sek110237 } 6505184Sek110237 6515184Sek110237 /* 6525184Sek110237 * Allocates a semid from the table of semids for pre intialized 6535184Sek110237 * semaphores. Searches for the first available semaphore, and 6545184Sek110237 * sets the entry in the table to "1" to indicate allocation. 6555184Sek110237 * Returns the allocated semid. Stops the run if all semaphores 6565184Sek110237 * are already in use. 6575184Sek110237 */ 6585184Sek110237 int 6595184Sek110237 ipc_semidalloc(void) 6605184Sek110237 { 6615184Sek110237 int semid; 6625184Sek110237 6635184Sek110237 for (semid = 0; filebench_shm->semids[semid] == 1; semid++) 6645184Sek110237 ; 6655184Sek110237 if (semid == FILEBENCH_NSEMS) { 6665184Sek110237 filebench_log(LOG_ERROR, 6675184Sek110237 "Out of semaphores, increase system tunable limit"); 6685184Sek110237 filebench_shutdown(1); 6695184Sek110237 } 6705184Sek110237 filebench_shm->semids[semid] = 1; 6715184Sek110237 return (semid); 6725184Sek110237 } 6735184Sek110237 6745184Sek110237 /* 6755184Sek110237 * Frees up the supplied semid by seting its position in the 6765184Sek110237 * allocation table to "0". 6775184Sek110237 */ 6785184Sek110237 void 6795184Sek110237 ipc_semidfree(int semid) 6805184Sek110237 { 6815184Sek110237 filebench_shm->semids[semid] = 0; 6825184Sek110237 } 6835184Sek110237 6845184Sek110237 /* 6855184Sek110237 * Create a pool of shared memory to fit the per-thread 6865184Sek110237 * allocations. Uses shmget() to create a shared memory region 6875184Sek110237 * of size "size", attaches to it using shmat(), and stores 6885184Sek110237 * the returned address of the region in filebench_shm->shm_addr. 6895184Sek110237 * The pool is only created on the first call. The routine 6905184Sek110237 * returns 0 if successful or the pool already exists, 6915184Sek110237 * -1 otherwise. 6925184Sek110237 */ 6935184Sek110237 int 6945184Sek110237 ipc_ismcreate(size_t size) 6955184Sek110237 { 6965184Sek110237 #ifdef HAVE_SHM_SHARE_MMU 6975184Sek110237 int flag = SHM_SHARE_MMU; 6985184Sek110237 #else 6995184Sek110237 int flag = 0; 7005184Sek110237 #endif /* HAVE_SHM_SHARE_MMU */ 7015184Sek110237 7025184Sek110237 /* Already done? */ 7035184Sek110237 if (filebench_shm->shm_id != -1) 7045184Sek110237 return (0); 7055184Sek110237 7065184Sek110237 filebench_log(LOG_VERBOSE, 7075184Sek110237 "Creating %zd bytes of ISM Shared Memory...", size); 7085184Sek110237 7095184Sek110237 if ((filebench_shm->shm_id = 7105184Sek110237 shmget(0, size, IPC_CREAT | 0666)) == -1) { 7115184Sek110237 filebench_log(LOG_ERROR, 7125184Sek110237 "Failed to create %zd bytes of ISM shared memory", size); 7135184Sek110237 return (-1); 7145184Sek110237 } 7155184Sek110237 7165184Sek110237 if ((filebench_shm->shm_addr = (caddr_t)shmat(filebench_shm->shm_id, 7175184Sek110237 0, flag)) == (void *)-1) { 7185184Sek110237 filebench_log(LOG_ERROR, 7195184Sek110237 "Failed to attach %zd bytes of created ISM shared memory", 7205184Sek110237 size); 7215184Sek110237 return (-1); 7225184Sek110237 } 7235184Sek110237 7245184Sek110237 filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr; 7255184Sek110237 7265184Sek110237 filebench_log(LOG_VERBOSE, 7275184Sek110237 "Allocated %zd bytes of ISM Shared Memory... at %zx", 7285184Sek110237 size, filebench_shm->shm_addr); 7295184Sek110237 7305184Sek110237 /* Locked until allocated to block allocs */ 731*6305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_ism_lock); 7325184Sek110237 7335184Sek110237 return (0); 7345184Sek110237 } 7355184Sek110237 7365184Sek110237 /* Per addr space ism */ 7375184Sek110237 static int ism_attached = 0; 7385184Sek110237 7395184Sek110237 /* 7405184Sek110237 * Attach to interprocess shared memory. If already attached 7415184Sek110237 * just return, otherwise use shmat() to attached to the region 7425184Sek110237 * with ID of filebench_shm->shm_id. Returns -1 if shmat() 7435184Sek110237 * fails, otherwise 0. 7445184Sek110237 */ 7455184Sek110237 static int 7465184Sek110237 ipc_ismattach(void) 7475184Sek110237 { 7485184Sek110237 #ifdef HAVE_SHM_SHARE_MMU 7495184Sek110237 int flag = SHM_SHARE_MMU; 7505184Sek110237 #else 7515184Sek110237 int flag = 0; 7525184Sek110237 #endif /* HAVE_SHM_SHARE_MMU */ 7535184Sek110237 7545184Sek110237 7555184Sek110237 if (ism_attached) 7565184Sek110237 return (0); 7575184Sek110237 7585184Sek110237 /* Does it exist? */ 7595184Sek110237 if (filebench_shm->shm_id == 999) 7605184Sek110237 return (0); 7615184Sek110237 7625184Sek110237 if (shmat(filebench_shm->shm_id, filebench_shm->shm_addr, 7635184Sek110237 flag) == NULL) 7645184Sek110237 return (-1); 7655184Sek110237 7665184Sek110237 ism_attached = 1; 7675184Sek110237 7685184Sek110237 return (0); 7695184Sek110237 } 7705184Sek110237 7715184Sek110237 /* 7725184Sek110237 * Allocate from interprocess shared memory. Attaches to ism 7735184Sek110237 * if necessary, then allocates "size" bytes, updates allocation 7745184Sek110237 * information and returns a pointer to the allocated memory. 7755184Sek110237 */ 7765184Sek110237 /* 7775184Sek110237 * XXX No check is made for out-of-memory condition 7785184Sek110237 */ 7795184Sek110237 char * 7805184Sek110237 ipc_ismmalloc(size_t size) 7815184Sek110237 { 7825184Sek110237 char *allocstr; 7835184Sek110237 784*6305Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_ism_lock); 7855184Sek110237 7865184Sek110237 /* Map in shared memory */ 7875184Sek110237 (void) ipc_ismattach(); 7885184Sek110237 7895184Sek110237 allocstr = filebench_shm->shm_ptr; 7905184Sek110237 7915184Sek110237 filebench_shm->shm_ptr += size; 7925184Sek110237 filebench_shm->shm_allocated += size; 7935184Sek110237 794*6305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_ism_lock); 7955184Sek110237 7965184Sek110237 return (allocstr); 7975184Sek110237 } 7985184Sek110237 7995184Sek110237 /* 8005184Sek110237 * Deletes shared memory region and resets shared memory region 8015184Sek110237 * information in filebench_shm. 8025184Sek110237 */ 8035184Sek110237 void 8045184Sek110237 ipc_ismdelete(void) 8055184Sek110237 { 8065184Sek110237 if (filebench_shm->shm_id == -1) 8075184Sek110237 return; 8085184Sek110237 8095184Sek110237 filebench_log(LOG_VERBOSE, "Deleting ISM..."); 8105184Sek110237 811*6305Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_ism_lock); 8125184Sek110237 #ifdef HAVE_SEM_RMID 8135184Sek110237 (void) shmctl(filebench_shm->shm_id, IPC_RMID, 0); 8145184Sek110237 #endif 8155184Sek110237 filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr; 8165184Sek110237 filebench_shm->shm_id = -1; 8175184Sek110237 filebench_shm->shm_allocated = 0; 818*6305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_ism_lock); 8195184Sek110237 } 820