summaryrefslogtreecommitdiff
path: root/usr/src/cmd/filebench/common/ipc.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/filebench/common/ipc.c')
-rw-r--r--usr/src/cmd/filebench/common/ipc.c818
1 files changed, 818 insertions, 0 deletions
diff --git a/usr/src/cmd/filebench/common/ipc.c b/usr/src/cmd/filebench/common/ipc.c
new file mode 100644
index 0000000000..beaf2b119a
--- /dev/null
+++ b/usr/src/cmd/filebench/common/ipc.c
@@ -0,0 +1,818 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "config.h"
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/errno.h>
+#include <signal.h>
+#include <pthread.h>
+#include <sys/shm.h>
+#include "filebench.h"
+
+/* IPC Hub and Simple memory allocator */
+
+static int shmfd;
+filebench_shm_t *filebench_shm = NULL;
+static pthread_mutexattr_t *mutexattr = NULL;
+
+/*
+ * Interprocess Communication mechanisms. If multiple processes
+ * are used, filebench opens a shared file in memory mapped mode to hold
+ * a variety of global variables and data structures. If only using
+ * multiple threads, it just allocates a region of local memory. A
+ * region of interprocess shared memory and a set of shared semaphores
+ * are also created. Routines are provided to manage the creation,
+ * destruction, and allocation of these resoures.
+ */
+
+
+/*
+ * Locks a mutex and logs any errors.
+ */
+int
+ipc_mutex_lock(pthread_mutex_t *mutex)
+{
+ int error;
+
+ error = pthread_mutex_lock(mutex);
+
+#ifdef HAVE_ROBUST_MUTEX
+ if (error == EOWNERDEAD) {
+ if (pthread_mutex_consistent_np(mutex) != 0) {
+ filebench_log(LOG_FATAL, "mutex make consistent "
+ "failed: %s", strerror(error));
+ return (-1);
+ }
+ return (0);
+ }
+#endif /* HAVE_ROBUST_MUTEX */
+
+ if (error != 0) {
+ filebench_log(LOG_FATAL, "mutex lock failed: %s",
+ strerror(error));
+ }
+
+ return (error);
+}
+
+/*
+ * Unlocks a mutex and logs any errors.
+ */
+int
+ipc_mutex_unlock(pthread_mutex_t *mutex)
+{
+ int error;
+
+ error = pthread_mutex_unlock(mutex);
+
+#ifdef HAVE_ROBUST_MUTEX
+ if (error == EOWNERDEAD) {
+ if (pthread_mutex_consistent_np(mutex) != 0) {
+ filebench_log(LOG_FATAL, "mutex make consistent "
+ "failed: %s", strerror(error));
+ return (-1);
+ }
+ return (0);
+ }
+#endif /* HAVE_ROBUST_MUTEX */
+
+ if (error != 0) {
+ filebench_log(LOG_FATAL, "mutex unlock failed: %s",
+ strerror(error));
+ }
+
+ return (error);
+}
+
+/*
+ * On first invocation, allocates a mutex attributes structure
+ * and initializes it with appropriate attributes. In all cases,
+ * returns a pointer to the structure.
+ */
+pthread_mutexattr_t *
+ipc_mutexattr(void)
+{
+#ifdef USE_PROCESS_MODEL
+ if (mutexattr == NULL) {
+ if ((mutexattr =
+ malloc(sizeof (pthread_mutexattr_t))) == NULL) {
+ filebench_log(LOG_ERROR, "cannot alloc mutex attr");
+ filebench_shutdown(1);
+ }
+#ifdef HAVE_PROCSCOPE_PTHREADS
+ (void) pthread_mutexattr_init(mutexattr);
+ if (pthread_mutexattr_setpshared(mutexattr,
+ PTHREAD_PROCESS_SHARED) != 0) {
+ filebench_log(LOG_ERROR, "cannot set mutex attr "
+ "PROCESS_SHARED on this platform");
+ filebench_shutdown(1);
+ }
+#ifdef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL
+ if (pthread_mutexattr_setprotocol(mutexattr,
+ PTHREAD_PRIO_INHERIT) != 0) {
+ filebench_log(LOG_ERROR, "cannot set mutex attr "
+ "PTHREAD_PRIO_INHERIT on this platform");
+ filebench_shutdown(1);
+ }
+#endif /* HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL */
+#endif /* HAVE_PROCSCOPE_PTHREADS */
+#ifdef HAVE_ROBUST_MUTEX
+ if (pthread_mutexattr_setrobust_np(mutexattr,
+ PTHREAD_MUTEX_ROBUST_NP) != 0) {
+ filebench_log(LOG_ERROR, "cannot set mutex attr "
+ "PTHREAD_MUTEX_ROBUST_NP on this platform");
+ filebench_shutdown(1);
+ }
+ if (pthread_mutexattr_settype(mutexattr,
+ PTHREAD_MUTEX_ERRORCHECK) != 0) {
+ filebench_log(LOG_ERROR, "cannot set mutex attr "
+ "PTHREAD_MUTEX_ERRORCHECK on this platform");
+ filebench_shutdown(1);
+ }
+#endif /* HAVE_ROBUST_MUTEX */
+
+ }
+#endif /* USE_PROCESS_MODEL */
+ return (mutexattr);
+}
+
+static pthread_condattr_t *condattr = NULL;
+
+/*
+ * On first invocation, allocates a condition variable attributes
+ * structure and initializes it with appropriate attributes. In
+ * all cases, returns a pointer to the structure.
+ */
+pthread_condattr_t *
+ipc_condattr(void)
+{
+#ifdef USE_PROCESS_MODEL
+ if (condattr == NULL) {
+ if ((condattr = malloc(sizeof (pthread_condattr_t))) == NULL) {
+ filebench_log(LOG_ERROR, "cannot alloc cond attr");
+ filebench_shutdown(1);
+ }
+#ifdef HAVE_PROCSCOPE_PTHREADS
+ (void) pthread_condattr_init(condattr);
+ if (pthread_condattr_setpshared(condattr,
+ PTHREAD_PROCESS_SHARED) != 0) {
+ filebench_log(LOG_ERROR,
+ "cannot set cond attr PROCESS_SHARED");
+ filebench_shutdown(1);
+ }
+#endif /* HAVE_PROCSCOPE_PTHREADS */
+ }
+#endif /* USE_PROCESS_MODEL */
+ return (condattr);
+}
+
+static pthread_rwlockattr_t *rwlockattr = NULL;
+
+/*
+ * On first invocation, allocates a readers/writers attributes
+ * structure and initializes it with appropriate attributes.
+ * In all cases, returns a pointer to the structure.
+ */
+static pthread_rwlockattr_t *
+ipc_rwlockattr(void)
+{
+#ifdef USE_PROCESS_MODEL
+ if (rwlockattr == NULL) {
+ if ((rwlockattr =
+ malloc(sizeof (pthread_rwlockattr_t))) == NULL) {
+ filebench_log(LOG_ERROR, "cannot alloc rwlock attr");
+ filebench_shutdown(1);
+ }
+#ifdef HAVE_PROCSCOPE_PTHREADS
+ (void) pthread_rwlockattr_init(rwlockattr);
+ if (pthread_rwlockattr_setpshared(rwlockattr,
+ PTHREAD_PROCESS_SHARED) != 0) {
+ filebench_log(LOG_ERROR,
+ "cannot set rwlock attr PROCESS_SHARED");
+ filebench_shutdown(1);
+ }
+#endif /* HAVE_PROCSCOPE_PTHREADS */
+ }
+#endif /* USE_PROCESS_MODEL */
+ return (rwlockattr);
+}
+
+char *shmpath = NULL;
+
+/*
+ * Calls semget() to get a set of shared system V semaphores.
+ */
+void
+ipc_seminit(void)
+{
+ key_t key = filebench_shm->semkey;
+
+ /* Already done? */
+ if (filebench_shm->seminit)
+ return;
+
+ if ((semget(key, FILEBENCH_NSEMS, IPC_CREAT |
+ S_IRUSR | S_IWUSR)) == -1) {
+ filebench_log(LOG_ERROR,
+ "could not create sysv semaphore set "
+ "(need to increase sems?): %s",
+ strerror(errno));
+ exit(1);
+ }
+}
+
+/*
+ * Initialize the Interprocess Communication system and its
+ * associated shared memory structure. It first creates a
+ * temporary file using either the mkstemp() function or the
+ * tempnam() and open() functions. If the process model is in
+ * use,it than sets the file large enough to hold the
+ * filebench_shm and an additional Megabyte. The file is then
+ * memory mapped. If the process model is not in use, it simply
+ * mallocs a region of sizeof (filebench_shm_t).
+ *
+ * Once the shared memory region / file is created, ipc_init
+ * initializes various locks pointers, and variables in the
+ * shared memory. It also uses ftok() to get a shared memory
+ * semaphore key for later use in allocating shared semaphores.
+ */
+void
+ipc_init(void)
+{
+ filebench_shm_t *buf = malloc(MB);
+ key_t key;
+ caddr_t c1;
+ caddr_t c2;
+#ifdef HAVE_SEM_RMID
+ int semid;
+#endif
+
+#ifdef HAVE_MKSTEMP
+ shmpath = (char *)malloc(128);
+ (void) strcpy(shmpath, "/var/tmp/fbenchXXXXXX");
+ shmfd = mkstemp(shmpath);
+#else
+ shmfd = open(shmpath, O_CREAT | O_RDWR | O_TRUNC, 0666);
+ shmpath = tempnam("/var/tmp", "fbench");
+#endif /* HAVE_MKSTEMP */
+
+#ifdef USE_PROCESS_MODEL
+
+ if (shmfd < 0) {
+ filebench_log(LOG_FATAL, "Cannot open shm %s: %s",
+ shmpath,
+ strerror(errno));
+ exit(1);
+ }
+
+ (void) lseek(shmfd, sizeof (filebench_shm_t), SEEK_SET);
+ if (write(shmfd, buf, MB) != MB) {
+ filebench_log(LOG_FATAL,
+ "Cannot allocate shm: %s", strerror(errno));
+ exit(1);
+ }
+
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ if ((filebench_shm = (filebench_shm_t *)mmap((caddr_t)0,
+ sizeof (filebench_shm_t), PROT_READ | PROT_WRITE, MAP_SHARED,
+ shmfd, 0)) == NULL) {
+ filebench_log(LOG_FATAL, "Cannot mmap shm");
+ exit(1);
+ }
+
+#else
+ if ((filebench_shm =
+ (filebench_shm_t *)malloc(sizeof (filebench_shm_t))) == NULL) {
+ filebench_log(LOG_FATAL, "Cannot malloc shm");
+ exit(1);
+ }
+#endif /* USE_PROCESS_MODEL */
+
+ c1 = (caddr_t)filebench_shm;
+ c2 = (caddr_t)&filebench_shm->marker;
+
+ (void) memset(filebench_shm, 0, c2 - c1);
+ filebench_shm->epoch = gethrtime();
+ filebench_shm->debug_level = 2;
+ filebench_shm->string_ptr = &filebench_shm->strings[0];
+ filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr;
+ filebench_shm->path_ptr = &filebench_shm->filesetpaths[0];
+
+ /* Setup mutexes for object lists */
+ (void) pthread_mutex_init(&filebench_shm->fileobj_lock,
+ ipc_mutexattr());
+ (void) pthread_mutex_init(&filebench_shm->fileset_lock,
+ ipc_mutexattr());
+ (void) pthread_mutex_init(&filebench_shm->procflow_lock,
+ ipc_mutexattr());
+ (void) pthread_mutex_init(&filebench_shm->threadflow_lock,
+ ipc_mutexattr());
+ (void) pthread_mutex_init(&filebench_shm->flowop_lock, ipc_mutexattr());
+ (void) pthread_mutex_init(&filebench_shm->msg_lock, ipc_mutexattr());
+ (void) pthread_mutex_init(&filebench_shm->eventgen_lock,
+ ipc_mutexattr());
+ (void) pthread_mutex_init(&filebench_shm->malloc_lock, ipc_mutexattr());
+ (void) pthread_mutex_init(&filebench_shm->ism_lock, ipc_mutexattr());
+ (void) pthread_cond_init(&filebench_shm->eventgen_cv, ipc_condattr());
+ (void) pthread_rwlock_init(&filebench_shm->flowop_find_lock,
+ ipc_rwlockattr());
+ (void) pthread_rwlock_init(&filebench_shm->run_lock, ipc_rwlockattr());
+ (void) pthread_rwlock_rdlock(&filebench_shm->run_lock);
+
+ (void) ipc_mutex_lock(&filebench_shm->ism_lock);
+
+ /* Create semaphore */
+ if ((key = ftok(shmpath, 1)) < 0) {
+ filebench_log(LOG_ERROR, "cannot create sem: %s",
+ strerror(errno));
+ exit(1);
+ }
+
+#ifdef HAVE_SEM_RMID
+ if ((semid = semget(key, 0, 0)) != -1)
+ (void) semctl(semid, 0, IPC_RMID);
+#endif
+
+ filebench_shm->semkey = key;
+ filebench_shm->log_fd = -1;
+ filebench_shm->dump_fd = -1;
+ filebench_shm->eventgen_hz = 0;
+ filebench_shm->shm_id = -1;
+
+ free(buf);
+}
+
+/*
+ * If compiled to use process model, just unlinks the shmpath.
+ * Otherwise a no-op.
+ */
+void
+ipc_cleanup(void)
+{
+#ifdef USE_PROCESS_MODEL
+ (void) unlink(shmpath);
+#endif /* USE_PROCESS_MODEL */
+}
+
+/*
+ * Attach to shared memory. Used by worker processes to open
+ * and mmap the shared memory region. If successful, it
+ * initializes the worker process' filebench_shm to point to
+ * the region and returns 0. Otherwise it returns -1.
+ */
+int
+ipc_attach(caddr_t shmaddr)
+{
+ if ((shmfd = open(shmpath, O_RDWR, 0666)) < 0) {
+ filebench_log(LOG_ERROR, "Cannot open shm");
+ return (-1);
+ }
+
+ /* LINTED E_BAD_PTR_CAST_ALIGN */
+ if ((filebench_shm = (filebench_shm_t *)mmap(shmaddr,
+ sizeof (filebench_shm_t), PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_FIXED, shmfd, 0)) == NULL) {
+ filebench_log(LOG_ERROR, "Cannot mmap shm");
+ return (-1);
+ }
+
+ filebench_log(LOG_DEBUG_IMPL, "addr = %zx", filebench_shm);
+
+ return (0);
+}
+
+static int filebench_sizes[] = {
+ FILEBENCH_NFILEOBJS,
+ FILEBENCH_NPROCFLOWS,
+ FILEBENCH_NTHREADFLOWS,
+ FILEBENCH_NFLOWOPS,
+ FILEBENCH_NVARS,
+ FILEBENCH_NVARS,
+ FILEBENCH_NVARS,
+ FILEBENCH_NFILESETS,
+ FILEBENCH_NFILESETENTRIES};
+
+/*
+ * Allocates filebench objects from pre allocated region of
+ * shareable memory. The memory region is partitioned into sets
+ * of objects during initialization. This routine scans for
+ * the first unallocated object of type "type" in the set of
+ * available objects, and makes it as allocated. The routine
+ * returns a pointer to the object, or NULL if all objects have
+ * been allocated.
+ */
+void *
+ipc_malloc(int type)
+{
+ int i;
+ int max = filebench_sizes[type];
+
+ (void) ipc_mutex_lock(&filebench_shm->malloc_lock);
+
+ for (i = 0; i < max; i++) {
+ if (filebench_shm->bitmap[type][i] == 0)
+ break;
+ }
+
+ if (i >= max) {
+ filebench_log(LOG_ERROR, "Out of shared memory (%d)!", type);
+ (void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
+ return (NULL);
+ }
+
+ filebench_shm->bitmap[type][i] = 1;
+
+ switch (type) {
+ case FILEBENCH_FILEOBJ:
+ (void) memset((char *)&filebench_shm->fileobj[i], 0,
+ sizeof (fileobj_t));
+ (void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
+ return ((char *)&filebench_shm->fileobj[i]);
+
+ case FILEBENCH_FILESET:
+ (void) memset((char *)&filebench_shm->fileset[i], 0,
+ sizeof (fileset_t));
+ (void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
+ return ((char *)&filebench_shm->fileset[i]);
+
+ case FILEBENCH_FILESETENTRY:
+ (void) memset((char *)&filebench_shm->filesetentry[i], 0,
+ sizeof (filesetentry_t));
+ (void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
+ return ((char *)&filebench_shm->filesetentry[i]);
+
+ case FILEBENCH_PROCFLOW:
+ (void) memset((char *)&filebench_shm->procflow[i], 0,
+ sizeof (procflow_t));
+ (void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
+ return ((char *)&filebench_shm->procflow[i]);
+
+ case FILEBENCH_THREADFLOW:
+ (void) memset((char *)&filebench_shm->threadflow[i], 0,
+ sizeof (threadflow_t));
+ (void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
+ return ((char *)&filebench_shm->threadflow[i]);
+
+ case FILEBENCH_FLOWOP:
+ (void) memset((char *)&filebench_shm->flowop[i], 0,
+ sizeof (flowop_t));
+ (void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
+ return ((char *)&filebench_shm->flowop[i]);
+
+ case FILEBENCH_INTEGER:
+ filebench_shm->integer_ptrs[i] = NULL;
+ (void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
+ return ((char *)&filebench_shm->integer_ptrs[i]);
+
+ case FILEBENCH_STRING:
+ filebench_shm->string_ptrs[i] = NULL;
+ (void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
+ return ((char *)&filebench_shm->string_ptrs[i]);
+
+ case FILEBENCH_VARIABLE:
+ (void) memset((char *)&filebench_shm->var[i], 0,
+ sizeof (var_t));
+ (void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
+ return ((char *)&filebench_shm->var[i]);
+ }
+
+ filebench_log(LOG_ERROR, "Attempt to ipc_malloc unknown type (%d)!",
+ type);
+ return (NULL);
+}
+
+/*
+ * Frees a filebench object of type "type" at the location
+ * pointed to by "addr". It uses the type and address to
+ * calculate which object is being freed, and clears its
+ * allocation map entry.
+ */
+void
+ipc_free(int type, char *addr)
+{
+ int item;
+ caddr_t base;
+ size_t offset;
+ size_t size;
+
+ if (addr == NULL) {
+ filebench_log(LOG_ERROR, "Freeing type %d %zx", type, addr);
+ return;
+ }
+
+ switch (type) {
+ case FILEBENCH_FILEOBJ:
+ base = (caddr_t)&filebench_shm->fileobj[0];
+ size = sizeof (fileobj_t);
+ break;
+
+ case FILEBENCH_FILESET:
+ base = (caddr_t)&filebench_shm->fileset[0];
+ size = sizeof (fileset_t);
+ break;
+
+ case FILEBENCH_FILESETENTRY:
+ base = (caddr_t)&filebench_shm->filesetentry[0];
+ size = sizeof (filesetentry_t);
+ break;
+
+ case FILEBENCH_PROCFLOW:
+ base = (caddr_t)&filebench_shm->procflow[0];
+ size = sizeof (procflow_t);
+ break;
+
+ case FILEBENCH_THREADFLOW:
+ base = (caddr_t)&filebench_shm->threadflow[0];
+ size = sizeof (threadflow_t);
+ break;
+
+ case FILEBENCH_FLOWOP:
+ base = (caddr_t)&filebench_shm->flowop[0];
+ size = sizeof (flowop_t);
+ break;
+
+ case FILEBENCH_INTEGER:
+ base = (caddr_t)&filebench_shm->integer_ptrs[0];
+ size = sizeof (caddr_t);
+ break;
+
+ case FILEBENCH_STRING:
+ base = (caddr_t)&filebench_shm->string_ptrs[0];
+ size = sizeof (caddr_t);
+ break;
+
+ case FILEBENCH_VARIABLE:
+ base = (caddr_t)&filebench_shm->var[0];
+ size = sizeof (var_t);
+ break;
+ }
+
+ offset = ((size_t)addr - (size_t)base);
+ item = offset / size;
+
+ (void) ipc_mutex_lock(&filebench_shm->malloc_lock);
+ filebench_shm->bitmap[type][item] = 0;
+ (void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
+}
+
+/*
+ * Allocate a string from filebench string memory. The length
+ * of the allocated string is the same as the length of the
+ * supplied string "string", and the contents of string are
+ * copied to the newly allocated string.
+ */
+char *
+ipc_stralloc(char *string)
+{
+ char *allocstr = filebench_shm->string_ptr;
+
+ filebench_shm->string_ptr += strlen(string) + 1;
+
+ if ((filebench_shm->string_ptr - &filebench_shm->strings[0]) >
+ FILEBENCH_STRINGMEMORY) {
+ filebench_log(LOG_ERROR, "Out of ipc string memory");
+ return (NULL);
+ }
+
+ (void) strncpy(allocstr, string, strlen(string));
+
+ return (allocstr);
+}
+
+/*
+ * Allocate a path string from filebench path string memory.
+ * Specifically used for allocating fileset paths. The length
+ * of the allocated path string is the same as the length of
+ * the supplied path string "path", and the contents of path
+ * are copied to the newly allocated path string. Checks for
+ * out-of-path-string-memory condition and returns NULL if so.
+ * Otherwise it returns a pointer to the newly allocated path
+ * string.
+ */
+char *
+ipc_pathalloc(char *path)
+{
+ char *allocpath = filebench_shm->path_ptr;
+
+ filebench_shm->path_ptr += strlen(path) + 1;
+
+ if ((filebench_shm->path_ptr - &filebench_shm->filesetpaths[0]) >
+ FILEBENCH_FILESETPATHMEMORY) {
+ filebench_log(LOG_ERROR, "Out of fileset path memory");
+ return (NULL);
+ }
+
+ (void) strncpy(allocpath, path, strlen(path));
+
+ return (allocpath);
+}
+
+/*
+ * This is a limited functionality deallocator for path
+ * strings - it can only free all path strings at once,
+ * in order to avoid fragmentation.
+ */
+void
+ipc_freepaths(void)
+{
+ filebench_shm->path_ptr = &filebench_shm->filesetpaths[0];
+}
+
+/*
+ * Allocates a semid from the table of semids for pre intialized
+ * semaphores. Searches for the first available semaphore, and
+ * sets the entry in the table to "1" to indicate allocation.
+ * Returns the allocated semid. Stops the run if all semaphores
+ * are already in use.
+ */
+int
+ipc_semidalloc(void)
+{
+ int semid;
+
+ for (semid = 0; filebench_shm->semids[semid] == 1; semid++)
+ ;
+ if (semid == FILEBENCH_NSEMS) {
+ filebench_log(LOG_ERROR,
+ "Out of semaphores, increase system tunable limit");
+ filebench_shutdown(1);
+ }
+ filebench_shm->semids[semid] = 1;
+ return (semid);
+}
+
+/*
+ * Frees up the supplied semid by seting its position in the
+ * allocation table to "0".
+ */
+void
+ipc_semidfree(int semid)
+{
+ filebench_shm->semids[semid] = 0;
+}
+
+/*
+ * Create a pool of shared memory to fit the per-thread
+ * allocations. Uses shmget() to create a shared memory region
+ * of size "size", attaches to it using shmat(), and stores
+ * the returned address of the region in filebench_shm->shm_addr.
+ * The pool is only created on the first call. The routine
+ * returns 0 if successful or the pool already exists,
+ * -1 otherwise.
+ */
+int
+ipc_ismcreate(size_t size)
+{
+#ifdef HAVE_SHM_SHARE_MMU
+ int flag = SHM_SHARE_MMU;
+#else
+ int flag = 0;
+#endif /* HAVE_SHM_SHARE_MMU */
+
+ /* Already done? */
+ if (filebench_shm->shm_id != -1)
+ return (0);
+
+ filebench_log(LOG_VERBOSE,
+ "Creating %zd bytes of ISM Shared Memory...", size);
+
+ if ((filebench_shm->shm_id =
+ shmget(0, size, IPC_CREAT | 0666)) == -1) {
+ filebench_log(LOG_ERROR,
+ "Failed to create %zd bytes of ISM shared memory", size);
+ return (-1);
+ }
+
+ if ((filebench_shm->shm_addr = (caddr_t)shmat(filebench_shm->shm_id,
+ 0, flag)) == (void *)-1) {
+ filebench_log(LOG_ERROR,
+ "Failed to attach %zd bytes of created ISM shared memory",
+ size);
+ return (-1);
+ }
+
+ filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr;
+
+ filebench_log(LOG_VERBOSE,
+ "Allocated %zd bytes of ISM Shared Memory... at %zx",
+ size, filebench_shm->shm_addr);
+
+ /* Locked until allocated to block allocs */
+ (void) ipc_mutex_unlock(&filebench_shm->ism_lock);
+
+ return (0);
+}
+
+/* Per addr space ism */
+static int ism_attached = 0;
+
+/*
+ * Attach to interprocess shared memory. If already attached
+ * just return, otherwise use shmat() to attached to the region
+ * with ID of filebench_shm->shm_id. Returns -1 if shmat()
+ * fails, otherwise 0.
+ */
+static int
+ipc_ismattach(void)
+{
+#ifdef HAVE_SHM_SHARE_MMU
+ int flag = SHM_SHARE_MMU;
+#else
+ int flag = 0;
+#endif /* HAVE_SHM_SHARE_MMU */
+
+
+ if (ism_attached)
+ return (0);
+
+ /* Does it exist? */
+ if (filebench_shm->shm_id == 999)
+ return (0);
+
+ if (shmat(filebench_shm->shm_id, filebench_shm->shm_addr,
+ flag) == NULL)
+ return (-1);
+
+ ism_attached = 1;
+
+ return (0);
+}
+
+/*
+ * Allocate from interprocess shared memory. Attaches to ism
+ * if necessary, then allocates "size" bytes, updates allocation
+ * information and returns a pointer to the allocated memory.
+ */
+/*
+ * XXX No check is made for out-of-memory condition
+ */
+char *
+ipc_ismmalloc(size_t size)
+{
+ char *allocstr;
+
+ (void) ipc_mutex_lock(&filebench_shm->ism_lock);
+
+ /* Map in shared memory */
+ (void) ipc_ismattach();
+
+ allocstr = filebench_shm->shm_ptr;
+
+ filebench_shm->shm_ptr += size;
+ filebench_shm->shm_allocated += size;
+
+ (void) ipc_mutex_unlock(&filebench_shm->ism_lock);
+
+ return (allocstr);
+}
+
+/*
+ * Deletes shared memory region and resets shared memory region
+ * information in filebench_shm.
+ */
+void
+ipc_ismdelete(void)
+{
+ if (filebench_shm->shm_id == -1)
+ return;
+
+ filebench_log(LOG_VERBOSE, "Deleting ISM...");
+
+ (void) ipc_mutex_lock(&filebench_shm->ism_lock);
+#ifdef HAVE_SEM_RMID
+ (void) shmctl(filebench_shm->shm_id, IPC_RMID, 0);
+#endif
+ filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr;
+ filebench_shm->shm_id = -1;
+ filebench_shm->shm_allocated = 0;
+ (void) ipc_mutex_unlock(&filebench_shm->ism_lock);
+}