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 #include "config.h"
275184Sek110237
285184Sek110237 #include <stdio.h>
295184Sek110237 #include <fcntl.h>
305184Sek110237 #include <sys/mman.h>
315184Sek110237 #include <sys/ipc.h>
325184Sek110237 #include <sys/sem.h>
335184Sek110237 #include <sys/errno.h>
345184Sek110237 #include <signal.h>
355184Sek110237 #include <pthread.h>
365184Sek110237 #include <sys/shm.h>
375184Sek110237 #include "filebench.h"
385184Sek110237
395184Sek110237 /* IPC Hub and Simple memory allocator */
405184Sek110237
415184Sek110237 static int shmfd;
425184Sek110237 filebench_shm_t *filebench_shm = NULL;
435184Sek110237
445184Sek110237 /*
455184Sek110237 * Interprocess Communication mechanisms. If multiple processes
465184Sek110237 * are used, filebench opens a shared file in memory mapped mode to hold
475184Sek110237 * a variety of global variables and data structures. If only using
485184Sek110237 * multiple threads, it just allocates a region of local memory. A
495184Sek110237 * region of interprocess shared memory and a set of shared semaphores
505184Sek110237 * are also created. Routines are provided to manage the creation,
515184Sek110237 * destruction, and allocation of these resoures.
525184Sek110237 */
535184Sek110237
545184Sek110237
555184Sek110237 /*
565184Sek110237 * Locks a mutex and logs any errors.
575184Sek110237 */
585184Sek110237 int
ipc_mutex_lock(pthread_mutex_t * mutex)595184Sek110237 ipc_mutex_lock(pthread_mutex_t *mutex)
605184Sek110237 {
615184Sek110237 int error;
625184Sek110237
635184Sek110237 error = pthread_mutex_lock(mutex);
645184Sek110237
655184Sek110237 #ifdef HAVE_ROBUST_MUTEX
665184Sek110237 if (error == EOWNERDEAD) {
675184Sek110237 if (pthread_mutex_consistent_np(mutex) != 0) {
685184Sek110237 filebench_log(LOG_FATAL, "mutex make consistent "
695184Sek110237 "failed: %s", strerror(error));
705184Sek110237 return (-1);
715184Sek110237 }
725184Sek110237 return (0);
735184Sek110237 }
745184Sek110237 #endif /* HAVE_ROBUST_MUTEX */
755184Sek110237
765184Sek110237 if (error != 0) {
775184Sek110237 filebench_log(LOG_FATAL, "mutex lock failed: %s",
785184Sek110237 strerror(error));
795184Sek110237 }
805184Sek110237
815184Sek110237 return (error);
825184Sek110237 }
835184Sek110237
845184Sek110237 /*
855184Sek110237 * Unlocks a mutex and logs any errors.
865184Sek110237 */
875184Sek110237 int
ipc_mutex_unlock(pthread_mutex_t * mutex)885184Sek110237 ipc_mutex_unlock(pthread_mutex_t *mutex)
895184Sek110237 {
905184Sek110237 int error;
915184Sek110237
925184Sek110237 error = pthread_mutex_unlock(mutex);
935184Sek110237
945184Sek110237 #ifdef HAVE_ROBUST_MUTEX
955184Sek110237 if (error == EOWNERDEAD) {
965184Sek110237 if (pthread_mutex_consistent_np(mutex) != 0) {
975184Sek110237 filebench_log(LOG_FATAL, "mutex make consistent "
985184Sek110237 "failed: %s", strerror(error));
995184Sek110237 return (-1);
1005184Sek110237 }
1015184Sek110237 return (0);
1025184Sek110237 }
1035184Sek110237 #endif /* HAVE_ROBUST_MUTEX */
1045184Sek110237
1055184Sek110237 if (error != 0) {
1065184Sek110237 filebench_log(LOG_FATAL, "mutex unlock failed: %s",
1075184Sek110237 strerror(error));
1085184Sek110237 }
1095184Sek110237
1105184Sek110237 return (error);
1115184Sek110237 }
1125184Sek110237
1135184Sek110237 /*
114*7556SAndrew.W.Wilson@sun.com * Initialize mutex attributes for the various flavors of mutexes
115*7556SAndrew.W.Wilson@sun.com */
116*7556SAndrew.W.Wilson@sun.com static void
ipc_mutexattr_init(int mtx_type)117*7556SAndrew.W.Wilson@sun.com ipc_mutexattr_init(int mtx_type)
118*7556SAndrew.W.Wilson@sun.com {
119*7556SAndrew.W.Wilson@sun.com pthread_mutexattr_t *mtx_attrp;
120*7556SAndrew.W.Wilson@sun.com
121*7556SAndrew.W.Wilson@sun.com mtx_attrp = &(filebench_shm->shm_mutexattr[mtx_type]);
122*7556SAndrew.W.Wilson@sun.com
123*7556SAndrew.W.Wilson@sun.com (void) pthread_mutexattr_init(mtx_attrp);
124*7556SAndrew.W.Wilson@sun.com
125*7556SAndrew.W.Wilson@sun.com #ifdef USE_PROCESS_MODEL
126*7556SAndrew.W.Wilson@sun.com #ifdef HAVE_PROCSCOPE_PTHREADS
127*7556SAndrew.W.Wilson@sun.com if (pthread_mutexattr_setpshared(mtx_attrp,
128*7556SAndrew.W.Wilson@sun.com PTHREAD_PROCESS_SHARED) != 0) {
129*7556SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, "cannot set mutex attr "
130*7556SAndrew.W.Wilson@sun.com "PROCESS_SHARED on this platform");
131*7556SAndrew.W.Wilson@sun.com filebench_shutdown(1);
132*7556SAndrew.W.Wilson@sun.com }
133*7556SAndrew.W.Wilson@sun.com #ifdef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL
134*7556SAndrew.W.Wilson@sun.com if (mtx_type & IPC_MUTEX_PRIORITY) {
135*7556SAndrew.W.Wilson@sun.com if (pthread_mutexattr_setprotocol(mtx_attrp,
136*7556SAndrew.W.Wilson@sun.com PTHREAD_PRIO_INHERIT) != 0) {
137*7556SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR,
138*7556SAndrew.W.Wilson@sun.com "cannot set mutex attr "
139*7556SAndrew.W.Wilson@sun.com "PTHREAD_PRIO_INHERIT on this platform");
140*7556SAndrew.W.Wilson@sun.com filebench_shutdown(1);
141*7556SAndrew.W.Wilson@sun.com }
142*7556SAndrew.W.Wilson@sun.com }
143*7556SAndrew.W.Wilson@sun.com #endif /* HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL */
144*7556SAndrew.W.Wilson@sun.com #endif /* HAVE_PROCSCOPE_PTHREADS */
145*7556SAndrew.W.Wilson@sun.com #ifdef HAVE_ROBUST_MUTEX
146*7556SAndrew.W.Wilson@sun.com if (mtx_type & IPC_MUTEX_ROBUST) {
147*7556SAndrew.W.Wilson@sun.com if (pthread_mutexattr_setrobust_np(mtx_attrp,
148*7556SAndrew.W.Wilson@sun.com PTHREAD_MUTEX_ROBUST_NP) != 0) {
149*7556SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR,
150*7556SAndrew.W.Wilson@sun.com "cannot set mutex attr "
151*7556SAndrew.W.Wilson@sun.com "PTHREAD_MUTEX_ROBUST_NP on this platform");
152*7556SAndrew.W.Wilson@sun.com filebench_shutdown(1);
153*7556SAndrew.W.Wilson@sun.com }
154*7556SAndrew.W.Wilson@sun.com if (pthread_mutexattr_settype(mtx_attrp,
155*7556SAndrew.W.Wilson@sun.com PTHREAD_MUTEX_ERRORCHECK) != 0) {
156*7556SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR,
157*7556SAndrew.W.Wilson@sun.com "cannot set mutex attr "
158*7556SAndrew.W.Wilson@sun.com "PTHREAD_MUTEX_ERRORCHECK "
159*7556SAndrew.W.Wilson@sun.com "on this platform");
160*7556SAndrew.W.Wilson@sun.com filebench_shutdown(1);
161*7556SAndrew.W.Wilson@sun.com }
162*7556SAndrew.W.Wilson@sun.com }
163*7556SAndrew.W.Wilson@sun.com #endif /* HAVE_ROBUST_MUTEX */
164*7556SAndrew.W.Wilson@sun.com #endif /* USE_PROCESS_MODEL */
165*7556SAndrew.W.Wilson@sun.com }
166*7556SAndrew.W.Wilson@sun.com
167*7556SAndrew.W.Wilson@sun.com /*
1685184Sek110237 * On first invocation, allocates a mutex attributes structure
1695184Sek110237 * and initializes it with appropriate attributes. In all cases,
1705184Sek110237 * returns a pointer to the structure.
1715184Sek110237 */
1725184Sek110237 pthread_mutexattr_t *
ipc_mutexattr(int mtx_type)173*7556SAndrew.W.Wilson@sun.com ipc_mutexattr(int mtx_type)
1745184Sek110237 {
175*7556SAndrew.W.Wilson@sun.com if ((mtx_type >= IPC_NUM_MUTEX_ATTRS) ||
176*7556SAndrew.W.Wilson@sun.com (mtx_type < IPC_MUTEX_NORMAL)) {
177*7556SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR,
178*7556SAndrew.W.Wilson@sun.com "ipc_mutexattr called with undefined attr selector %d",
179*7556SAndrew.W.Wilson@sun.com mtx_type);
180*7556SAndrew.W.Wilson@sun.com return (&(filebench_shm->shm_mutexattr[IPC_MUTEX_NORMAL]));
181*7556SAndrew.W.Wilson@sun.com }
1825184Sek110237
183*7556SAndrew.W.Wilson@sun.com return (&(filebench_shm->shm_mutexattr[mtx_type]));
1845184Sek110237 }
1855184Sek110237
1865184Sek110237 static pthread_condattr_t *condattr = NULL;
1875184Sek110237
1885184Sek110237 /*
1895184Sek110237 * On first invocation, allocates a condition variable attributes
1905184Sek110237 * structure and initializes it with appropriate attributes. In
1915184Sek110237 * all cases, returns a pointer to the structure.
1925184Sek110237 */
1935184Sek110237 pthread_condattr_t *
ipc_condattr(void)1945184Sek110237 ipc_condattr(void)
1955184Sek110237 {
1965184Sek110237 #ifdef USE_PROCESS_MODEL
1975184Sek110237 if (condattr == NULL) {
1985184Sek110237 if ((condattr = malloc(sizeof (pthread_condattr_t))) == NULL) {
1995184Sek110237 filebench_log(LOG_ERROR, "cannot alloc cond attr");
2005184Sek110237 filebench_shutdown(1);
2015184Sek110237 }
2025184Sek110237 #ifdef HAVE_PROCSCOPE_PTHREADS
2035184Sek110237 (void) pthread_condattr_init(condattr);
2045184Sek110237 if (pthread_condattr_setpshared(condattr,
2055184Sek110237 PTHREAD_PROCESS_SHARED) != 0) {
2065184Sek110237 filebench_log(LOG_ERROR,
2075184Sek110237 "cannot set cond attr PROCESS_SHARED");
2085184Sek110237 filebench_shutdown(1);
2095184Sek110237 }
2105184Sek110237 #endif /* HAVE_PROCSCOPE_PTHREADS */
2115184Sek110237 }
2125184Sek110237 #endif /* USE_PROCESS_MODEL */
2135184Sek110237 return (condattr);
2145184Sek110237 }
2155184Sek110237
2165184Sek110237 static pthread_rwlockattr_t *rwlockattr = NULL;
2175184Sek110237
2185184Sek110237 /*
2195184Sek110237 * On first invocation, allocates a readers/writers attributes
2205184Sek110237 * structure and initializes it with appropriate attributes.
2215184Sek110237 * In all cases, returns a pointer to the structure.
2225184Sek110237 */
2235184Sek110237 static pthread_rwlockattr_t *
ipc_rwlockattr(void)2245184Sek110237 ipc_rwlockattr(void)
2255184Sek110237 {
2265184Sek110237 #ifdef USE_PROCESS_MODEL
2275184Sek110237 if (rwlockattr == NULL) {
2285184Sek110237 if ((rwlockattr =
2295184Sek110237 malloc(sizeof (pthread_rwlockattr_t))) == NULL) {
2305184Sek110237 filebench_log(LOG_ERROR, "cannot alloc rwlock attr");
2315184Sek110237 filebench_shutdown(1);
2325184Sek110237 }
2335184Sek110237 #ifdef HAVE_PROCSCOPE_PTHREADS
2345184Sek110237 (void) pthread_rwlockattr_init(rwlockattr);
2355184Sek110237 if (pthread_rwlockattr_setpshared(rwlockattr,
2365184Sek110237 PTHREAD_PROCESS_SHARED) != 0) {
2375184Sek110237 filebench_log(LOG_ERROR,
2385184Sek110237 "cannot set rwlock attr PROCESS_SHARED");
2395184Sek110237 filebench_shutdown(1);
2405184Sek110237 }
2415184Sek110237 #endif /* HAVE_PROCSCOPE_PTHREADS */
2425184Sek110237 }
2435184Sek110237 #endif /* USE_PROCESS_MODEL */
2445184Sek110237 return (rwlockattr);
2455184Sek110237 }
2465184Sek110237
2475184Sek110237 char *shmpath = NULL;
2485184Sek110237
2495184Sek110237 /*
2505184Sek110237 * Calls semget() to get a set of shared system V semaphores.
2515184Sek110237 */
2525184Sek110237 void
ipc_seminit(void)2535184Sek110237 ipc_seminit(void)
2545184Sek110237 {
2556391Saw148015 key_t key = filebench_shm->shm_semkey;
2566391Saw148015 int sys_semid;
2575184Sek110237
2585184Sek110237 /* Already done? */
2596391Saw148015 if (filebench_shm->shm_sys_semid >= 0)
2605184Sek110237 return;
2615184Sek110237
2626391Saw148015 if ((sys_semid = semget(key, FILEBENCH_NSEMS, IPC_CREAT |
2635184Sek110237 S_IRUSR | S_IWUSR)) == -1) {
2645184Sek110237 filebench_log(LOG_ERROR,
2655184Sek110237 "could not create sysv semaphore set "
2665184Sek110237 "(need to increase sems?): %s",
2675184Sek110237 strerror(errno));
2686391Saw148015 filebench_shutdown(1);
2695184Sek110237 }
2706391Saw148015
2716391Saw148015 filebench_shm->shm_sys_semid = sys_semid;
2725184Sek110237 }
2735184Sek110237
2745184Sek110237 /*
2755184Sek110237 * Initialize the Interprocess Communication system and its
2765184Sek110237 * associated shared memory structure. It first creates a
2775184Sek110237 * temporary file using either the mkstemp() function or the
2785184Sek110237 * tempnam() and open() functions. If the process model is in
2795184Sek110237 * use,it than sets the file large enough to hold the
2805184Sek110237 * filebench_shm and an additional Megabyte. The file is then
2815184Sek110237 * memory mapped. If the process model is not in use, it simply
2825184Sek110237 * mallocs a region of sizeof (filebench_shm_t).
2835184Sek110237 *
2845184Sek110237 * Once the shared memory region / file is created, ipc_init
2855184Sek110237 * initializes various locks pointers, and variables in the
2865184Sek110237 * shared memory. It also uses ftok() to get a shared memory
2875184Sek110237 * semaphore key for later use in allocating shared semaphores.
2885184Sek110237 */
2895184Sek110237 void
ipc_init(void)2905184Sek110237 ipc_init(void)
2915184Sek110237 {
2925184Sek110237 filebench_shm_t *buf = malloc(MB);
2935184Sek110237 key_t key;
2945184Sek110237 caddr_t c1;
2955184Sek110237 caddr_t c2;
2965184Sek110237 #ifdef HAVE_SEM_RMID
2976391Saw148015 int sys_semid;
2985184Sek110237 #endif
2995184Sek110237
3005184Sek110237 #ifdef HAVE_MKSTEMP
3015184Sek110237 shmpath = (char *)malloc(128);
3025184Sek110237 (void) strcpy(shmpath, "/var/tmp/fbenchXXXXXX");
3035184Sek110237 shmfd = mkstemp(shmpath);
3045184Sek110237 #else
3055184Sek110237 shmfd = open(shmpath, O_CREAT | O_RDWR | O_TRUNC, 0666);
3065184Sek110237 shmpath = tempnam("/var/tmp", "fbench");
3075184Sek110237 #endif /* HAVE_MKSTEMP */
3085184Sek110237
3095184Sek110237 #ifdef USE_PROCESS_MODEL
3105184Sek110237
3115184Sek110237 if (shmfd < 0) {
3125184Sek110237 filebench_log(LOG_FATAL, "Cannot open shm %s: %s",
3135184Sek110237 shmpath,
3145184Sek110237 strerror(errno));
3155184Sek110237 exit(1);
3165184Sek110237 }
3175184Sek110237
3185184Sek110237 (void) lseek(shmfd, sizeof (filebench_shm_t), SEEK_SET);
3195184Sek110237 if (write(shmfd, buf, MB) != MB) {
3205184Sek110237 filebench_log(LOG_FATAL,
3215184Sek110237 "Cannot allocate shm: %s", strerror(errno));
3225184Sek110237 exit(1);
3235184Sek110237 }
3245184Sek110237
3255184Sek110237 /* LINTED E_BAD_PTR_CAST_ALIGN */
3265184Sek110237 if ((filebench_shm = (filebench_shm_t *)mmap((caddr_t)0,
3275673Saw148015 sizeof (filebench_shm_t), PROT_READ | PROT_WRITE,
3285673Saw148015 MAP_SHARED, shmfd, 0)) == NULL) {
3295184Sek110237 filebench_log(LOG_FATAL, "Cannot mmap shm");
3305184Sek110237 exit(1);
3315184Sek110237 }
3325184Sek110237
3335184Sek110237 #else
3345184Sek110237 if ((filebench_shm =
3355184Sek110237 (filebench_shm_t *)malloc(sizeof (filebench_shm_t))) == NULL) {
3365184Sek110237 filebench_log(LOG_FATAL, "Cannot malloc shm");
3375184Sek110237 exit(1);
3385184Sek110237 }
3395184Sek110237 #endif /* USE_PROCESS_MODEL */
3405184Sek110237
3415184Sek110237 c1 = (caddr_t)filebench_shm;
3426305Saw148015 c2 = (caddr_t)&filebench_shm->shm_marker;
3435184Sek110237
3445184Sek110237 (void) memset(filebench_shm, 0, c2 - c1);
3456391Saw148015 filebench_shm->shm_epoch = gethrtime();
3466391Saw148015 filebench_shm->shm_debug_level = LOG_VERBOSE;
3476084Saw148015 filebench_shm->shm_rmode = FILEBENCH_MODE_TIMEOUT;
3486305Saw148015 filebench_shm->shm_string_ptr = &filebench_shm->shm_strings[0];
3495184Sek110237 filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr;
3506305Saw148015 filebench_shm->shm_path_ptr = &filebench_shm->shm_filesetpaths[0];
3515184Sek110237
3525184Sek110237 /* Setup mutexes for object lists */
353*7556SAndrew.W.Wilson@sun.com ipc_mutexattr_init(IPC_MUTEX_NORMAL);
354*7556SAndrew.W.Wilson@sun.com ipc_mutexattr_init(IPC_MUTEX_PRIORITY);
355*7556SAndrew.W.Wilson@sun.com ipc_mutexattr_init(IPC_MUTEX_ROBUST);
356*7556SAndrew.W.Wilson@sun.com ipc_mutexattr_init(IPC_MUTEX_PRI_ROB);
3576391Saw148015 (void) pthread_mutex_init(&filebench_shm->shm_fileset_lock,
358*7556SAndrew.W.Wilson@sun.com ipc_mutexattr(IPC_MUTEX_NORMAL));
3596391Saw148015 (void) pthread_mutex_init(&filebench_shm->shm_procflow_lock,
360*7556SAndrew.W.Wilson@sun.com ipc_mutexattr(IPC_MUTEX_NORMAL));
3616701Saw148015 (void) pthread_mutex_init(&filebench_shm->shm_procs_running_lock,
362*7556SAndrew.W.Wilson@sun.com ipc_mutexattr(IPC_MUTEX_NORMAL));
3636391Saw148015 (void) pthread_mutex_init(&filebench_shm->shm_threadflow_lock,
364*7556SAndrew.W.Wilson@sun.com ipc_mutexattr(IPC_MUTEX_NORMAL));
3656391Saw148015 (void) pthread_mutex_init(&filebench_shm->shm_flowop_lock,
366*7556SAndrew.W.Wilson@sun.com ipc_mutexattr(IPC_MUTEX_NORMAL));
3676391Saw148015 (void) pthread_mutex_init(&filebench_shm->shm_msg_lock,
368*7556SAndrew.W.Wilson@sun.com ipc_mutexattr(IPC_MUTEX_NORMAL));
3696391Saw148015 (void) pthread_mutex_init(&filebench_shm->shm_eventgen_lock,
370*7556SAndrew.W.Wilson@sun.com ipc_mutexattr(IPC_MUTEX_PRI_ROB));
3716305Saw148015 (void) pthread_mutex_init(&filebench_shm->shm_malloc_lock,
372*7556SAndrew.W.Wilson@sun.com ipc_mutexattr(IPC_MUTEX_NORMAL));
3736305Saw148015 (void) pthread_mutex_init(&filebench_shm->shm_ism_lock,
374*7556SAndrew.W.Wilson@sun.com ipc_mutexattr(IPC_MUTEX_NORMAL));
3756391Saw148015 (void) pthread_cond_init(&filebench_shm->shm_eventgen_cv,
3766391Saw148015 ipc_condattr());
3776391Saw148015 (void) pthread_rwlock_init(&filebench_shm->shm_flowop_find_lock,
3785184Sek110237 ipc_rwlockattr());
379*7556SAndrew.W.Wilson@sun.com #ifdef USE_PROCESS_MODEL
380*7556SAndrew.W.Wilson@sun.com (void) pthread_cond_init(&filebench_shm->shm_procflow_procs_cv,
381*7556SAndrew.W.Wilson@sun.com ipc_condattr());
382*7556SAndrew.W.Wilson@sun.com #endif
3836391Saw148015 (void) pthread_rwlock_init(&filebench_shm->shm_run_lock,
3846391Saw148015 ipc_rwlockattr());
3856391Saw148015 (void) pthread_rwlock_rdlock(&filebench_shm->shm_run_lock);
3865184Sek110237
3876305Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_ism_lock);
3885184Sek110237
3895184Sek110237 /* Create semaphore */
3905184Sek110237 if ((key = ftok(shmpath, 1)) < 0) {
3915184Sek110237 filebench_log(LOG_ERROR, "cannot create sem: %s",
3925184Sek110237 strerror(errno));
3935184Sek110237 exit(1);
3945184Sek110237 }
3955184Sek110237
3965184Sek110237 #ifdef HAVE_SEM_RMID
3976391Saw148015 if ((sys_semid = semget(key, 0, 0)) != -1)
3986391Saw148015 (void) semctl(sys_semid, 0, IPC_RMID);
3995184Sek110237 #endif
4005184Sek110237
4016391Saw148015 filebench_shm->shm_semkey = key;
4026391Saw148015 filebench_shm->shm_sys_semid = -1;
4036391Saw148015 filebench_shm->shm_log_fd = -1;
4046391Saw148015 filebench_shm->shm_dump_fd = -1;
4056391Saw148015 filebench_shm->shm_eventgen_hz = 0;
4065184Sek110237 filebench_shm->shm_id = -1;
4075184Sek110237
4085184Sek110237 free(buf);
4095184Sek110237 }
4105184Sek110237
4115184Sek110237 /*
4125184Sek110237 * If compiled to use process model, just unlinks the shmpath.
4135184Sek110237 * Otherwise a no-op.
4145184Sek110237 */
4155184Sek110237 void
ipc_fini(void)4166750Sek110237 ipc_fini(void)
4175184Sek110237 {
4185184Sek110237 #ifdef USE_PROCESS_MODEL
4195184Sek110237 (void) unlink(shmpath);
4205184Sek110237 #endif /* USE_PROCESS_MODEL */
4216750Sek110237
4226750Sek110237 #ifdef HAVE_SEM_RMID
4236750Sek110237 if (filebench_shm->shm_sys_semid != -1) {
4246750Sek110237 (void) semctl(filebench_shm->shm_sys_semid, 0, IPC_RMID);
4256750Sek110237 filebench_shm->shm_sys_semid = -1;
4266750Sek110237 }
4276750Sek110237 #endif
4285184Sek110237 }
4295184Sek110237
4305184Sek110237 /*
4315184Sek110237 * Attach to shared memory. Used by worker processes to open
4325184Sek110237 * and mmap the shared memory region. If successful, it
4335184Sek110237 * initializes the worker process' filebench_shm to point to
4345184Sek110237 * the region and returns 0. Otherwise it returns -1.
4355184Sek110237 */
4365184Sek110237 int
ipc_attach(caddr_t shmaddr)4375184Sek110237 ipc_attach(caddr_t shmaddr)
4385184Sek110237 {
4395184Sek110237 if ((shmfd = open(shmpath, O_RDWR, 0666)) < 0) {
4405184Sek110237 filebench_log(LOG_ERROR, "Cannot open shm");
4415184Sek110237 return (-1);
4425184Sek110237 }
4435184Sek110237
4445184Sek110237 /* LINTED E_BAD_PTR_CAST_ALIGN */
4455184Sek110237 if ((filebench_shm = (filebench_shm_t *)mmap(shmaddr,
4465184Sek110237 sizeof (filebench_shm_t), PROT_READ | PROT_WRITE,
4475184Sek110237 MAP_SHARED | MAP_FIXED, shmfd, 0)) == NULL) {
4485184Sek110237 filebench_log(LOG_ERROR, "Cannot mmap shm");
4495184Sek110237 return (-1);
4505184Sek110237 }
4515184Sek110237
4525184Sek110237 filebench_log(LOG_DEBUG_IMPL, "addr = %zx", filebench_shm);
4535184Sek110237
4545184Sek110237 return (0);
4555184Sek110237 }
4565184Sek110237
4575184Sek110237 static int filebench_sizes[] = {
4586212Saw148015 FILEBENCH_NPROCFLOWS, /* number of procflows */
4596212Saw148015 FILEBENCH_NTHREADFLOWS, /* number of threadflows */
4606212Saw148015 FILEBENCH_NFLOWOPS, /* number of flowops */
4616212Saw148015 (FILEBENCH_NVARS * 2), /* number of attribute value dscrs */
4626212Saw148015 FILEBENCH_NVARS, /* number of variables */
4636212Saw148015 FILEBENCH_NFILESETS, /* number of filesets */
4646212Saw148015 FILEBENCH_NFILESETENTRIES, /* number of fileset entries */
4656212Saw148015 FILEBENCH_NRANDDISTS}; /* number of random distributions */
4665184Sek110237
4675184Sek110237 /*
4685184Sek110237 * Allocates filebench objects from pre allocated region of
4695184Sek110237 * shareable memory. The memory region is partitioned into sets
4705184Sek110237 * of objects during initialization. This routine scans for
4715184Sek110237 * the first unallocated object of type "type" in the set of
4725184Sek110237 * available objects, and makes it as allocated. The routine
4735184Sek110237 * returns a pointer to the object, or NULL if all objects have
4745184Sek110237 * been allocated.
4755184Sek110237 */
4765184Sek110237 void *
ipc_malloc(int type)4775184Sek110237 ipc_malloc(int type)
4785184Sek110237 {
4795184Sek110237 int i;
4805184Sek110237 int max = filebench_sizes[type];
4816305Saw148015 int start_idx = filebench_shm->shm_lastbitmapindex[type];
4825184Sek110237
4836305Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_malloc_lock);
4845184Sek110237
4856305Saw148015 i = start_idx;
4866305Saw148015 do {
4876305Saw148015 i++;
4886305Saw148015 if (i >= max)
4896305Saw148015 i = 0;
4906305Saw148015
4916305Saw148015 if (filebench_shm->shm_bitmap[type][i] == 0)
4925184Sek110237 break;
4936305Saw148015
4946305Saw148015 } while (i != start_idx);
4955184Sek110237
4966305Saw148015 if (i == start_idx) {
4975184Sek110237 filebench_log(LOG_ERROR, "Out of shared memory (%d)!", type);
4986305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock);
4995184Sek110237 return (NULL);
5005184Sek110237 }
5015184Sek110237
5026305Saw148015 filebench_shm->shm_bitmap[type][i] = 1;
5036305Saw148015 filebench_shm->shm_lastbitmapindex[type] = i;
5045184Sek110237
5055184Sek110237 switch (type) {
5065184Sek110237 case FILEBENCH_FILESET:
5076305Saw148015 (void) memset((char *)&filebench_shm->shm_fileset[i], 0,
5085184Sek110237 sizeof (fileset_t));
5096305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock);
5106305Saw148015 return ((char *)&filebench_shm->shm_fileset[i]);
5115184Sek110237
5125184Sek110237 case FILEBENCH_FILESETENTRY:
5136305Saw148015 (void) memset((char *)&filebench_shm->shm_filesetentry[i], 0,
5145184Sek110237 sizeof (filesetentry_t));
5156305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock);
5166305Saw148015 return ((char *)&filebench_shm->shm_filesetentry[i]);
5175184Sek110237
5185184Sek110237 case FILEBENCH_PROCFLOW:
5196305Saw148015 (void) memset((char *)&filebench_shm->shm_procflow[i], 0,
5205184Sek110237 sizeof (procflow_t));
5216305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock);
5226305Saw148015 return ((char *)&filebench_shm->shm_procflow[i]);
5235184Sek110237
5245184Sek110237 case FILEBENCH_THREADFLOW:
5256305Saw148015 (void) memset((char *)&filebench_shm->shm_threadflow[i], 0,
5265184Sek110237 sizeof (threadflow_t));
5276305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock);
5286305Saw148015 return ((char *)&filebench_shm->shm_threadflow[i]);
5295184Sek110237
5305184Sek110237 case FILEBENCH_FLOWOP:
5316305Saw148015 (void) memset((char *)&filebench_shm->shm_flowop[i], 0,
5325184Sek110237 sizeof (flowop_t));
5336305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock);
5346305Saw148015 return ((char *)&filebench_shm->shm_flowop[i]);
5355184Sek110237
5366212Saw148015 case FILEBENCH_AVD:
5376212Saw148015 filebench_shm->shm_avd_ptrs[i].avd_type = AVD_INVALID;
5386212Saw148015 filebench_shm->shm_avd_ptrs[i].avd_val.varptr = NULL;
5396305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock);
5406212Saw148015 return ((char *)&filebench_shm->shm_avd_ptrs[i]);
5415184Sek110237
5425184Sek110237 case FILEBENCH_VARIABLE:
5436305Saw148015 (void) memset((char *)&filebench_shm->shm_var[i], 0,
5445184Sek110237 sizeof (var_t));
5456305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock);
5466305Saw148015 return ((char *)&filebench_shm->shm_var[i]);
5476212Saw148015
5486212Saw148015 case FILEBENCH_RANDDIST:
5496212Saw148015 (void) memset((char *)&filebench_shm->shm_randdist[i], 0,
5506212Saw148015 sizeof (randdist_t));
5516305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock);
5526212Saw148015 return ((char *)&filebench_shm->shm_randdist[i]);
5535184Sek110237 }
5545184Sek110237
5555184Sek110237 filebench_log(LOG_ERROR, "Attempt to ipc_malloc unknown type (%d)!",
5565184Sek110237 type);
5575184Sek110237 return (NULL);
5585184Sek110237 }
5595184Sek110237
5605184Sek110237 /*
5615184Sek110237 * Frees a filebench object of type "type" at the location
5625184Sek110237 * pointed to by "addr". It uses the type and address to
5635184Sek110237 * calculate which object is being freed, and clears its
5645184Sek110237 * allocation map entry.
5655184Sek110237 */
5665184Sek110237 void
ipc_free(int type,char * addr)5675184Sek110237 ipc_free(int type, char *addr)
5685184Sek110237 {
5695184Sek110237 int item;
5705184Sek110237 caddr_t base;
5715184Sek110237 size_t offset;
5725184Sek110237 size_t size;
5735184Sek110237
5745184Sek110237 if (addr == NULL) {
5755184Sek110237 filebench_log(LOG_ERROR, "Freeing type %d %zx", type, addr);
5765184Sek110237 return;
5775184Sek110237 }
5785184Sek110237
5795184Sek110237 switch (type) {
5805184Sek110237
5815184Sek110237 case FILEBENCH_FILESET:
5826305Saw148015 base = (caddr_t)&filebench_shm->shm_fileset[0];
5835184Sek110237 size = sizeof (fileset_t);
5845184Sek110237 break;
5855184Sek110237
5865184Sek110237 case FILEBENCH_FILESETENTRY:
5876305Saw148015 base = (caddr_t)&filebench_shm->shm_filesetentry[0];
5885184Sek110237 size = sizeof (filesetentry_t);
5895184Sek110237 break;
5905184Sek110237
5915184Sek110237 case FILEBENCH_PROCFLOW:
5926305Saw148015 base = (caddr_t)&filebench_shm->shm_procflow[0];
5935184Sek110237 size = sizeof (procflow_t);
5945184Sek110237 break;
5955184Sek110237
5965184Sek110237 case FILEBENCH_THREADFLOW:
5976305Saw148015 base = (caddr_t)&filebench_shm->shm_threadflow[0];
5985184Sek110237 size = sizeof (threadflow_t);
5995184Sek110237 break;
6005184Sek110237
6015184Sek110237 case FILEBENCH_FLOWOP:
6026305Saw148015 base = (caddr_t)&filebench_shm->shm_flowop[0];
6035184Sek110237 size = sizeof (flowop_t);
6045184Sek110237 break;
6055184Sek110237
6066212Saw148015 case FILEBENCH_AVD:
6076212Saw148015 base = (caddr_t)&filebench_shm->shm_avd_ptrs[0];
6086212Saw148015 size = sizeof (avd_t);
6095184Sek110237 break;
6105184Sek110237
6115184Sek110237 case FILEBENCH_VARIABLE:
6126305Saw148015 base = (caddr_t)&filebench_shm->shm_var[0];
6135184Sek110237 size = sizeof (var_t);
6145184Sek110237 break;
6156212Saw148015
6166212Saw148015 case FILEBENCH_RANDDIST:
6176212Saw148015 base = (caddr_t)&filebench_shm->shm_randdist[0];
6186212Saw148015 size = sizeof (randdist_t);
6196212Saw148015 break;
6205184Sek110237 }
6215184Sek110237
6225184Sek110237 offset = ((size_t)addr - (size_t)base);
6235184Sek110237 item = offset / size;
6245184Sek110237
6256305Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_malloc_lock);
6266305Saw148015 filebench_shm->shm_bitmap[type][item] = 0;
6276305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_malloc_lock);
6285184Sek110237 }
6295184Sek110237
6305184Sek110237 /*
6315184Sek110237 * Allocate a string from filebench string memory. The length
6325184Sek110237 * of the allocated string is the same as the length of the
6335184Sek110237 * supplied string "string", and the contents of string are
6345184Sek110237 * copied to the newly allocated string.
6355184Sek110237 */
6365184Sek110237 char *
ipc_stralloc(char * string)6375184Sek110237 ipc_stralloc(char *string)
6385184Sek110237 {
6396305Saw148015 char *allocstr = filebench_shm->shm_string_ptr;
6405184Sek110237
6416305Saw148015 filebench_shm->shm_string_ptr += strlen(string) + 1;
6425184Sek110237
6436305Saw148015 if ((filebench_shm->shm_string_ptr - &filebench_shm->shm_strings[0]) >
6445184Sek110237 FILEBENCH_STRINGMEMORY) {
6455184Sek110237 filebench_log(LOG_ERROR, "Out of ipc string memory");
6465184Sek110237 return (NULL);
6475184Sek110237 }
6485184Sek110237
6495184Sek110237 (void) strncpy(allocstr, string, strlen(string));
6505184Sek110237
6515184Sek110237 return (allocstr);
6525184Sek110237 }
6535184Sek110237
6545184Sek110237 /*
6555184Sek110237 * Allocate a path string from filebench path string memory.
6565184Sek110237 * Specifically used for allocating fileset paths. The length
6575184Sek110237 * of the allocated path string is the same as the length of
6585184Sek110237 * the supplied path string "path", and the contents of path
6595184Sek110237 * are copied to the newly allocated path string. Checks for
6605184Sek110237 * out-of-path-string-memory condition and returns NULL if so.
6615184Sek110237 * Otherwise it returns a pointer to the newly allocated path
6625184Sek110237 * string.
6635184Sek110237 */
6645184Sek110237 char *
ipc_pathalloc(char * path)6655184Sek110237 ipc_pathalloc(char *path)
6665184Sek110237 {
6676305Saw148015 char *allocpath = filebench_shm->shm_path_ptr;
6685184Sek110237
6696305Saw148015 filebench_shm->shm_path_ptr += strlen(path) + 1;
6705184Sek110237
6716305Saw148015 if ((filebench_shm->shm_path_ptr -
6726305Saw148015 &filebench_shm->shm_filesetpaths[0]) >
6735184Sek110237 FILEBENCH_FILESETPATHMEMORY) {
6745184Sek110237 filebench_log(LOG_ERROR, "Out of fileset path memory");
6755184Sek110237 return (NULL);
6765184Sek110237 }
6775184Sek110237
6785184Sek110237 (void) strncpy(allocpath, path, strlen(path));
6795184Sek110237
6805184Sek110237 return (allocpath);
6815184Sek110237 }
6825184Sek110237
6835184Sek110237 /*
6845184Sek110237 * This is a limited functionality deallocator for path
6855184Sek110237 * strings - it can only free all path strings at once,
6865184Sek110237 * in order to avoid fragmentation.
6875184Sek110237 */
6885184Sek110237 void
ipc_freepaths(void)6895184Sek110237 ipc_freepaths(void)
6905184Sek110237 {
6916305Saw148015 filebench_shm->shm_path_ptr = &filebench_shm->shm_filesetpaths[0];
6925184Sek110237 }
6935184Sek110237
6945184Sek110237 /*
6955184Sek110237 * Allocates a semid from the table of semids for pre intialized
6965184Sek110237 * semaphores. Searches for the first available semaphore, and
6975184Sek110237 * sets the entry in the table to "1" to indicate allocation.
6985184Sek110237 * Returns the allocated semid. Stops the run if all semaphores
6995184Sek110237 * are already in use.
7005184Sek110237 */
7015184Sek110237 int
ipc_semidalloc(void)7025184Sek110237 ipc_semidalloc(void)
7035184Sek110237 {
7045184Sek110237 int semid;
7055184Sek110237
7066391Saw148015 for (semid = 0; filebench_shm->shm_semids[semid] == 1; semid++)
7075184Sek110237 ;
7085184Sek110237 if (semid == FILEBENCH_NSEMS) {
7095184Sek110237 filebench_log(LOG_ERROR,
7105184Sek110237 "Out of semaphores, increase system tunable limit");
7115184Sek110237 filebench_shutdown(1);
7125184Sek110237 }
7136391Saw148015 filebench_shm->shm_semids[semid] = 1;
7145184Sek110237 return (semid);
7155184Sek110237 }
7165184Sek110237
7175184Sek110237 /*
7185184Sek110237 * Frees up the supplied semid by seting its position in the
7195184Sek110237 * allocation table to "0".
7205184Sek110237 */
7215184Sek110237 void
ipc_semidfree(int semid)7225184Sek110237 ipc_semidfree(int semid)
7235184Sek110237 {
7246391Saw148015 filebench_shm->shm_semids[semid] = 0;
7255184Sek110237 }
7265184Sek110237
7275184Sek110237 /*
7285184Sek110237 * Create a pool of shared memory to fit the per-thread
7295184Sek110237 * allocations. Uses shmget() to create a shared memory region
7305184Sek110237 * of size "size", attaches to it using shmat(), and stores
7315184Sek110237 * the returned address of the region in filebench_shm->shm_addr.
7325184Sek110237 * The pool is only created on the first call. The routine
7335184Sek110237 * returns 0 if successful or the pool already exists,
7345184Sek110237 * -1 otherwise.
7355184Sek110237 */
7365184Sek110237 int
ipc_ismcreate(size_t size)7375184Sek110237 ipc_ismcreate(size_t size)
7385184Sek110237 {
7395184Sek110237 #ifdef HAVE_SHM_SHARE_MMU
7405184Sek110237 int flag = SHM_SHARE_MMU;
7415184Sek110237 #else
7425184Sek110237 int flag = 0;
7435184Sek110237 #endif /* HAVE_SHM_SHARE_MMU */
7445184Sek110237
7455184Sek110237 /* Already done? */
7465184Sek110237 if (filebench_shm->shm_id != -1)
7475184Sek110237 return (0);
7485184Sek110237
7495184Sek110237 filebench_log(LOG_VERBOSE,
7505184Sek110237 "Creating %zd bytes of ISM Shared Memory...", size);
7515184Sek110237
7525184Sek110237 if ((filebench_shm->shm_id =
7535184Sek110237 shmget(0, size, IPC_CREAT | 0666)) == -1) {
7545184Sek110237 filebench_log(LOG_ERROR,
7555184Sek110237 "Failed to create %zd bytes of ISM shared memory", size);
7565184Sek110237 return (-1);
7575184Sek110237 }
7585184Sek110237
7595184Sek110237 if ((filebench_shm->shm_addr = (caddr_t)shmat(filebench_shm->shm_id,
7605184Sek110237 0, flag)) == (void *)-1) {
7615184Sek110237 filebench_log(LOG_ERROR,
7625184Sek110237 "Failed to attach %zd bytes of created ISM shared memory",
7635184Sek110237 size);
7645184Sek110237 return (-1);
7655184Sek110237 }
7665184Sek110237
7675184Sek110237 filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr;
7685184Sek110237
7695184Sek110237 filebench_log(LOG_VERBOSE,
7705184Sek110237 "Allocated %zd bytes of ISM Shared Memory... at %zx",
7715184Sek110237 size, filebench_shm->shm_addr);
7725184Sek110237
7735184Sek110237 /* Locked until allocated to block allocs */
7746305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_ism_lock);
7755184Sek110237
7765184Sek110237 return (0);
7775184Sek110237 }
7785184Sek110237
7795184Sek110237 /* Per addr space ism */
7805184Sek110237 static int ism_attached = 0;
7815184Sek110237
7825184Sek110237 /*
7835184Sek110237 * Attach to interprocess shared memory. If already attached
7845184Sek110237 * just return, otherwise use shmat() to attached to the region
7855184Sek110237 * with ID of filebench_shm->shm_id. Returns -1 if shmat()
7865184Sek110237 * fails, otherwise 0.
7875184Sek110237 */
7885184Sek110237 static int
ipc_ismattach(void)7895184Sek110237 ipc_ismattach(void)
7905184Sek110237 {
7915184Sek110237 #ifdef HAVE_SHM_SHARE_MMU
7925184Sek110237 int flag = SHM_SHARE_MMU;
7935184Sek110237 #else
7945184Sek110237 int flag = 0;
7955184Sek110237 #endif /* HAVE_SHM_SHARE_MMU */
7965184Sek110237
7975184Sek110237
7985184Sek110237 if (ism_attached)
7995184Sek110237 return (0);
8005184Sek110237
8015184Sek110237 /* Does it exist? */
8025184Sek110237 if (filebench_shm->shm_id == 999)
8035184Sek110237 return (0);
8045184Sek110237
8055184Sek110237 if (shmat(filebench_shm->shm_id, filebench_shm->shm_addr,
8065184Sek110237 flag) == NULL)
8075184Sek110237 return (-1);
8085184Sek110237
8095184Sek110237 ism_attached = 1;
8105184Sek110237
8115184Sek110237 return (0);
8125184Sek110237 }
8135184Sek110237
8145184Sek110237 /*
8155184Sek110237 * Allocate from interprocess shared memory. Attaches to ism
8165184Sek110237 * if necessary, then allocates "size" bytes, updates allocation
8175184Sek110237 * information and returns a pointer to the allocated memory.
8185184Sek110237 */
8195184Sek110237 /*
8205184Sek110237 * XXX No check is made for out-of-memory condition
8215184Sek110237 */
8225184Sek110237 char *
ipc_ismmalloc(size_t size)8235184Sek110237 ipc_ismmalloc(size_t size)
8245184Sek110237 {
8255184Sek110237 char *allocstr;
8265184Sek110237
8276305Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_ism_lock);
8285184Sek110237
8295184Sek110237 /* Map in shared memory */
8305184Sek110237 (void) ipc_ismattach();
8315184Sek110237
8325184Sek110237 allocstr = filebench_shm->shm_ptr;
8335184Sek110237
8345184Sek110237 filebench_shm->shm_ptr += size;
8355184Sek110237 filebench_shm->shm_allocated += size;
8365184Sek110237
8376305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_ism_lock);
8385184Sek110237
8395184Sek110237 return (allocstr);
8405184Sek110237 }
8415184Sek110237
8425184Sek110237 /*
8435184Sek110237 * Deletes shared memory region and resets shared memory region
8445184Sek110237 * information in filebench_shm.
8455184Sek110237 */
8465184Sek110237 void
ipc_ismdelete(void)8475184Sek110237 ipc_ismdelete(void)
8485184Sek110237 {
8495184Sek110237 if (filebench_shm->shm_id == -1)
8505184Sek110237 return;
8515184Sek110237
8525184Sek110237 filebench_log(LOG_VERBOSE, "Deleting ISM...");
8535184Sek110237
8546305Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_ism_lock);
8555184Sek110237 #ifdef HAVE_SEM_RMID
8565184Sek110237 (void) shmctl(filebench_shm->shm_id, IPC_RMID, 0);
8575184Sek110237 #endif
8585184Sek110237 filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr;
8595184Sek110237 filebench_shm->shm_id = -1;
8605184Sek110237 filebench_shm->shm_allocated = 0;
8616305Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_ism_lock);
8625184Sek110237 }
863