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 #include <pthread.h>
305184Sek110237 #ifdef HAVE_LWPS
315184Sek110237 #include <sys/lwp.h>
325184Sek110237 #endif
335184Sek110237 #include <signal.h>
345184Sek110237 #include "threadflow.h"
355184Sek110237 #include "filebench.h"
365184Sek110237 #include "flowop.h"
375184Sek110237 #include "ipc.h"
385184Sek110237 
395184Sek110237 static threadflow_t *threadflow_define_common(procflow_t *procflow,
405184Sek110237     char *name, threadflow_t *inherit, int instance);
415184Sek110237 
425184Sek110237 /*
435184Sek110237  * Threadflows are filebench entities which manage operating system
445184Sek110237  * threads. Each worker threadflow spawns a separate filebench thread,
455184Sek110237  * with attributes inherited from a FLOW_MASTER threadflow created during
465184Sek110237  * f model language parsing. This section contains routines to define,
475184Sek110237  * create, control, and delete threadflows.
485184Sek110237  *
495184Sek110237  * Each thread defined in the f model creates a FLOW_MASTER
505184Sek110237  * threadflow which encapsulates the defined attributes and flowops of
515184Sek110237  * the f language thread, including the number of instances to create.
525184Sek110237  * At runtime, a worker threadflow instance with an associated filebench
535184Sek110237  * thread is created, which runs until told to quit or is specifically
545184Sek110237  * deleted.
555184Sek110237  */
565184Sek110237 
575184Sek110237 
585184Sek110237 /*
595184Sek110237  * Prints information about threadflow syntax.
605184Sek110237  */
615184Sek110237 void
625184Sek110237 threadflow_usage(void)
635184Sek110237 {
645184Sek110237 	(void) fprintf(stderr, "  thread  name=<name>[,instances=<count>]\n");
655184Sek110237 	(void) fprintf(stderr, "\n");
665184Sek110237 	(void) fprintf(stderr, "  {\n");
675184Sek110237 	(void) fprintf(stderr, "    flowop ...\n");
685184Sek110237 	(void) fprintf(stderr, "    flowop ...\n");
695184Sek110237 	(void) fprintf(stderr, "    flowop ...\n");
705184Sek110237 	(void) fprintf(stderr, "  }\n");
715184Sek110237 	(void) fprintf(stderr, "\n");
725184Sek110237 }
735184Sek110237 
745184Sek110237 /*
755184Sek110237  * Creates a thread for the supplied threadflow. If interprocess
765184Sek110237  * shared memory is desired, then increments the amount of shared
775184Sek110237  * memory needed by the amount specified in the threadflow's
785184Sek110237  * tf_memsize parameter. The thread starts in routine
795184Sek110237  * flowop_start() with a poineter to the threadflow supplied
805184Sek110237  * as the argument.
815184Sek110237  */
825184Sek110237 static int
835184Sek110237 threadflow_createthread(threadflow_t *threadflow)
845184Sek110237 {
85*6212Saw148015 	fbint_t memsize;
86*6212Saw148015 	memsize = avd_get_int(threadflow->tf_memsize);
87*6212Saw148015 	threadflow->tf_constmemsize = memsize;
88*6212Saw148015 
895184Sek110237 	filebench_log(LOG_DEBUG_SCRIPT, "Creating thread %s, memory = %ld",
90*6212Saw148015 	    threadflow->tf_name, memsize);
915184Sek110237 
925184Sek110237 	if (threadflow->tf_attrs & THREADFLOW_USEISM)
93*6212Saw148015 		filebench_shm->shm_required += memsize;
945184Sek110237 
955184Sek110237 	if (pthread_create(&threadflow->tf_tid, NULL,
965184Sek110237 	    (void *(*)(void*))flowop_start, threadflow) != 0) {
975184Sek110237 		filebench_log(LOG_ERROR, "thread create failed");
985184Sek110237 		filebench_shutdown(1);
996084Saw148015 		return (FILEBENCH_ERROR);
1005184Sek110237 	}
1015184Sek110237 
1026084Saw148015 	return (FILEBENCH_OK);
1035184Sek110237 }
1045184Sek110237 
1055184Sek110237 /*
1065184Sek110237  * Terminates (exits) all the threads of the procflow (process).
1075184Sek110237  * The procflow is determined from a process private pointer
1085184Sek110237  * initialized by threadflow_init().
1095184Sek110237  */
1105184Sek110237 /* ARGSUSED */
1115184Sek110237 static void
1125184Sek110237 threadflow_cancel(int arg1)
1135184Sek110237 {
1146084Saw148015 	threadflow_t *threadflow;
1155184Sek110237 
1165184Sek110237 #ifdef HAVE_LWPS
1175184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "Thread signal handler on tid %d",
1185184Sek110237 	    _lwp_self());
1195184Sek110237 #endif
1205184Sek110237 
1216084Saw148015 	threadflow = my_procflow->pf_threads;
1225184Sek110237 	my_procflow->pf_running = 0;
1235184Sek110237 
1245184Sek110237 	while (threadflow) {
1255184Sek110237 		if (threadflow->tf_tid) {
1266084Saw148015 			/* make sure thread has been cleaned up */
1276084Saw148015 			flowop_destruct_all_flows(threadflow);
1286084Saw148015 
1295184Sek110237 			(void) pthread_cancel(threadflow->tf_tid);
1305184Sek110237 			filebench_log(LOG_DEBUG_IMPL, "Thread %d cancelled...",
1315184Sek110237 			    threadflow->tf_tid);
1325184Sek110237 		}
1335184Sek110237 		threadflow = threadflow->tf_next;
1345184Sek110237 	}
1356084Saw148015 
1366084Saw148015 	exit(0);
1375184Sek110237 }
1385184Sek110237 
1395184Sek110237 /*
1405184Sek110237  * Creates threads for the threadflows associated with a procflow.
1415184Sek110237  * The routine iterates through the list of threadflows in the
1425184Sek110237  * supplied procflow's pf_threads list. For each threadflow on
1435184Sek110237  * the list, it defines tf_instances number of cloned
1445184Sek110237  * threadflows, and then calls threadflow_createthread() for
1455184Sek110237  * each to create and start the actual operating system thread.
1465184Sek110237  * Note that each of the newly defined threadflows will be linked
1475184Sek110237  * into the procflows threadflow list, but at the head of the
1485184Sek110237  * list, so they will not become part of the supplied set. After
1495184Sek110237  * all the threads have been created, threadflow_init enters
1505184Sek110237  * a join loop for all the threads in the newly defined
1515184Sek110237  * threadflows. Once all the created threads have exited,
1525184Sek110237  * threadflow_init will return 0. If errors are encountered, it
1535184Sek110237  * will return a non zero value.
1545184Sek110237  */
1555184Sek110237 int
1565184Sek110237 threadflow_init(procflow_t *procflow)
1575184Sek110237 {
1585184Sek110237 	threadflow_t *threadflow = procflow->pf_threads;
1595184Sek110237 	int ret = 0;
1605184Sek110237 
1615184Sek110237 	(void) ipc_mutex_lock(&filebench_shm->threadflow_lock);
1625184Sek110237 
1635184Sek110237 	(void) signal(SIGUSR1, threadflow_cancel);
1646084Saw148015 
1655184Sek110237 	while (threadflow) {
1665184Sek110237 		threadflow_t *newthread;
167*6212Saw148015 		int instances;
1685184Sek110237 		int i;
1695184Sek110237 
170*6212Saw148015 		instances = avd_get_int(threadflow->tf_instances);
1715184Sek110237 		filebench_log(LOG_VERBOSE,
1725184Sek110237 		    "Starting %lld %s threads",
173*6212Saw148015 		    instances, threadflow->tf_name);
1745184Sek110237 
175*6212Saw148015 		for (i = 1; i < instances; i++) {
1765184Sek110237 			/* Create threads */
1775184Sek110237 			newthread =
1785184Sek110237 			    threadflow_define_common(procflow,
1795184Sek110237 			    threadflow->tf_name, threadflow, i + 1);
1805184Sek110237 			if (newthread == NULL)
1815184Sek110237 				return (-1);
1826084Saw148015 			ret |= threadflow_createthread(newthread);
1835184Sek110237 		}
1845184Sek110237 
1855184Sek110237 		newthread = threadflow_define_common(procflow,
1865184Sek110237 		    threadflow->tf_name,
1875184Sek110237 		    threadflow, 1);
1885184Sek110237 
1895184Sek110237 		if (newthread == NULL)
1905184Sek110237 			return (-1);
1915184Sek110237 
1926084Saw148015 		/* Create each thread */
1936084Saw148015 		ret |= threadflow_createthread(newthread);
1945184Sek110237 
1955184Sek110237 		threadflow = threadflow->tf_next;
1965184Sek110237 	}
1975184Sek110237 
1985184Sek110237 	threadflow = procflow->pf_threads;
1995184Sek110237 
2005184Sek110237 	(void) ipc_mutex_unlock(&filebench_shm->threadflow_lock);
2015184Sek110237 
2025184Sek110237 	while (threadflow) {
2035184Sek110237 		void *status;
2045184Sek110237 
2056084Saw148015 		/* wait for all threads to finish */
2065184Sek110237 		if (threadflow->tf_tid)
2075184Sek110237 			(void) pthread_join(threadflow->tf_tid, &status);
2085184Sek110237 
2096084Saw148015 		ret |= *(int *)status;
2105184Sek110237 		threadflow = threadflow->tf_next;
2115184Sek110237 	}
2125184Sek110237 
2135184Sek110237 	procflow->pf_running = 0;
2145184Sek110237 
2155184Sek110237 	return (ret);
2165184Sek110237 }
2175184Sek110237 
2185184Sek110237 /*
2195184Sek110237  * Tells the threadflow's thread to stop and optionally signals
2205184Sek110237  * its associated process to end the thread.
2215184Sek110237  */
2225184Sek110237 static void
2236084Saw148015 threadflow_kill(threadflow_t *threadflow, int wait_cnt)
2245184Sek110237 {
2255184Sek110237 	/* Tell thread to finish */
2265184Sek110237 	threadflow->tf_abort = 1;
2275184Sek110237 
2286084Saw148015 	/* wait a bit for threadflow to stop */
2296084Saw148015 	while (wait_cnt && threadflow->tf_running) {
2306084Saw148015 		(void) sleep(1);
2316084Saw148015 		wait_cnt--;
2326084Saw148015 	}
2336084Saw148015 
2345184Sek110237 #ifdef USE_PROCESS_MODEL
2355184Sek110237 #ifdef HAVE_SIGSEND
2365184Sek110237 	(void) sigsend(P_PID, threadflow->tf_process->pf_pid, SIGUSR1);
2375184Sek110237 #else
2385184Sek110237 	(void) kill(threadflow->tf_process->pf_pid, SIGUSR1);
2395184Sek110237 #endif
2405184Sek110237 #else /* USE_PROCESS_MODEL */
2415184Sek110237 	threadflow->tf_process->pf_running = 0;
2425184Sek110237 #endif /* USE_PROCESS_MODEL */
2435184Sek110237 }
2445184Sek110237 
2455184Sek110237 /*
2465184Sek110237  * Deletes the specified threadflow from the specified threadflow
2475184Sek110237  * list after first terminating the threadflow's thread, deleting
2485184Sek110237  * the threadflow's flowops, and finally freeing the threadflow
2495184Sek110237  * entity. It also subtracts the threadflow's shared memory
2505184Sek110237  * requirements from the total amount required, shm_required. If
2515184Sek110237  * the specified threadflow is found, returns 0, otherwise
2525184Sek110237  * returns -1.
2535184Sek110237  */
2545184Sek110237 static int
2556084Saw148015 threadflow_delete(threadflow_t **threadlist, threadflow_t *threadflow,
2566084Saw148015     int wait_cnt)
2575184Sek110237 {
2585184Sek110237 	threadflow_t *entry = *threadlist;
2595184Sek110237 
2605184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "Deleting thread: (%s-%d)",
2615184Sek110237 	    threadflow->tf_name,
2625184Sek110237 	    threadflow->tf_instance);
2635184Sek110237 
264*6212Saw148015 	if (threadflow->tf_attrs & THREADFLOW_USEISM)
265*6212Saw148015 		filebench_shm->shm_required -= threadflow->tf_constmemsize;
2665184Sek110237 
2675184Sek110237 	if (threadflow == *threadlist) {
2685184Sek110237 		/* First on list */
2695184Sek110237 		filebench_log(LOG_DEBUG_IMPL, "Deleted thread: (%s-%d)",
2705184Sek110237 		    threadflow->tf_name,
2715184Sek110237 		    threadflow->tf_instance);
2725184Sek110237 
2736084Saw148015 		threadflow_kill(threadflow, wait_cnt);
2745184Sek110237 		flowop_delete_all(&threadflow->tf_ops);
2755184Sek110237 		*threadlist = threadflow->tf_next;
2765184Sek110237 		ipc_free(FILEBENCH_THREADFLOW, (char *)threadflow);
2775184Sek110237 		return (0);
2785184Sek110237 	}
2795184Sek110237 
2805184Sek110237 	while (entry->tf_next) {
2815184Sek110237 		filebench_log(LOG_DEBUG_IMPL,
2825184Sek110237 		    "Delete thread: (%s-%d) == (%s-%d)",
2835184Sek110237 		    entry->tf_next->tf_name,
2845184Sek110237 		    entry->tf_next->tf_instance,
2855184Sek110237 		    threadflow->tf_name,
2865184Sek110237 		    threadflow->tf_instance);
2875184Sek110237 
2885184Sek110237 		if (threadflow == entry->tf_next) {
2895184Sek110237 			/* Delete */
2905184Sek110237 			filebench_log(LOG_DEBUG_IMPL,
2915184Sek110237 			    "Deleted thread: (%s-%d)",
2925184Sek110237 			    entry->tf_next->tf_name,
2935184Sek110237 			    entry->tf_next->tf_instance);
2946084Saw148015 			threadflow_kill(entry->tf_next, wait_cnt);
2955184Sek110237 			flowop_delete_all(&entry->tf_next->tf_ops);
2965184Sek110237 			ipc_free(FILEBENCH_THREADFLOW, (char *)threadflow);
2975184Sek110237 			entry->tf_next = entry->tf_next->tf_next;
2985184Sek110237 			return (0);
2995184Sek110237 		}
3005184Sek110237 		entry = entry->tf_next;
3015184Sek110237 	}
3025184Sek110237 
3035184Sek110237 	return (-1);
3045184Sek110237 }
3055184Sek110237 
3065184Sek110237 /*
3075184Sek110237  * Given a pointer to the thread list of a procflow, cycles
3085184Sek110237  * through all the threadflows on the list, deleting each one
3095184Sek110237  * except the FLOW_MASTER.
3105184Sek110237  */
3115184Sek110237 void
3126084Saw148015 threadflow_delete_all(threadflow_t **threadlist, int wait_cnt)
3135184Sek110237 {
3145184Sek110237 	threadflow_t *threadflow = *threadlist;
3155184Sek110237 
3165184Sek110237 	(void) ipc_mutex_lock(&filebench_shm->threadflow_lock);
3175184Sek110237 
3185184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "Deleting all threads");
3195184Sek110237 
3205184Sek110237 	while (threadflow) {
3215184Sek110237 		if (threadflow->tf_instance &&
3225184Sek110237 		    (threadflow->tf_instance == FLOW_MASTER)) {
3235184Sek110237 			threadflow = threadflow->tf_next;
3245184Sek110237 			continue;
3255184Sek110237 		}
3266084Saw148015 		(void) threadflow_delete(threadlist, threadflow, wait_cnt);
3275184Sek110237 		threadflow = threadflow->tf_next;
3286084Saw148015 		/* grow more impatient */
3296084Saw148015 		if (wait_cnt > 0)
3306084Saw148015 			wait_cnt--;
3315184Sek110237 	}
3325184Sek110237 
3335184Sek110237 	(void) ipc_mutex_unlock(&filebench_shm->threadflow_lock);
3345184Sek110237 }
3355184Sek110237 
3365184Sek110237 /*
3375184Sek110237  * Waits till all threadflows are started, or a timeout occurs.
3385184Sek110237  * Checks through the list of threadflows, waiting up to 10
3395184Sek110237  * seconds for each one to set its tf_running flag to 1. If not
3405184Sek110237  * set after 10 seconds, continues on to the next threadflow
3415184Sek110237  * anyway.
3425184Sek110237  */
3435184Sek110237 void
3445184Sek110237 threadflow_allstarted(pid_t pid, threadflow_t *threadflow)
3455184Sek110237 {
3465184Sek110237 	(void) ipc_mutex_lock(&filebench_shm->threadflow_lock);
3475184Sek110237 
3485184Sek110237 	while (threadflow) {
3495184Sek110237 		int waits;
3505184Sek110237 
3515184Sek110237 		if ((threadflow->tf_instance == 0) ||
3525184Sek110237 		    (threadflow->tf_instance == FLOW_MASTER)) {
3535184Sek110237 			threadflow = threadflow->tf_next;
3545184Sek110237 			continue;
3555184Sek110237 		}
3565184Sek110237 
3575184Sek110237 		filebench_log(LOG_DEBUG_IMPL, "Checking pid %d thread %s-%d",
3585184Sek110237 		    pid,
3595184Sek110237 		    threadflow->tf_name,
3605184Sek110237 		    threadflow->tf_instance);
3615184Sek110237 
3625184Sek110237 		waits = 10;
3635184Sek110237 		while (waits && threadflow->tf_running == 0) {
3645184Sek110237 			(void) ipc_mutex_unlock(
3655184Sek110237 			    &filebench_shm->threadflow_lock);
3665184Sek110237 			if (waits < 3)
3675184Sek110237 				filebench_log(LOG_INFO,
3685184Sek110237 				    "Waiting for pid %d thread %s-%d",
3695184Sek110237 				    pid,
3705184Sek110237 				    threadflow->tf_name,
3715184Sek110237 				    threadflow->tf_instance);
3725184Sek110237 
3735184Sek110237 			(void) sleep(1);
3745184Sek110237 			(void) ipc_mutex_lock(&filebench_shm->threadflow_lock);
3755184Sek110237 			waits--;
3765184Sek110237 		}
3775184Sek110237 
3785184Sek110237 		threadflow = threadflow->tf_next;
3795184Sek110237 	}
3805184Sek110237 
3815184Sek110237 	(void) ipc_mutex_unlock(&filebench_shm->threadflow_lock);
3825184Sek110237 }
3835184Sek110237 
3845184Sek110237 /*
3855184Sek110237  * Create an in-memory thread object linked to a parent procflow.
3865184Sek110237  * A threadflow entity is allocated from shared memory and
3875184Sek110237  * initialized from the "inherit" threadflow if supplied,
3885184Sek110237  * otherwise to zeros. The threadflow is assigned a unique
3895184Sek110237  * thread id, the supplied instance number, the supplied name
3905184Sek110237  * and added to the procflow's pf_thread list. If no name is
3915184Sek110237  * supplied or the threadflow can't be allocated, NULL is
3925184Sek110237  * returned Otherwise a pointer to the newly allocated threadflow
3935184Sek110237  * is returned.
3945184Sek110237  *
3955184Sek110237  * The filebench_shm->threadflow_lock must be held by the caller.
3965184Sek110237  */
3975184Sek110237 static threadflow_t *
3985184Sek110237 threadflow_define_common(procflow_t *procflow, char *name,
3995184Sek110237     threadflow_t *inherit, int instance)
4005184Sek110237 {
4015184Sek110237 	threadflow_t *threadflow;
4025184Sek110237 	threadflow_t **threadlistp = &procflow->pf_threads;
4035184Sek110237 
4045184Sek110237 	if (name == NULL)
4055184Sek110237 		return (NULL);
4065184Sek110237 
4075184Sek110237 	threadflow = (threadflow_t *)ipc_malloc(FILEBENCH_THREADFLOW);
4085184Sek110237 
4095184Sek110237 	if (threadflow == NULL)
4105184Sek110237 		return (NULL);
4115184Sek110237 
4125184Sek110237 	if (inherit)
4135184Sek110237 		(void) memcpy(threadflow, inherit, sizeof (threadflow_t));
4145184Sek110237 	else
4155184Sek110237 		(void) memset(threadflow, 0, sizeof (threadflow_t));
4165184Sek110237 
4175184Sek110237 	threadflow->tf_utid = ++filebench_shm->utid;
4185184Sek110237 
4195184Sek110237 	threadflow->tf_instance = instance;
4205184Sek110237 	(void) strcpy(threadflow->tf_name, name);
4215184Sek110237 	threadflow->tf_process = procflow;
4225184Sek110237 
4235184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "Defining thread %s-%d",
4245184Sek110237 	    name, instance);
4255184Sek110237 
4265184Sek110237 	/* Add threadflow to list */
4275184Sek110237 	if (*threadlistp == NULL) {
4285184Sek110237 		*threadlistp = threadflow;
4295184Sek110237 		threadflow->tf_next = NULL;
4305184Sek110237 	} else {
4315184Sek110237 		threadflow->tf_next = *threadlistp;
4325184Sek110237 		*threadlistp = threadflow;
4335184Sek110237 	}
4345184Sek110237 
4355184Sek110237 	return (threadflow);
4365184Sek110237 }
4375184Sek110237 
4385184Sek110237 /*
4395184Sek110237  * Create an in memory FLOW_MASTER thread object as described
4405184Sek110237  * by the syntax. Acquire the  filebench_shm->threadflow_lock and
4415184Sek110237  * call threadflow_define_common() to create a threadflow entity.
4425184Sek110237  * Set the number of instances to create at runtime,
4435184Sek110237  * tf_instances, to "instances". Return the threadflow pointer
4445184Sek110237  * returned by the threadflow_define_common call.
4455184Sek110237  */
4465184Sek110237 threadflow_t *
4475184Sek110237 threadflow_define(procflow_t *procflow, char *name,
448*6212Saw148015     threadflow_t *inherit, avd_t instances)
4495184Sek110237 {
4505184Sek110237 	threadflow_t *threadflow;
4515184Sek110237 
4525184Sek110237 	(void) ipc_mutex_lock(&filebench_shm->threadflow_lock);
4535184Sek110237 
4545184Sek110237 	if ((threadflow = threadflow_define_common(procflow, name,
4555184Sek110237 	    inherit, FLOW_MASTER)) == NULL)
4565184Sek110237 		return (NULL);
4575184Sek110237 
4585184Sek110237 	threadflow->tf_instances = instances;
4595184Sek110237 
4605184Sek110237 	(void) ipc_mutex_unlock(&filebench_shm->threadflow_lock);
4615184Sek110237 
4625184Sek110237 	return (threadflow);
4635184Sek110237 }
4645184Sek110237 
4655184Sek110237 
4665184Sek110237 /*
4675184Sek110237  * Searches the provided threadflow list for the named threadflow.
4685184Sek110237  * A pointer to the threadflow is returned, or NULL if threadflow
4695184Sek110237  * is not found.
4705184Sek110237  */
4715184Sek110237 threadflow_t *
4725184Sek110237 threadflow_find(threadflow_t *threadlist, char *name)
4735184Sek110237 {
4745184Sek110237 	threadflow_t *threadflow = threadlist;
4755184Sek110237 
4765184Sek110237 	(void) ipc_mutex_lock(&filebench_shm->threadflow_lock);
4775184Sek110237 
4785184Sek110237 	while (threadflow) {
4795184Sek110237 		if (strcmp(name, threadflow->tf_name) == 0) {
4805184Sek110237 
4815184Sek110237 			(void) ipc_mutex_unlock(
4825184Sek110237 			    &filebench_shm->threadflow_lock);
4835184Sek110237 
4845184Sek110237 			return (threadflow);
4855184Sek110237 		}
4865184Sek110237 		threadflow = threadflow->tf_next;
4875184Sek110237 	}
4885184Sek110237 
4895184Sek110237 	(void) ipc_mutex_unlock(&filebench_shm->threadflow_lock);
4905184Sek110237 
4915184Sek110237 
4925184Sek110237 	return (NULL);
4935184Sek110237 }
494