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