xref: /onnv-gate/usr/src/cmd/filebench/common/ipc.c (revision 5184:da60d2b4a9e2)
1*5184Sek110237 /*
2*5184Sek110237  * CDDL HEADER START
3*5184Sek110237  *
4*5184Sek110237  * The contents of this file are subject to the terms of the
5*5184Sek110237  * Common Development and Distribution License (the "License").
6*5184Sek110237  * You may not use this file except in compliance with the License.
7*5184Sek110237  *
8*5184Sek110237  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5184Sek110237  * or http://www.opensolaris.org/os/licensing.
10*5184Sek110237  * See the License for the specific language governing permissions
11*5184Sek110237  * and limitations under the License.
12*5184Sek110237  *
13*5184Sek110237  * When distributing Covered Code, include this CDDL HEADER in each
14*5184Sek110237  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5184Sek110237  * If applicable, add the following below this CDDL HEADER, with the
16*5184Sek110237  * fields enclosed by brackets "[]" replaced with your own identifying
17*5184Sek110237  * information: Portions Copyright [yyyy] [name of copyright owner]
18*5184Sek110237  *
19*5184Sek110237  * CDDL HEADER END
20*5184Sek110237  */
21*5184Sek110237 /*
22*5184Sek110237  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*5184Sek110237  * Use is subject to license terms.
24*5184Sek110237  */
25*5184Sek110237 
26*5184Sek110237 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*5184Sek110237 
28*5184Sek110237 #include "config.h"
29*5184Sek110237 
30*5184Sek110237 #include <stdio.h>
31*5184Sek110237 #include <fcntl.h>
32*5184Sek110237 #include <sys/mman.h>
33*5184Sek110237 #include <sys/ipc.h>
34*5184Sek110237 #include <sys/sem.h>
35*5184Sek110237 #include <sys/errno.h>
36*5184Sek110237 #include <signal.h>
37*5184Sek110237 #include <pthread.h>
38*5184Sek110237 #include <sys/shm.h>
39*5184Sek110237 #include "filebench.h"
40*5184Sek110237 
41*5184Sek110237 /* IPC Hub and Simple memory allocator */
42*5184Sek110237 
43*5184Sek110237 static int shmfd;
44*5184Sek110237 filebench_shm_t *filebench_shm = NULL;
45*5184Sek110237 static pthread_mutexattr_t *mutexattr = NULL;
46*5184Sek110237 
47*5184Sek110237 /*
48*5184Sek110237  * Interprocess Communication mechanisms. If multiple processes
49*5184Sek110237  * are used, filebench opens a shared file in memory mapped mode to hold
50*5184Sek110237  * a variety of global variables and data structures. If only using
51*5184Sek110237  * multiple threads, it just allocates a region of local memory. A
52*5184Sek110237  * region of interprocess shared memory and a set of shared semaphores
53*5184Sek110237  * are also created. Routines are provided to manage the creation,
54*5184Sek110237  * destruction, and allocation of these resoures.
55*5184Sek110237  */
56*5184Sek110237 
57*5184Sek110237 
58*5184Sek110237 /*
59*5184Sek110237  * Locks a mutex and logs any errors.
60*5184Sek110237  */
61*5184Sek110237 int
62*5184Sek110237 ipc_mutex_lock(pthread_mutex_t *mutex)
63*5184Sek110237 {
64*5184Sek110237 	int error;
65*5184Sek110237 
66*5184Sek110237 	error = pthread_mutex_lock(mutex);
67*5184Sek110237 
68*5184Sek110237 #ifdef HAVE_ROBUST_MUTEX
69*5184Sek110237 	if (error == EOWNERDEAD) {
70*5184Sek110237 		if (pthread_mutex_consistent_np(mutex) != 0) {
71*5184Sek110237 			filebench_log(LOG_FATAL, "mutex make consistent "
72*5184Sek110237 			    "failed: %s", strerror(error));
73*5184Sek110237 			return (-1);
74*5184Sek110237 		}
75*5184Sek110237 		return (0);
76*5184Sek110237 	}
77*5184Sek110237 #endif /* HAVE_ROBUST_MUTEX */
78*5184Sek110237 
79*5184Sek110237 	if (error != 0) {
80*5184Sek110237 		filebench_log(LOG_FATAL, "mutex lock failed: %s",
81*5184Sek110237 		    strerror(error));
82*5184Sek110237 	}
83*5184Sek110237 
84*5184Sek110237 	return (error);
85*5184Sek110237 }
86*5184Sek110237 
87*5184Sek110237 /*
88*5184Sek110237  * Unlocks a mutex and logs any errors.
89*5184Sek110237  */
90*5184Sek110237 int
91*5184Sek110237 ipc_mutex_unlock(pthread_mutex_t *mutex)
92*5184Sek110237 {
93*5184Sek110237 	int error;
94*5184Sek110237 
95*5184Sek110237 	error = pthread_mutex_unlock(mutex);
96*5184Sek110237 
97*5184Sek110237 #ifdef HAVE_ROBUST_MUTEX
98*5184Sek110237 	if (error == EOWNERDEAD) {
99*5184Sek110237 		if (pthread_mutex_consistent_np(mutex) != 0) {
100*5184Sek110237 			filebench_log(LOG_FATAL, "mutex make consistent "
101*5184Sek110237 			    "failed: %s", strerror(error));
102*5184Sek110237 			return (-1);
103*5184Sek110237 		}
104*5184Sek110237 		return (0);
105*5184Sek110237 	}
106*5184Sek110237 #endif /* HAVE_ROBUST_MUTEX */
107*5184Sek110237 
108*5184Sek110237 	if (error != 0) {
109*5184Sek110237 		filebench_log(LOG_FATAL, "mutex unlock failed: %s",
110*5184Sek110237 		    strerror(error));
111*5184Sek110237 	}
112*5184Sek110237 
113*5184Sek110237 	return (error);
114*5184Sek110237 }
115*5184Sek110237 
116*5184Sek110237 /*
117*5184Sek110237  * On first invocation, allocates a mutex attributes structure
118*5184Sek110237  * and initializes it with appropriate attributes. In all cases,
119*5184Sek110237  * returns a pointer to the structure.
120*5184Sek110237  */
121*5184Sek110237 pthread_mutexattr_t *
122*5184Sek110237 ipc_mutexattr(void)
123*5184Sek110237 {
124*5184Sek110237 #ifdef USE_PROCESS_MODEL
125*5184Sek110237 	if (mutexattr == NULL) {
126*5184Sek110237 		if ((mutexattr =
127*5184Sek110237 		    malloc(sizeof (pthread_mutexattr_t))) == NULL) {
128*5184Sek110237 			filebench_log(LOG_ERROR, "cannot alloc mutex attr");
129*5184Sek110237 			filebench_shutdown(1);
130*5184Sek110237 		}
131*5184Sek110237 #ifdef HAVE_PROCSCOPE_PTHREADS
132*5184Sek110237 		(void) pthread_mutexattr_init(mutexattr);
133*5184Sek110237 		if (pthread_mutexattr_setpshared(mutexattr,
134*5184Sek110237 		    PTHREAD_PROCESS_SHARED) != 0) {
135*5184Sek110237 			filebench_log(LOG_ERROR, "cannot set mutex attr "
136*5184Sek110237 			    "PROCESS_SHARED on this platform");
137*5184Sek110237 			filebench_shutdown(1);
138*5184Sek110237 		}
139*5184Sek110237 #ifdef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL
140*5184Sek110237 		if (pthread_mutexattr_setprotocol(mutexattr,
141*5184Sek110237 		    PTHREAD_PRIO_INHERIT) != 0) {
142*5184Sek110237 			filebench_log(LOG_ERROR, "cannot set mutex attr "
143*5184Sek110237 			    "PTHREAD_PRIO_INHERIT on this platform");
144*5184Sek110237 			filebench_shutdown(1);
145*5184Sek110237 		}
146*5184Sek110237 #endif /* HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL */
147*5184Sek110237 #endif /* HAVE_PROCSCOPE_PTHREADS */
148*5184Sek110237 #ifdef HAVE_ROBUST_MUTEX
149*5184Sek110237 		if (pthread_mutexattr_setrobust_np(mutexattr,
150*5184Sek110237 		    PTHREAD_MUTEX_ROBUST_NP) != 0) {
151*5184Sek110237 			filebench_log(LOG_ERROR, "cannot set mutex attr "
152*5184Sek110237 			    "PTHREAD_MUTEX_ROBUST_NP on this platform");
153*5184Sek110237 			filebench_shutdown(1);
154*5184Sek110237 		}
155*5184Sek110237 		if (pthread_mutexattr_settype(mutexattr,
156*5184Sek110237 		    PTHREAD_MUTEX_ERRORCHECK) != 0) {
157*5184Sek110237 			filebench_log(LOG_ERROR, "cannot set mutex attr "
158*5184Sek110237 			    "PTHREAD_MUTEX_ERRORCHECK on this platform");
159*5184Sek110237 			filebench_shutdown(1);
160*5184Sek110237 		}
161*5184Sek110237 #endif /* HAVE_ROBUST_MUTEX */
162*5184Sek110237 
163*5184Sek110237 	}
164*5184Sek110237 #endif /* USE_PROCESS_MODEL */
165*5184Sek110237 	return (mutexattr);
166*5184Sek110237 }
167*5184Sek110237 
168*5184Sek110237 static pthread_condattr_t *condattr = NULL;
169*5184Sek110237 
170*5184Sek110237 /*
171*5184Sek110237  * On first invocation, allocates a condition variable attributes
172*5184Sek110237  * structure and initializes it with appropriate attributes. In
173*5184Sek110237  * all cases, returns a pointer to the structure.
174*5184Sek110237  */
175*5184Sek110237 pthread_condattr_t *
176*5184Sek110237 ipc_condattr(void)
177*5184Sek110237 {
178*5184Sek110237 #ifdef USE_PROCESS_MODEL
179*5184Sek110237 	if (condattr == NULL) {
180*5184Sek110237 		if ((condattr = malloc(sizeof (pthread_condattr_t))) == NULL) {
181*5184Sek110237 			filebench_log(LOG_ERROR, "cannot alloc cond attr");
182*5184Sek110237 			filebench_shutdown(1);
183*5184Sek110237 		}
184*5184Sek110237 #ifdef HAVE_PROCSCOPE_PTHREADS
185*5184Sek110237 		(void) pthread_condattr_init(condattr);
186*5184Sek110237 		if (pthread_condattr_setpshared(condattr,
187*5184Sek110237 		    PTHREAD_PROCESS_SHARED) != 0) {
188*5184Sek110237 			filebench_log(LOG_ERROR,
189*5184Sek110237 			    "cannot set cond attr PROCESS_SHARED");
190*5184Sek110237 			filebench_shutdown(1);
191*5184Sek110237 		}
192*5184Sek110237 #endif /* HAVE_PROCSCOPE_PTHREADS */
193*5184Sek110237 	}
194*5184Sek110237 #endif /* USE_PROCESS_MODEL */
195*5184Sek110237 	return (condattr);
196*5184Sek110237 }
197*5184Sek110237 
198*5184Sek110237 static pthread_rwlockattr_t *rwlockattr = NULL;
199*5184Sek110237 
200*5184Sek110237 /*
201*5184Sek110237  * On first invocation, allocates a readers/writers attributes
202*5184Sek110237  * structure and initializes it with appropriate attributes.
203*5184Sek110237  * In all cases, returns a pointer to the structure.
204*5184Sek110237  */
205*5184Sek110237 static pthread_rwlockattr_t *
206*5184Sek110237 ipc_rwlockattr(void)
207*5184Sek110237 {
208*5184Sek110237 #ifdef USE_PROCESS_MODEL
209*5184Sek110237 	if (rwlockattr == NULL) {
210*5184Sek110237 		if ((rwlockattr =
211*5184Sek110237 		    malloc(sizeof (pthread_rwlockattr_t))) == NULL) {
212*5184Sek110237 			filebench_log(LOG_ERROR, "cannot alloc rwlock attr");
213*5184Sek110237 			filebench_shutdown(1);
214*5184Sek110237 		}
215*5184Sek110237 #ifdef HAVE_PROCSCOPE_PTHREADS
216*5184Sek110237 		(void) pthread_rwlockattr_init(rwlockattr);
217*5184Sek110237 		if (pthread_rwlockattr_setpshared(rwlockattr,
218*5184Sek110237 		    PTHREAD_PROCESS_SHARED) != 0) {
219*5184Sek110237 			filebench_log(LOG_ERROR,
220*5184Sek110237 			    "cannot set rwlock attr PROCESS_SHARED");
221*5184Sek110237 			filebench_shutdown(1);
222*5184Sek110237 		}
223*5184Sek110237 #endif /* HAVE_PROCSCOPE_PTHREADS */
224*5184Sek110237 	}
225*5184Sek110237 #endif /* USE_PROCESS_MODEL */
226*5184Sek110237 	return (rwlockattr);
227*5184Sek110237 }
228*5184Sek110237 
229*5184Sek110237 char *shmpath = NULL;
230*5184Sek110237 
231*5184Sek110237 /*
232*5184Sek110237  * Calls semget() to get a set of shared system V semaphores.
233*5184Sek110237  */
234*5184Sek110237 void
235*5184Sek110237 ipc_seminit(void)
236*5184Sek110237 {
237*5184Sek110237 	key_t key = filebench_shm->semkey;
238*5184Sek110237 
239*5184Sek110237 	/* Already done? */
240*5184Sek110237 	if (filebench_shm->seminit)
241*5184Sek110237 		return;
242*5184Sek110237 
243*5184Sek110237 	if ((semget(key, FILEBENCH_NSEMS, IPC_CREAT |
244*5184Sek110237 	    S_IRUSR | S_IWUSR)) == -1) {
245*5184Sek110237 		filebench_log(LOG_ERROR,
246*5184Sek110237 		    "could not create sysv semaphore set "
247*5184Sek110237 		    "(need to increase sems?): %s",
248*5184Sek110237 		    strerror(errno));
249*5184Sek110237 		exit(1);
250*5184Sek110237 	}
251*5184Sek110237 }
252*5184Sek110237 
253*5184Sek110237 /*
254*5184Sek110237  * Initialize the Interprocess Communication system and its
255*5184Sek110237  * associated shared memory structure. It first creates a
256*5184Sek110237  * temporary file using either the mkstemp() function or the
257*5184Sek110237  * tempnam() and open() functions. If the process model is in
258*5184Sek110237  * use,it than sets the file large enough to hold the
259*5184Sek110237  * filebench_shm and an additional Megabyte. The file is then
260*5184Sek110237  * memory mapped. If the process model is not in use, it simply
261*5184Sek110237  * mallocs a region of sizeof (filebench_shm_t).
262*5184Sek110237  *
263*5184Sek110237  * Once the shared memory region / file is created, ipc_init
264*5184Sek110237  * initializes various locks pointers, and variables in the
265*5184Sek110237  * shared memory. It also uses ftok() to get a shared memory
266*5184Sek110237  * semaphore key for later use in allocating shared semaphores.
267*5184Sek110237  */
268*5184Sek110237 void
269*5184Sek110237 ipc_init(void)
270*5184Sek110237 {
271*5184Sek110237 	filebench_shm_t *buf = malloc(MB);
272*5184Sek110237 	key_t key;
273*5184Sek110237 	caddr_t c1;
274*5184Sek110237 	caddr_t c2;
275*5184Sek110237 #ifdef HAVE_SEM_RMID
276*5184Sek110237 	int semid;
277*5184Sek110237 #endif
278*5184Sek110237 
279*5184Sek110237 #ifdef HAVE_MKSTEMP
280*5184Sek110237 	shmpath = (char *)malloc(128);
281*5184Sek110237 	(void) strcpy(shmpath, "/var/tmp/fbenchXXXXXX");
282*5184Sek110237 	shmfd = mkstemp(shmpath);
283*5184Sek110237 #else
284*5184Sek110237 	shmfd   = open(shmpath, O_CREAT | O_RDWR | O_TRUNC, 0666);
285*5184Sek110237 	shmpath = tempnam("/var/tmp", "fbench");
286*5184Sek110237 #endif	/* HAVE_MKSTEMP */
287*5184Sek110237 
288*5184Sek110237 #ifdef USE_PROCESS_MODEL
289*5184Sek110237 
290*5184Sek110237 	if (shmfd  < 0) {
291*5184Sek110237 		filebench_log(LOG_FATAL, "Cannot open shm %s: %s",
292*5184Sek110237 		    shmpath,
293*5184Sek110237 		    strerror(errno));
294*5184Sek110237 		exit(1);
295*5184Sek110237 	}
296*5184Sek110237 
297*5184Sek110237 	(void) lseek(shmfd, sizeof (filebench_shm_t), SEEK_SET);
298*5184Sek110237 	if (write(shmfd, buf, MB) != MB) {
299*5184Sek110237 		filebench_log(LOG_FATAL,
300*5184Sek110237 		    "Cannot allocate shm: %s", strerror(errno));
301*5184Sek110237 		exit(1);
302*5184Sek110237 	}
303*5184Sek110237 
304*5184Sek110237 	/* LINTED E_BAD_PTR_CAST_ALIGN */
305*5184Sek110237 	if ((filebench_shm = (filebench_shm_t *)mmap((caddr_t)0,
306*5184Sek110237 	    sizeof (filebench_shm_t), PROT_READ | PROT_WRITE, MAP_SHARED,
307*5184Sek110237 	    shmfd, 0)) == NULL) {
308*5184Sek110237 		filebench_log(LOG_FATAL, "Cannot mmap shm");
309*5184Sek110237 		exit(1);
310*5184Sek110237 	}
311*5184Sek110237 
312*5184Sek110237 #else
313*5184Sek110237 	if ((filebench_shm =
314*5184Sek110237 	    (filebench_shm_t *)malloc(sizeof (filebench_shm_t))) == NULL) {
315*5184Sek110237 		filebench_log(LOG_FATAL, "Cannot malloc shm");
316*5184Sek110237 		exit(1);
317*5184Sek110237 	}
318*5184Sek110237 #endif /* USE_PROCESS_MODEL */
319*5184Sek110237 
320*5184Sek110237 	c1 = (caddr_t)filebench_shm;
321*5184Sek110237 	c2 = (caddr_t)&filebench_shm->marker;
322*5184Sek110237 
323*5184Sek110237 	(void) memset(filebench_shm, 0, c2 - c1);
324*5184Sek110237 	filebench_shm->epoch = gethrtime();
325*5184Sek110237 	filebench_shm->debug_level = 2;
326*5184Sek110237 	filebench_shm->string_ptr = &filebench_shm->strings[0];
327*5184Sek110237 	filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr;
328*5184Sek110237 	filebench_shm->path_ptr = &filebench_shm->filesetpaths[0];
329*5184Sek110237 
330*5184Sek110237 	/* Setup mutexes for object lists */
331*5184Sek110237 	(void) pthread_mutex_init(&filebench_shm->fileobj_lock,
332*5184Sek110237 	    ipc_mutexattr());
333*5184Sek110237 	(void) pthread_mutex_init(&filebench_shm->fileset_lock,
334*5184Sek110237 	    ipc_mutexattr());
335*5184Sek110237 	(void) pthread_mutex_init(&filebench_shm->procflow_lock,
336*5184Sek110237 	    ipc_mutexattr());
337*5184Sek110237 	(void) pthread_mutex_init(&filebench_shm->threadflow_lock,
338*5184Sek110237 	    ipc_mutexattr());
339*5184Sek110237 	(void) pthread_mutex_init(&filebench_shm->flowop_lock, ipc_mutexattr());
340*5184Sek110237 	(void) pthread_mutex_init(&filebench_shm->msg_lock, ipc_mutexattr());
341*5184Sek110237 	(void) pthread_mutex_init(&filebench_shm->eventgen_lock,
342*5184Sek110237 	    ipc_mutexattr());
343*5184Sek110237 	(void) pthread_mutex_init(&filebench_shm->malloc_lock, ipc_mutexattr());
344*5184Sek110237 	(void) pthread_mutex_init(&filebench_shm->ism_lock, ipc_mutexattr());
345*5184Sek110237 	(void) pthread_cond_init(&filebench_shm->eventgen_cv, ipc_condattr());
346*5184Sek110237 	(void) pthread_rwlock_init(&filebench_shm->flowop_find_lock,
347*5184Sek110237 	    ipc_rwlockattr());
348*5184Sek110237 	(void) pthread_rwlock_init(&filebench_shm->run_lock, ipc_rwlockattr());
349*5184Sek110237 	(void) pthread_rwlock_rdlock(&filebench_shm->run_lock);
350*5184Sek110237 
351*5184Sek110237 	(void) ipc_mutex_lock(&filebench_shm->ism_lock);
352*5184Sek110237 
353*5184Sek110237 	/* Create semaphore */
354*5184Sek110237 	if ((key = ftok(shmpath, 1)) < 0) {
355*5184Sek110237 		filebench_log(LOG_ERROR, "cannot create sem: %s",
356*5184Sek110237 		    strerror(errno));
357*5184Sek110237 		exit(1);
358*5184Sek110237 	}
359*5184Sek110237 
360*5184Sek110237 #ifdef HAVE_SEM_RMID
361*5184Sek110237 	if ((semid = semget(key, 0, 0)) != -1)
362*5184Sek110237 		(void) semctl(semid, 0, IPC_RMID);
363*5184Sek110237 #endif
364*5184Sek110237 
365*5184Sek110237 	filebench_shm->semkey = key;
366*5184Sek110237 	filebench_shm->log_fd = -1;
367*5184Sek110237 	filebench_shm->dump_fd = -1;
368*5184Sek110237 	filebench_shm->eventgen_hz = 0;
369*5184Sek110237 	filebench_shm->shm_id = -1;
370*5184Sek110237 
371*5184Sek110237 	free(buf);
372*5184Sek110237 }
373*5184Sek110237 
374*5184Sek110237 /*
375*5184Sek110237  * If compiled to use process model, just unlinks the shmpath.
376*5184Sek110237  * Otherwise a no-op.
377*5184Sek110237  */
378*5184Sek110237 void
379*5184Sek110237 ipc_cleanup(void)
380*5184Sek110237 {
381*5184Sek110237 #ifdef USE_PROCESS_MODEL
382*5184Sek110237 	(void) unlink(shmpath);
383*5184Sek110237 #endif /* USE_PROCESS_MODEL */
384*5184Sek110237 }
385*5184Sek110237 
386*5184Sek110237 /*
387*5184Sek110237  * Attach to shared memory. Used by worker processes to open
388*5184Sek110237  * and mmap the shared memory region. If successful, it
389*5184Sek110237  * initializes the worker process' filebench_shm to point to
390*5184Sek110237  * the region and returns 0. Otherwise it returns -1.
391*5184Sek110237  */
392*5184Sek110237 int
393*5184Sek110237 ipc_attach(caddr_t shmaddr)
394*5184Sek110237 {
395*5184Sek110237 	if ((shmfd = open(shmpath, O_RDWR, 0666)) < 0) {
396*5184Sek110237 		filebench_log(LOG_ERROR, "Cannot open shm");
397*5184Sek110237 		return (-1);
398*5184Sek110237 	}
399*5184Sek110237 
400*5184Sek110237 	/* LINTED E_BAD_PTR_CAST_ALIGN */
401*5184Sek110237 	if ((filebench_shm = (filebench_shm_t *)mmap(shmaddr,
402*5184Sek110237 	    sizeof (filebench_shm_t), PROT_READ | PROT_WRITE,
403*5184Sek110237 	    MAP_SHARED | MAP_FIXED, shmfd, 0)) == NULL) {
404*5184Sek110237 		filebench_log(LOG_ERROR, "Cannot mmap shm");
405*5184Sek110237 		return (-1);
406*5184Sek110237 	}
407*5184Sek110237 
408*5184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "addr = %zx", filebench_shm);
409*5184Sek110237 
410*5184Sek110237 	return (0);
411*5184Sek110237 }
412*5184Sek110237 
413*5184Sek110237 static int filebench_sizes[] = {
414*5184Sek110237 	FILEBENCH_NFILEOBJS,
415*5184Sek110237 	FILEBENCH_NPROCFLOWS,
416*5184Sek110237 	FILEBENCH_NTHREADFLOWS,
417*5184Sek110237 	FILEBENCH_NFLOWOPS,
418*5184Sek110237 	FILEBENCH_NVARS,
419*5184Sek110237 	FILEBENCH_NVARS,
420*5184Sek110237 	FILEBENCH_NVARS,
421*5184Sek110237 	FILEBENCH_NFILESETS,
422*5184Sek110237 	FILEBENCH_NFILESETENTRIES};
423*5184Sek110237 
424*5184Sek110237 /*
425*5184Sek110237  * Allocates filebench objects from pre allocated region of
426*5184Sek110237  * shareable memory. The memory region is partitioned into sets
427*5184Sek110237  * of objects during initialization. This routine scans for
428*5184Sek110237  * the first unallocated object of type "type" in the set of
429*5184Sek110237  * available objects, and makes it as allocated. The routine
430*5184Sek110237  * returns a pointer to the object, or NULL if all objects have
431*5184Sek110237  * been allocated.
432*5184Sek110237  */
433*5184Sek110237 void *
434*5184Sek110237 ipc_malloc(int type)
435*5184Sek110237 {
436*5184Sek110237 	int i;
437*5184Sek110237 	int max = filebench_sizes[type];
438*5184Sek110237 
439*5184Sek110237 	(void) ipc_mutex_lock(&filebench_shm->malloc_lock);
440*5184Sek110237 
441*5184Sek110237 	for (i = 0; i < max; i++) {
442*5184Sek110237 		if (filebench_shm->bitmap[type][i] == 0)
443*5184Sek110237 			break;
444*5184Sek110237 	}
445*5184Sek110237 
446*5184Sek110237 	if (i >= max) {
447*5184Sek110237 		filebench_log(LOG_ERROR, "Out of shared memory (%d)!", type);
448*5184Sek110237 		(void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
449*5184Sek110237 		return (NULL);
450*5184Sek110237 	}
451*5184Sek110237 
452*5184Sek110237 	filebench_shm->bitmap[type][i] = 1;
453*5184Sek110237 
454*5184Sek110237 	switch (type) {
455*5184Sek110237 	case FILEBENCH_FILEOBJ:
456*5184Sek110237 		(void) memset((char *)&filebench_shm->fileobj[i], 0,
457*5184Sek110237 		    sizeof (fileobj_t));
458*5184Sek110237 		(void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
459*5184Sek110237 		return ((char *)&filebench_shm->fileobj[i]);
460*5184Sek110237 
461*5184Sek110237 	case FILEBENCH_FILESET:
462*5184Sek110237 		(void) memset((char *)&filebench_shm->fileset[i], 0,
463*5184Sek110237 		    sizeof (fileset_t));
464*5184Sek110237 		(void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
465*5184Sek110237 		return ((char *)&filebench_shm->fileset[i]);
466*5184Sek110237 
467*5184Sek110237 	case FILEBENCH_FILESETENTRY:
468*5184Sek110237 		(void) memset((char *)&filebench_shm->filesetentry[i], 0,
469*5184Sek110237 		    sizeof (filesetentry_t));
470*5184Sek110237 		(void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
471*5184Sek110237 		return ((char *)&filebench_shm->filesetentry[i]);
472*5184Sek110237 
473*5184Sek110237 	case FILEBENCH_PROCFLOW:
474*5184Sek110237 		(void) memset((char *)&filebench_shm->procflow[i], 0,
475*5184Sek110237 		    sizeof (procflow_t));
476*5184Sek110237 		(void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
477*5184Sek110237 		return ((char *)&filebench_shm->procflow[i]);
478*5184Sek110237 
479*5184Sek110237 	case FILEBENCH_THREADFLOW:
480*5184Sek110237 		(void) memset((char *)&filebench_shm->threadflow[i], 0,
481*5184Sek110237 		    sizeof (threadflow_t));
482*5184Sek110237 		(void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
483*5184Sek110237 		return ((char *)&filebench_shm->threadflow[i]);
484*5184Sek110237 
485*5184Sek110237 	case FILEBENCH_FLOWOP:
486*5184Sek110237 		(void) memset((char *)&filebench_shm->flowop[i], 0,
487*5184Sek110237 		    sizeof (flowop_t));
488*5184Sek110237 		(void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
489*5184Sek110237 		return ((char *)&filebench_shm->flowop[i]);
490*5184Sek110237 
491*5184Sek110237 	case FILEBENCH_INTEGER:
492*5184Sek110237 		filebench_shm->integer_ptrs[i] = NULL;
493*5184Sek110237 		(void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
494*5184Sek110237 		return ((char *)&filebench_shm->integer_ptrs[i]);
495*5184Sek110237 
496*5184Sek110237 	case FILEBENCH_STRING:
497*5184Sek110237 		filebench_shm->string_ptrs[i] = NULL;
498*5184Sek110237 		(void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
499*5184Sek110237 		return ((char *)&filebench_shm->string_ptrs[i]);
500*5184Sek110237 
501*5184Sek110237 	case FILEBENCH_VARIABLE:
502*5184Sek110237 		(void) memset((char *)&filebench_shm->var[i], 0,
503*5184Sek110237 		    sizeof (var_t));
504*5184Sek110237 		(void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
505*5184Sek110237 		return ((char *)&filebench_shm->var[i]);
506*5184Sek110237 	}
507*5184Sek110237 
508*5184Sek110237 	filebench_log(LOG_ERROR, "Attempt to ipc_malloc unknown type (%d)!",
509*5184Sek110237 	    type);
510*5184Sek110237 	return (NULL);
511*5184Sek110237 }
512*5184Sek110237 
513*5184Sek110237 /*
514*5184Sek110237  * Frees a filebench object of type "type" at the location
515*5184Sek110237  * pointed to by "addr". It uses the type and address to
516*5184Sek110237  * calculate which object is being freed, and clears its
517*5184Sek110237  * allocation map entry.
518*5184Sek110237  */
519*5184Sek110237 void
520*5184Sek110237 ipc_free(int type, char *addr)
521*5184Sek110237 {
522*5184Sek110237 	int item;
523*5184Sek110237 	caddr_t base;
524*5184Sek110237 	size_t offset;
525*5184Sek110237 	size_t size;
526*5184Sek110237 
527*5184Sek110237 	if (addr == NULL) {
528*5184Sek110237 		filebench_log(LOG_ERROR, "Freeing type %d %zx", type, addr);
529*5184Sek110237 		return;
530*5184Sek110237 	}
531*5184Sek110237 
532*5184Sek110237 	switch (type) {
533*5184Sek110237 	case FILEBENCH_FILEOBJ:
534*5184Sek110237 		base = (caddr_t)&filebench_shm->fileobj[0];
535*5184Sek110237 		size = sizeof (fileobj_t);
536*5184Sek110237 		break;
537*5184Sek110237 
538*5184Sek110237 	case FILEBENCH_FILESET:
539*5184Sek110237 		base = (caddr_t)&filebench_shm->fileset[0];
540*5184Sek110237 		size = sizeof (fileset_t);
541*5184Sek110237 		break;
542*5184Sek110237 
543*5184Sek110237 	case FILEBENCH_FILESETENTRY:
544*5184Sek110237 		base = (caddr_t)&filebench_shm->filesetentry[0];
545*5184Sek110237 		size = sizeof (filesetentry_t);
546*5184Sek110237 		break;
547*5184Sek110237 
548*5184Sek110237 	case FILEBENCH_PROCFLOW:
549*5184Sek110237 		base = (caddr_t)&filebench_shm->procflow[0];
550*5184Sek110237 		size = sizeof (procflow_t);
551*5184Sek110237 		break;
552*5184Sek110237 
553*5184Sek110237 	case FILEBENCH_THREADFLOW:
554*5184Sek110237 		base = (caddr_t)&filebench_shm->threadflow[0];
555*5184Sek110237 		size = sizeof (threadflow_t);
556*5184Sek110237 		break;
557*5184Sek110237 
558*5184Sek110237 	case FILEBENCH_FLOWOP:
559*5184Sek110237 		base = (caddr_t)&filebench_shm->flowop[0];
560*5184Sek110237 		size = sizeof (flowop_t);
561*5184Sek110237 		break;
562*5184Sek110237 
563*5184Sek110237 	case FILEBENCH_INTEGER:
564*5184Sek110237 		base = (caddr_t)&filebench_shm->integer_ptrs[0];
565*5184Sek110237 		size = sizeof (caddr_t);
566*5184Sek110237 		break;
567*5184Sek110237 
568*5184Sek110237 	case FILEBENCH_STRING:
569*5184Sek110237 		base = (caddr_t)&filebench_shm->string_ptrs[0];
570*5184Sek110237 		size = sizeof (caddr_t);
571*5184Sek110237 		break;
572*5184Sek110237 
573*5184Sek110237 	case FILEBENCH_VARIABLE:
574*5184Sek110237 		base = (caddr_t)&filebench_shm->var[0];
575*5184Sek110237 		size = sizeof (var_t);
576*5184Sek110237 		break;
577*5184Sek110237 	}
578*5184Sek110237 
579*5184Sek110237 	offset = ((size_t)addr - (size_t)base);
580*5184Sek110237 	item = offset / size;
581*5184Sek110237 
582*5184Sek110237 	(void) ipc_mutex_lock(&filebench_shm->malloc_lock);
583*5184Sek110237 	filebench_shm->bitmap[type][item] = 0;
584*5184Sek110237 	(void) ipc_mutex_unlock(&filebench_shm->malloc_lock);
585*5184Sek110237 }
586*5184Sek110237 
587*5184Sek110237 /*
588*5184Sek110237  * Allocate a string from filebench string memory. The length
589*5184Sek110237  * of the allocated string is the same as the length of the
590*5184Sek110237  * supplied string "string", and the contents of string are
591*5184Sek110237  * copied to the newly allocated string.
592*5184Sek110237  */
593*5184Sek110237 char *
594*5184Sek110237 ipc_stralloc(char *string)
595*5184Sek110237 {
596*5184Sek110237 	char *allocstr = filebench_shm->string_ptr;
597*5184Sek110237 
598*5184Sek110237 	filebench_shm->string_ptr += strlen(string) + 1;
599*5184Sek110237 
600*5184Sek110237 	if ((filebench_shm->string_ptr - &filebench_shm->strings[0]) >
601*5184Sek110237 	    FILEBENCH_STRINGMEMORY) {
602*5184Sek110237 		filebench_log(LOG_ERROR, "Out of ipc string memory");
603*5184Sek110237 		return (NULL);
604*5184Sek110237 	}
605*5184Sek110237 
606*5184Sek110237 	(void) strncpy(allocstr, string, strlen(string));
607*5184Sek110237 
608*5184Sek110237 	return (allocstr);
609*5184Sek110237 }
610*5184Sek110237 
611*5184Sek110237 /*
612*5184Sek110237  * Allocate a path string from filebench path string memory.
613*5184Sek110237  * Specifically used for allocating fileset paths. The length
614*5184Sek110237  * of the allocated path string is the same as the length of
615*5184Sek110237  * the supplied path string "path", and the contents of path
616*5184Sek110237  * are copied to the newly allocated path string. Checks for
617*5184Sek110237  * out-of-path-string-memory condition and returns NULL if so.
618*5184Sek110237  * Otherwise it returns a pointer to the newly allocated path
619*5184Sek110237  * string.
620*5184Sek110237  */
621*5184Sek110237 char *
622*5184Sek110237 ipc_pathalloc(char *path)
623*5184Sek110237 {
624*5184Sek110237 	char *allocpath = filebench_shm->path_ptr;
625*5184Sek110237 
626*5184Sek110237 	filebench_shm->path_ptr += strlen(path) + 1;
627*5184Sek110237 
628*5184Sek110237 	if ((filebench_shm->path_ptr - &filebench_shm->filesetpaths[0]) >
629*5184Sek110237 	    FILEBENCH_FILESETPATHMEMORY) {
630*5184Sek110237 		filebench_log(LOG_ERROR, "Out of fileset path memory");
631*5184Sek110237 		return (NULL);
632*5184Sek110237 	}
633*5184Sek110237 
634*5184Sek110237 	(void) strncpy(allocpath, path, strlen(path));
635*5184Sek110237 
636*5184Sek110237 	return (allocpath);
637*5184Sek110237 }
638*5184Sek110237 
639*5184Sek110237 /*
640*5184Sek110237  * This is a limited functionality deallocator for path
641*5184Sek110237  * strings - it can only free all path strings at once,
642*5184Sek110237  * in order to avoid fragmentation.
643*5184Sek110237  */
644*5184Sek110237 void
645*5184Sek110237 ipc_freepaths(void)
646*5184Sek110237 {
647*5184Sek110237 	filebench_shm->path_ptr = &filebench_shm->filesetpaths[0];
648*5184Sek110237 }
649*5184Sek110237 
650*5184Sek110237 /*
651*5184Sek110237  * Allocates a semid from the table of semids for pre intialized
652*5184Sek110237  * semaphores. Searches for the first available semaphore, and
653*5184Sek110237  * sets the entry in the table to "1" to indicate allocation.
654*5184Sek110237  * Returns the allocated semid. Stops the run if all semaphores
655*5184Sek110237  * are already in use.
656*5184Sek110237  */
657*5184Sek110237 int
658*5184Sek110237 ipc_semidalloc(void)
659*5184Sek110237 {
660*5184Sek110237 	int semid;
661*5184Sek110237 
662*5184Sek110237 	for (semid = 0; filebench_shm->semids[semid] == 1; semid++)
663*5184Sek110237 		;
664*5184Sek110237 	if (semid == FILEBENCH_NSEMS) {
665*5184Sek110237 		filebench_log(LOG_ERROR,
666*5184Sek110237 		    "Out of semaphores, increase system tunable limit");
667*5184Sek110237 		filebench_shutdown(1);
668*5184Sek110237 	}
669*5184Sek110237 	filebench_shm->semids[semid] = 1;
670*5184Sek110237 	return (semid);
671*5184Sek110237 }
672*5184Sek110237 
673*5184Sek110237 /*
674*5184Sek110237  * Frees up the supplied semid by seting its position in the
675*5184Sek110237  * allocation table to "0".
676*5184Sek110237  */
677*5184Sek110237 void
678*5184Sek110237 ipc_semidfree(int semid)
679*5184Sek110237 {
680*5184Sek110237 	filebench_shm->semids[semid] = 0;
681*5184Sek110237 }
682*5184Sek110237 
683*5184Sek110237 /*
684*5184Sek110237  * Create a pool of shared memory to fit the per-thread
685*5184Sek110237  * allocations. Uses shmget() to create a shared memory region
686*5184Sek110237  * of size "size", attaches to it using shmat(), and stores
687*5184Sek110237  * the returned address of the region in filebench_shm->shm_addr.
688*5184Sek110237  * The pool is only created on the first call. The routine
689*5184Sek110237  * returns 0 if successful or the pool already exists,
690*5184Sek110237  * -1 otherwise.
691*5184Sek110237  */
692*5184Sek110237 int
693*5184Sek110237 ipc_ismcreate(size_t size)
694*5184Sek110237 {
695*5184Sek110237 #ifdef HAVE_SHM_SHARE_MMU
696*5184Sek110237 	int flag = SHM_SHARE_MMU;
697*5184Sek110237 #else
698*5184Sek110237 	int flag = 0;
699*5184Sek110237 #endif /* HAVE_SHM_SHARE_MMU */
700*5184Sek110237 
701*5184Sek110237 	/* Already done? */
702*5184Sek110237 	if (filebench_shm->shm_id != -1)
703*5184Sek110237 		return (0);
704*5184Sek110237 
705*5184Sek110237 	filebench_log(LOG_VERBOSE,
706*5184Sek110237 	    "Creating %zd bytes of ISM Shared Memory...", size);
707*5184Sek110237 
708*5184Sek110237 	if ((filebench_shm->shm_id =
709*5184Sek110237 	    shmget(0, size, IPC_CREAT | 0666)) == -1) {
710*5184Sek110237 		filebench_log(LOG_ERROR,
711*5184Sek110237 		    "Failed to create %zd bytes of ISM shared memory", size);
712*5184Sek110237 		return (-1);
713*5184Sek110237 	}
714*5184Sek110237 
715*5184Sek110237 	if ((filebench_shm->shm_addr = (caddr_t)shmat(filebench_shm->shm_id,
716*5184Sek110237 	    0, flag)) == (void *)-1) {
717*5184Sek110237 		filebench_log(LOG_ERROR,
718*5184Sek110237 		    "Failed to attach %zd bytes of created ISM shared memory",
719*5184Sek110237 		    size);
720*5184Sek110237 		return (-1);
721*5184Sek110237 	}
722*5184Sek110237 
723*5184Sek110237 	filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr;
724*5184Sek110237 
725*5184Sek110237 	filebench_log(LOG_VERBOSE,
726*5184Sek110237 	    "Allocated %zd bytes of ISM Shared Memory... at %zx",
727*5184Sek110237 	    size, filebench_shm->shm_addr);
728*5184Sek110237 
729*5184Sek110237 	/* Locked until allocated to block allocs */
730*5184Sek110237 	(void) ipc_mutex_unlock(&filebench_shm->ism_lock);
731*5184Sek110237 
732*5184Sek110237 	return (0);
733*5184Sek110237 }
734*5184Sek110237 
735*5184Sek110237 /* Per addr space ism */
736*5184Sek110237 static int ism_attached = 0;
737*5184Sek110237 
738*5184Sek110237 /*
739*5184Sek110237  * Attach to interprocess shared memory. If already attached
740*5184Sek110237  * just return, otherwise use shmat() to attached to the region
741*5184Sek110237  * with ID of filebench_shm->shm_id. Returns -1 if shmat()
742*5184Sek110237  * fails, otherwise 0.
743*5184Sek110237  */
744*5184Sek110237 static int
745*5184Sek110237 ipc_ismattach(void)
746*5184Sek110237 {
747*5184Sek110237 #ifdef HAVE_SHM_SHARE_MMU
748*5184Sek110237 	int flag = SHM_SHARE_MMU;
749*5184Sek110237 #else
750*5184Sek110237 	int flag = 0;
751*5184Sek110237 #endif /* HAVE_SHM_SHARE_MMU */
752*5184Sek110237 
753*5184Sek110237 
754*5184Sek110237 	if (ism_attached)
755*5184Sek110237 		return (0);
756*5184Sek110237 
757*5184Sek110237 	/* Does it exist? */
758*5184Sek110237 	if (filebench_shm->shm_id == 999)
759*5184Sek110237 		return (0);
760*5184Sek110237 
761*5184Sek110237 	if (shmat(filebench_shm->shm_id, filebench_shm->shm_addr,
762*5184Sek110237 	    flag) == NULL)
763*5184Sek110237 		return (-1);
764*5184Sek110237 
765*5184Sek110237 	ism_attached = 1;
766*5184Sek110237 
767*5184Sek110237 	return (0);
768*5184Sek110237 }
769*5184Sek110237 
770*5184Sek110237 /*
771*5184Sek110237  * Allocate from interprocess shared memory. Attaches to ism
772*5184Sek110237  * if necessary, then allocates "size" bytes, updates allocation
773*5184Sek110237  * information and returns a pointer to the allocated memory.
774*5184Sek110237  */
775*5184Sek110237 /*
776*5184Sek110237  * XXX No check is made for out-of-memory condition
777*5184Sek110237  */
778*5184Sek110237 char *
779*5184Sek110237 ipc_ismmalloc(size_t size)
780*5184Sek110237 {
781*5184Sek110237 	char *allocstr;
782*5184Sek110237 
783*5184Sek110237 	(void) ipc_mutex_lock(&filebench_shm->ism_lock);
784*5184Sek110237 
785*5184Sek110237 	/* Map in shared memory */
786*5184Sek110237 	(void) ipc_ismattach();
787*5184Sek110237 
788*5184Sek110237 	allocstr = filebench_shm->shm_ptr;
789*5184Sek110237 
790*5184Sek110237 	filebench_shm->shm_ptr += size;
791*5184Sek110237 	filebench_shm->shm_allocated += size;
792*5184Sek110237 
793*5184Sek110237 	(void) ipc_mutex_unlock(&filebench_shm->ism_lock);
794*5184Sek110237 
795*5184Sek110237 	return (allocstr);
796*5184Sek110237 }
797*5184Sek110237 
798*5184Sek110237 /*
799*5184Sek110237  * Deletes shared memory region and resets shared memory region
800*5184Sek110237  * information in filebench_shm.
801*5184Sek110237  */
802*5184Sek110237 void
803*5184Sek110237 ipc_ismdelete(void)
804*5184Sek110237 {
805*5184Sek110237 	if (filebench_shm->shm_id == -1)
806*5184Sek110237 		return;
807*5184Sek110237 
808*5184Sek110237 	filebench_log(LOG_VERBOSE, "Deleting ISM...");
809*5184Sek110237 
810*5184Sek110237 	(void) ipc_mutex_lock(&filebench_shm->ism_lock);
811*5184Sek110237 #ifdef HAVE_SEM_RMID
812*5184Sek110237 	(void) shmctl(filebench_shm->shm_id, IPC_RMID, 0);
813*5184Sek110237 #endif
814*5184Sek110237 	filebench_shm->shm_ptr = (char *)filebench_shm->shm_addr;
815*5184Sek110237 	filebench_shm->shm_id = -1;
816*5184Sek110237 	filebench_shm->shm_allocated = 0;
817*5184Sek110237 	(void) ipc_mutex_unlock(&filebench_shm->ism_lock);
818*5184Sek110237 }
819