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 /*
22*6084Saw148015  * 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 {
855184Sek110237 	filebench_log(LOG_DEBUG_SCRIPT, "Creating thread %s, memory = %ld",
865184Sek110237 	    threadflow->tf_name,
875184Sek110237 	    *threadflow->tf_memsize);
885184Sek110237 
895184Sek110237 	if (threadflow->tf_attrs & THREADFLOW_USEISM)
905184Sek110237 		filebench_shm->shm_required += (*threadflow->tf_memsize);
915184Sek110237 
925184Sek110237 	if (pthread_create(&threadflow->tf_tid, NULL,
935184Sek110237 	    (void *(*)(void*))flowop_start, threadflow) != 0) {
945184Sek110237 		filebench_log(LOG_ERROR, "thread create failed");
955184Sek110237 		filebench_shutdown(1);
96*6084Saw148015 		return (FILEBENCH_ERROR);
975184Sek110237 	}
985184Sek110237 
99*6084Saw148015 	return (FILEBENCH_OK);
1005184Sek110237 }
1015184Sek110237 
1025184Sek110237 /*
1035184Sek110237  * Terminates (exits) all the threads of the procflow (process).
1045184Sek110237  * The procflow is determined from a process private pointer
1055184Sek110237  * initialized by threadflow_init().
1065184Sek110237  */
1075184Sek110237 /* ARGSUSED */
1085184Sek110237 static void
1095184Sek110237 threadflow_cancel(int arg1)
1105184Sek110237 {
111*6084Saw148015 	threadflow_t *threadflow;
1125184Sek110237 
1135184Sek110237 #ifdef HAVE_LWPS
1145184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "Thread signal handler on tid %d",
1155184Sek110237 	    _lwp_self());
1165184Sek110237 #endif
1175184Sek110237 
118*6084Saw148015 	threadflow = my_procflow->pf_threads;
1195184Sek110237 	my_procflow->pf_running = 0;
1205184Sek110237 
1215184Sek110237 	while (threadflow) {
1225184Sek110237 		if (threadflow->tf_tid) {
123*6084Saw148015 			/* make sure thread has been cleaned up */
124*6084Saw148015 			flowop_destruct_all_flows(threadflow);
125*6084Saw148015 
1265184Sek110237 			(void) pthread_cancel(threadflow->tf_tid);
1275184Sek110237 			filebench_log(LOG_DEBUG_IMPL, "Thread %d cancelled...",
1285184Sek110237 			    threadflow->tf_tid);
1295184Sek110237 		}
1305184Sek110237 		threadflow = threadflow->tf_next;
1315184Sek110237 	}
132*6084Saw148015 
133*6084Saw148015 	exit(0);
1345184Sek110237 }
1355184Sek110237 
1365184Sek110237 /*
1375184Sek110237  * Creates threads for the threadflows associated with a procflow.
1385184Sek110237  * The routine iterates through the list of threadflows in the
1395184Sek110237  * supplied procflow's pf_threads list. For each threadflow on
1405184Sek110237  * the list, it defines tf_instances number of cloned
1415184Sek110237  * threadflows, and then calls threadflow_createthread() for
1425184Sek110237  * each to create and start the actual operating system thread.
1435184Sek110237  * Note that each of the newly defined threadflows will be linked
1445184Sek110237  * into the procflows threadflow list, but at the head of the
1455184Sek110237  * list, so they will not become part of the supplied set. After
1465184Sek110237  * all the threads have been created, threadflow_init enters
1475184Sek110237  * a join loop for all the threads in the newly defined
1485184Sek110237  * threadflows. Once all the created threads have exited,
1495184Sek110237  * threadflow_init will return 0. If errors are encountered, it
1505184Sek110237  * will return a non zero value.
1515184Sek110237  */
1525184Sek110237 int
1535184Sek110237 threadflow_init(procflow_t *procflow)
1545184Sek110237 {
1555184Sek110237 	threadflow_t *threadflow = procflow->pf_threads;
1565184Sek110237 	int ret = 0;
1575184Sek110237 
1585184Sek110237 	(void) ipc_mutex_lock(&filebench_shm->threadflow_lock);
1595184Sek110237 
1605184Sek110237 	(void) signal(SIGUSR1, threadflow_cancel);
161*6084Saw148015 
1625184Sek110237 	while (threadflow) {
1635184Sek110237 		threadflow_t *newthread;
1645184Sek110237 		int i;
1655184Sek110237 
1665184Sek110237 		filebench_log(LOG_VERBOSE,
1675184Sek110237 		    "Starting %lld %s threads",
1685184Sek110237 		    *(threadflow->tf_instances),
1695184Sek110237 		    threadflow->tf_name);
1705184Sek110237 
1715184Sek110237 		for (i = 1; i < *threadflow->tf_instances; i++) {
1725184Sek110237 			/* Create threads */
1735184Sek110237 			newthread =
1745184Sek110237 			    threadflow_define_common(procflow,
1755184Sek110237 			    threadflow->tf_name, threadflow, i + 1);
1765184Sek110237 			if (newthread == NULL)
1775184Sek110237 				return (-1);
178*6084Saw148015 			ret |= threadflow_createthread(newthread);
1795184Sek110237 		}
1805184Sek110237 
1815184Sek110237 		newthread = threadflow_define_common(procflow,
1825184Sek110237 		    threadflow->tf_name,
1835184Sek110237 		    threadflow, 1);
1845184Sek110237 
1855184Sek110237 		if (newthread == NULL)
1865184Sek110237 			return (-1);
1875184Sek110237 
188*6084Saw148015 		/* Create each thread */
189*6084Saw148015 		ret |= threadflow_createthread(newthread);
1905184Sek110237 
1915184Sek110237 		threadflow = threadflow->tf_next;
1925184Sek110237 	}
1935184Sek110237 
1945184Sek110237 	threadflow = procflow->pf_threads;
1955184Sek110237 
1965184Sek110237 	(void) ipc_mutex_unlock(&filebench_shm->threadflow_lock);
1975184Sek110237 
1985184Sek110237 	while (threadflow) {
1995184Sek110237 		void *status;
2005184Sek110237 
201*6084Saw148015 		/* wait for all threads to finish */
2025184Sek110237 		if (threadflow->tf_tid)
2035184Sek110237 			(void) pthread_join(threadflow->tf_tid, &status);
2045184Sek110237 
205*6084Saw148015 		ret |= *(int *)status;
2065184Sek110237 		threadflow = threadflow->tf_next;
2075184Sek110237 	}
2085184Sek110237 
2095184Sek110237 	procflow->pf_running = 0;
2105184Sek110237 
2115184Sek110237 	return (ret);
2125184Sek110237 }
2135184Sek110237 
2145184Sek110237 /*
2155184Sek110237  * Tells the threadflow's thread to stop and optionally signals
2165184Sek110237  * its associated process to end the thread.
2175184Sek110237  */
2185184Sek110237 static void
219*6084Saw148015 threadflow_kill(threadflow_t *threadflow, int wait_cnt)
2205184Sek110237 {
2215184Sek110237 	/* Tell thread to finish */
2225184Sek110237 	threadflow->tf_abort = 1;
2235184Sek110237 
224*6084Saw148015 	/* wait a bit for threadflow to stop */
225*6084Saw148015 	while (wait_cnt && threadflow->tf_running) {
226*6084Saw148015 		(void) sleep(1);
227*6084Saw148015 		wait_cnt--;
228*6084Saw148015 	}
229*6084Saw148015 
2305184Sek110237 #ifdef USE_PROCESS_MODEL
2315184Sek110237 #ifdef HAVE_SIGSEND
2325184Sek110237 	(void) sigsend(P_PID, threadflow->tf_process->pf_pid, SIGUSR1);
2335184Sek110237 #else
2345184Sek110237 	(void) kill(threadflow->tf_process->pf_pid, SIGUSR1);
2355184Sek110237 #endif
2365184Sek110237 #else /* USE_PROCESS_MODEL */
2375184Sek110237 	threadflow->tf_process->pf_running = 0;
2385184Sek110237 #endif /* USE_PROCESS_MODEL */
2395184Sek110237 }
2405184Sek110237 
2415184Sek110237 /*
2425184Sek110237  * Deletes the specified threadflow from the specified threadflow
2435184Sek110237  * list after first terminating the threadflow's thread, deleting
2445184Sek110237  * the threadflow's flowops, and finally freeing the threadflow
2455184Sek110237  * entity. It also subtracts the threadflow's shared memory
2465184Sek110237  * requirements from the total amount required, shm_required. If
2475184Sek110237  * the specified threadflow is found, returns 0, otherwise
2485184Sek110237  * returns -1.
2495184Sek110237  */
2505184Sek110237 static int
251*6084Saw148015 threadflow_delete(threadflow_t **threadlist, threadflow_t *threadflow,
252*6084Saw148015     int wait_cnt)
2535184Sek110237 {
2545184Sek110237 	threadflow_t *entry = *threadlist;
2555184Sek110237 
2565184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "Deleting thread: (%s-%d)",
2575184Sek110237 	    threadflow->tf_name,
2585184Sek110237 	    threadflow->tf_instance);
2595184Sek110237 
2605184Sek110237 	if (threadflow->tf_attrs & THREADFLOW_USEISM) {
2615184Sek110237 		filebench_shm->shm_required -= (*threadflow->tf_memsize);
2625184Sek110237 	}
2635184Sek110237 
2645184Sek110237 	if (threadflow == *threadlist) {
2655184Sek110237 		/* First on list */
2665184Sek110237 		filebench_log(LOG_DEBUG_IMPL, "Deleted thread: (%s-%d)",
2675184Sek110237 		    threadflow->tf_name,
2685184Sek110237 		    threadflow->tf_instance);
2695184Sek110237 
270*6084Saw148015 		threadflow_kill(threadflow, wait_cnt);
2715184Sek110237 		flowop_delete_all(&threadflow->tf_ops);
2725184Sek110237 		*threadlist = threadflow->tf_next;
2735184Sek110237 		ipc_free(FILEBENCH_THREADFLOW, (char *)threadflow);
2745184Sek110237 		return (0);
2755184Sek110237 	}
2765184Sek110237 
2775184Sek110237 	while (entry->tf_next) {
2785184Sek110237 		filebench_log(LOG_DEBUG_IMPL,
2795184Sek110237 		    "Delete thread: (%s-%d) == (%s-%d)",
2805184Sek110237 		    entry->tf_next->tf_name,
2815184Sek110237 		    entry->tf_next->tf_instance,
2825184Sek110237 		    threadflow->tf_name,
2835184Sek110237 		    threadflow->tf_instance);
2845184Sek110237 
2855184Sek110237 		if (threadflow == entry->tf_next) {
2865184Sek110237 			/* Delete */
2875184Sek110237 			filebench_log(LOG_DEBUG_IMPL,
2885184Sek110237 			    "Deleted thread: (%s-%d)",
2895184Sek110237 			    entry->tf_next->tf_name,
2905184Sek110237 			    entry->tf_next->tf_instance);
291*6084Saw148015 			threadflow_kill(entry->tf_next, wait_cnt);
2925184Sek110237 			flowop_delete_all(&entry->tf_next->tf_ops);
2935184Sek110237 			ipc_free(FILEBENCH_THREADFLOW, (char *)threadflow);
2945184Sek110237 			entry->tf_next = entry->tf_next->tf_next;
2955184Sek110237 			return (0);
2965184Sek110237 		}
2975184Sek110237 		entry = entry->tf_next;
2985184Sek110237 	}
2995184Sek110237 
3005184Sek110237 	return (-1);
3015184Sek110237 }
3025184Sek110237 
3035184Sek110237 /*
3045184Sek110237  * Given a pointer to the thread list of a procflow, cycles
3055184Sek110237  * through all the threadflows on the list, deleting each one
3065184Sek110237  * except the FLOW_MASTER.
3075184Sek110237  */
3085184Sek110237 void
309*6084Saw148015 threadflow_delete_all(threadflow_t **threadlist, int wait_cnt)
3105184Sek110237 {
3115184Sek110237 	threadflow_t *threadflow = *threadlist;
3125184Sek110237 
3135184Sek110237 	(void) ipc_mutex_lock(&filebench_shm->threadflow_lock);
3145184Sek110237 
3155184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "Deleting all threads");
3165184Sek110237 
3175184Sek110237 	while (threadflow) {
3185184Sek110237 		if (threadflow->tf_instance &&
3195184Sek110237 		    (threadflow->tf_instance == FLOW_MASTER)) {
3205184Sek110237 			threadflow = threadflow->tf_next;
3215184Sek110237 			continue;
3225184Sek110237 		}
323*6084Saw148015 		(void) threadflow_delete(threadlist, threadflow, wait_cnt);
3245184Sek110237 		threadflow = threadflow->tf_next;
325*6084Saw148015 		/* grow more impatient */
326*6084Saw148015 		if (wait_cnt > 0)
327*6084Saw148015 			wait_cnt--;
3285184Sek110237 	}
3295184Sek110237 
3305184Sek110237 	(void) ipc_mutex_unlock(&filebench_shm->threadflow_lock);
3315184Sek110237 }
3325184Sek110237 
3335184Sek110237 /*
3345184Sek110237  * Waits till all threadflows are started, or a timeout occurs.
3355184Sek110237  * Checks through the list of threadflows, waiting up to 10
3365184Sek110237  * seconds for each one to set its tf_running flag to 1. If not
3375184Sek110237  * set after 10 seconds, continues on to the next threadflow
3385184Sek110237  * anyway.
3395184Sek110237  */
3405184Sek110237 void
3415184Sek110237 threadflow_allstarted(pid_t pid, threadflow_t *threadflow)
3425184Sek110237 {
3435184Sek110237 	(void) ipc_mutex_lock(&filebench_shm->threadflow_lock);
3445184Sek110237 
3455184Sek110237 	while (threadflow) {
3465184Sek110237 		int waits;
3475184Sek110237 
3485184Sek110237 		if ((threadflow->tf_instance == 0) ||
3495184Sek110237 		    (threadflow->tf_instance == FLOW_MASTER)) {
3505184Sek110237 			threadflow = threadflow->tf_next;
3515184Sek110237 			continue;
3525184Sek110237 		}
3535184Sek110237 
3545184Sek110237 		filebench_log(LOG_DEBUG_IMPL, "Checking pid %d thread %s-%d",
3555184Sek110237 		    pid,
3565184Sek110237 		    threadflow->tf_name,
3575184Sek110237 		    threadflow->tf_instance);
3585184Sek110237 
3595184Sek110237 		waits = 10;
3605184Sek110237 		while (waits && threadflow->tf_running == 0) {
3615184Sek110237 			(void) ipc_mutex_unlock(
3625184Sek110237 			    &filebench_shm->threadflow_lock);
3635184Sek110237 			if (waits < 3)
3645184Sek110237 				filebench_log(LOG_INFO,
3655184Sek110237 				    "Waiting for pid %d thread %s-%d",
3665184Sek110237 				    pid,
3675184Sek110237 				    threadflow->tf_name,
3685184Sek110237 				    threadflow->tf_instance);
3695184Sek110237 
3705184Sek110237 			(void) sleep(1);
3715184Sek110237 			(void) ipc_mutex_lock(&filebench_shm->threadflow_lock);
3725184Sek110237 			waits--;
3735184Sek110237 		}
3745184Sek110237 
3755184Sek110237 		threadflow = threadflow->tf_next;
3765184Sek110237 	}
3775184Sek110237 
3785184Sek110237 	(void) ipc_mutex_unlock(&filebench_shm->threadflow_lock);
3795184Sek110237 }
3805184Sek110237 
3815184Sek110237 /*
3825184Sek110237  * Create an in-memory thread object linked to a parent procflow.
3835184Sek110237  * A threadflow entity is allocated from shared memory and
3845184Sek110237  * initialized from the "inherit" threadflow if supplied,
3855184Sek110237  * otherwise to zeros. The threadflow is assigned a unique
3865184Sek110237  * thread id, the supplied instance number, the supplied name
3875184Sek110237  * and added to the procflow's pf_thread list. If no name is
3885184Sek110237  * supplied or the threadflow can't be allocated, NULL is
3895184Sek110237  * returned Otherwise a pointer to the newly allocated threadflow
3905184Sek110237  * is returned.
3915184Sek110237  *
3925184Sek110237  * The filebench_shm->threadflow_lock must be held by the caller.
3935184Sek110237  */
3945184Sek110237 static threadflow_t *
3955184Sek110237 threadflow_define_common(procflow_t *procflow, char *name,
3965184Sek110237     threadflow_t *inherit, int instance)
3975184Sek110237 {
3985184Sek110237 	threadflow_t *threadflow;
3995184Sek110237 	threadflow_t **threadlistp = &procflow->pf_threads;
4005184Sek110237 
4015184Sek110237 	if (name == NULL)
4025184Sek110237 		return (NULL);
4035184Sek110237 
4045184Sek110237 	threadflow = (threadflow_t *)ipc_malloc(FILEBENCH_THREADFLOW);
4055184Sek110237 
4065184Sek110237 	if (threadflow == NULL)
4075184Sek110237 		return (NULL);
4085184Sek110237 
4095184Sek110237 	if (inherit)
4105184Sek110237 		(void) memcpy(threadflow, inherit, sizeof (threadflow_t));
4115184Sek110237 	else
4125184Sek110237 		(void) memset(threadflow, 0, sizeof (threadflow_t));
4135184Sek110237 
4145184Sek110237 	threadflow->tf_utid = ++filebench_shm->utid;
4155184Sek110237 
4165184Sek110237 	threadflow->tf_instance = instance;
4175184Sek110237 	(void) strcpy(threadflow->tf_name, name);
4185184Sek110237 	threadflow->tf_process = procflow;
4195184Sek110237 
4205184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "Defining thread %s-%d",
4215184Sek110237 	    name, instance);
4225184Sek110237 
4235184Sek110237 	/* Add threadflow to list */
4245184Sek110237 	if (*threadlistp == NULL) {
4255184Sek110237 		*threadlistp = threadflow;
4265184Sek110237 		threadflow->tf_next = NULL;
4275184Sek110237 	} else {
4285184Sek110237 		threadflow->tf_next = *threadlistp;
4295184Sek110237 		*threadlistp = threadflow;
4305184Sek110237 	}
4315184Sek110237 
4325184Sek110237 	return (threadflow);
4335184Sek110237 }
4345184Sek110237 
4355184Sek110237 /*
4365184Sek110237  * Create an in memory FLOW_MASTER thread object as described
4375184Sek110237  * by the syntax. Acquire the  filebench_shm->threadflow_lock and
4385184Sek110237  * call threadflow_define_common() to create a threadflow entity.
4395184Sek110237  * Set the number of instances to create at runtime,
4405184Sek110237  * tf_instances, to "instances". Return the threadflow pointer
4415184Sek110237  * returned by the threadflow_define_common call.
4425184Sek110237  */
4435184Sek110237 threadflow_t *
4445184Sek110237 threadflow_define(procflow_t *procflow, char *name,
4455184Sek110237     threadflow_t *inherit, var_integer_t instances)
4465184Sek110237 {
4475184Sek110237 	threadflow_t *threadflow;
4485184Sek110237 
4495184Sek110237 	(void) ipc_mutex_lock(&filebench_shm->threadflow_lock);
4505184Sek110237 
4515184Sek110237 	if ((threadflow = threadflow_define_common(procflow, name,
4525184Sek110237 	    inherit, FLOW_MASTER)) == NULL)
4535184Sek110237 		return (NULL);
4545184Sek110237 
4555184Sek110237 	threadflow->tf_instances = instances;
4565184Sek110237 
4575184Sek110237 	(void) ipc_mutex_unlock(&filebench_shm->threadflow_lock);
4585184Sek110237 
4595184Sek110237 	return (threadflow);
4605184Sek110237 }
4615184Sek110237 
4625184Sek110237 
4635184Sek110237 /*
4645184Sek110237  * Searches the provided threadflow list for the named threadflow.
4655184Sek110237  * A pointer to the threadflow is returned, or NULL if threadflow
4665184Sek110237  * is not found.
4675184Sek110237  */
4685184Sek110237 threadflow_t *
4695184Sek110237 threadflow_find(threadflow_t *threadlist, char *name)
4705184Sek110237 {
4715184Sek110237 	threadflow_t *threadflow = threadlist;
4725184Sek110237 
4735184Sek110237 	(void) ipc_mutex_lock(&filebench_shm->threadflow_lock);
4745184Sek110237 
4755184Sek110237 	while (threadflow) {
4765184Sek110237 		if (strcmp(name, threadflow->tf_name) == 0) {
4775184Sek110237 
4785184Sek110237 			(void) ipc_mutex_unlock(
4795184Sek110237 			    &filebench_shm->threadflow_lock);
4805184Sek110237 
4815184Sek110237 			return (threadflow);
4825184Sek110237 		}
4835184Sek110237 		threadflow = threadflow->tf_next;
4845184Sek110237 	}
4855184Sek110237 
4865184Sek110237 	(void) ipc_mutex_unlock(&filebench_shm->threadflow_lock);
4875184Sek110237 
4885184Sek110237 
4895184Sek110237 	return (NULL);
4905184Sek110237 }
491