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. 246613Sek110237 * 256613Sek110237 * Portions Copyright 2008 Denis Cheng 265184Sek110237 */ 275184Sek110237 285184Sek110237 #include "config.h" 295184Sek110237 #include <pthread.h> 305184Sek110237 #ifdef HAVE_LWPS 315184Sek110237 #include <sys/lwp.h> 325184Sek110237 #endif 335184Sek110237 #include <signal.h> 346613Sek110237 356613Sek110237 #include "filebench.h" 365184Sek110237 #include "threadflow.h" 375184Sek110237 #include "flowop.h" 385184Sek110237 #include "ipc.h" 395184Sek110237 405184Sek110237 static threadflow_t *threadflow_define_common(procflow_t *procflow, 415184Sek110237 char *name, threadflow_t *inherit, int instance); 425184Sek110237 435184Sek110237 /* 445184Sek110237 * Threadflows are filebench entities which manage operating system 455184Sek110237 * threads. Each worker threadflow spawns a separate filebench thread, 465184Sek110237 * with attributes inherited from a FLOW_MASTER threadflow created during 475184Sek110237 * f model language parsing. This section contains routines to define, 485184Sek110237 * create, control, and delete threadflows. 495184Sek110237 * 505184Sek110237 * Each thread defined in the f model creates a FLOW_MASTER 515184Sek110237 * threadflow which encapsulates the defined attributes and flowops of 525184Sek110237 * the f language thread, including the number of instances to create. 535184Sek110237 * At runtime, a worker threadflow instance with an associated filebench 545184Sek110237 * thread is created, which runs until told to quit or is specifically 555184Sek110237 * deleted. 565184Sek110237 */ 575184Sek110237 585184Sek110237 595184Sek110237 /* 605184Sek110237 * Prints information about threadflow syntax. 615184Sek110237 */ 625184Sek110237 void 635184Sek110237 threadflow_usage(void) 645184Sek110237 { 655184Sek110237 (void) fprintf(stderr, " thread name=<name>[,instances=<count>]\n"); 665184Sek110237 (void) fprintf(stderr, "\n"); 675184Sek110237 (void) fprintf(stderr, " {\n"); 685184Sek110237 (void) fprintf(stderr, " flowop ...\n"); 695184Sek110237 (void) fprintf(stderr, " flowop ...\n"); 705184Sek110237 (void) fprintf(stderr, " flowop ...\n"); 715184Sek110237 (void) fprintf(stderr, " }\n"); 725184Sek110237 (void) fprintf(stderr, "\n"); 735184Sek110237 } 745184Sek110237 755184Sek110237 /* 765184Sek110237 * Creates a thread for the supplied threadflow. If interprocess 775184Sek110237 * shared memory is desired, then increments the amount of shared 785184Sek110237 * memory needed by the amount specified in the threadflow's 795184Sek110237 * tf_memsize parameter. The thread starts in routine 805184Sek110237 * flowop_start() with a poineter to the threadflow supplied 815184Sek110237 * as the argument. 825184Sek110237 */ 835184Sek110237 static int 845184Sek110237 threadflow_createthread(threadflow_t *threadflow) 855184Sek110237 { 866212Saw148015 fbint_t memsize; 876212Saw148015 memsize = avd_get_int(threadflow->tf_memsize); 886212Saw148015 threadflow->tf_constmemsize = memsize; 896212Saw148015 905184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, "Creating thread %s, memory = %ld", 916212Saw148015 threadflow->tf_name, memsize); 925184Sek110237 935184Sek110237 if (threadflow->tf_attrs & THREADFLOW_USEISM) 946212Saw148015 filebench_shm->shm_required += memsize; 955184Sek110237 965184Sek110237 if (pthread_create(&threadflow->tf_tid, NULL, 975184Sek110237 (void *(*)(void*))flowop_start, threadflow) != 0) { 985184Sek110237 filebench_log(LOG_ERROR, "thread create failed"); 995184Sek110237 filebench_shutdown(1); 1006084Saw148015 return (FILEBENCH_ERROR); 1015184Sek110237 } 1025184Sek110237 1036084Saw148015 return (FILEBENCH_OK); 1045184Sek110237 } 1055184Sek110237 1065184Sek110237 /* 1075184Sek110237 * Terminates (exits) all the threads of the procflow (process). 1085184Sek110237 * The procflow is determined from a process private pointer 1095184Sek110237 * initialized by threadflow_init(). 1105184Sek110237 */ 1115184Sek110237 /* ARGSUSED */ 1125184Sek110237 static void 1135184Sek110237 threadflow_cancel(int arg1) 1145184Sek110237 { 1156084Saw148015 threadflow_t *threadflow; 1165184Sek110237 1175184Sek110237 #ifdef HAVE_LWPS 1185184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Thread signal handler on tid %d", 1195184Sek110237 _lwp_self()); 1205184Sek110237 #endif 1215184Sek110237 1226084Saw148015 threadflow = my_procflow->pf_threads; 1235184Sek110237 my_procflow->pf_running = 0; 1245184Sek110237 1255184Sek110237 while (threadflow) { 1265184Sek110237 if (threadflow->tf_tid) { 1276084Saw148015 /* make sure thread has been cleaned up */ 1286084Saw148015 flowop_destruct_all_flows(threadflow); 1296084Saw148015 1305184Sek110237 (void) pthread_cancel(threadflow->tf_tid); 1315184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Thread %d cancelled...", 1325184Sek110237 threadflow->tf_tid); 1335184Sek110237 } 1345184Sek110237 threadflow = threadflow->tf_next; 1355184Sek110237 } 1366084Saw148015 1376084Saw148015 exit(0); 1385184Sek110237 } 1395184Sek110237 1405184Sek110237 /* 1415184Sek110237 * Creates threads for the threadflows associated with a procflow. 1425184Sek110237 * The routine iterates through the list of threadflows in the 1435184Sek110237 * supplied procflow's pf_threads list. For each threadflow on 1445184Sek110237 * the list, it defines tf_instances number of cloned 1455184Sek110237 * threadflows, and then calls threadflow_createthread() for 1465184Sek110237 * each to create and start the actual operating system thread. 1475184Sek110237 * Note that each of the newly defined threadflows will be linked 1485184Sek110237 * into the procflows threadflow list, but at the head of the 1495184Sek110237 * list, so they will not become part of the supplied set. After 1505184Sek110237 * all the threads have been created, threadflow_init enters 1515184Sek110237 * a join loop for all the threads in the newly defined 1525184Sek110237 * threadflows. Once all the created threads have exited, 1535184Sek110237 * threadflow_init will return 0. If errors are encountered, it 1545184Sek110237 * will return a non zero value. 1555184Sek110237 */ 1565184Sek110237 int 1575184Sek110237 threadflow_init(procflow_t *procflow) 1585184Sek110237 { 1595184Sek110237 threadflow_t *threadflow = procflow->pf_threads; 1605184Sek110237 int ret = 0; 1615184Sek110237 1626391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_threadflow_lock); 1635184Sek110237 1645184Sek110237 (void) signal(SIGUSR1, threadflow_cancel); 1656084Saw148015 1665184Sek110237 while (threadflow) { 1675184Sek110237 threadflow_t *newthread; 1686212Saw148015 int instances; 1695184Sek110237 int i; 1705184Sek110237 1716212Saw148015 instances = avd_get_int(threadflow->tf_instances); 1725184Sek110237 filebench_log(LOG_VERBOSE, 1736286Saw148015 "Starting %d %s threads", 1746212Saw148015 instances, threadflow->tf_name); 1755184Sek110237 1766212Saw148015 for (i = 1; i < instances; i++) { 1775184Sek110237 /* Create threads */ 1785184Sek110237 newthread = 1795184Sek110237 threadflow_define_common(procflow, 1805184Sek110237 threadflow->tf_name, threadflow, i + 1); 1815184Sek110237 if (newthread == NULL) 1825184Sek110237 return (-1); 1836084Saw148015 ret |= threadflow_createthread(newthread); 1845184Sek110237 } 1855184Sek110237 1865184Sek110237 newthread = threadflow_define_common(procflow, 1875184Sek110237 threadflow->tf_name, 1885184Sek110237 threadflow, 1); 1895184Sek110237 1905184Sek110237 if (newthread == NULL) 1915184Sek110237 return (-1); 1925184Sek110237 1936084Saw148015 /* Create each thread */ 1946084Saw148015 ret |= threadflow_createthread(newthread); 1955184Sek110237 1965184Sek110237 threadflow = threadflow->tf_next; 1975184Sek110237 } 1985184Sek110237 1995184Sek110237 threadflow = procflow->pf_threads; 2005184Sek110237 2016391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_threadflow_lock); 2025184Sek110237 2035184Sek110237 while (threadflow) { 2046333Sek110237 /* wait for all threads to finish */ 2056333Sek110237 if (threadflow->tf_tid) { 2066333Sek110237 void *status; 2075184Sek110237 2086333Sek110237 if (pthread_join(threadflow->tf_tid, &status) == 0) 2096333Sek110237 ret += *(int *)status; 2106333Sek110237 } 2115184Sek110237 threadflow = threadflow->tf_next; 2125184Sek110237 } 2135184Sek110237 2145184Sek110237 procflow->pf_running = 0; 2155184Sek110237 2165184Sek110237 return (ret); 2175184Sek110237 } 2185184Sek110237 2195184Sek110237 /* 2205184Sek110237 * Tells the threadflow's thread to stop and optionally signals 2215184Sek110237 * its associated process to end the thread. 2225184Sek110237 */ 2235184Sek110237 static void 2246084Saw148015 threadflow_kill(threadflow_t *threadflow, int wait_cnt) 2255184Sek110237 { 2265184Sek110237 /* Tell thread to finish */ 2275184Sek110237 threadflow->tf_abort = 1; 2285184Sek110237 2296084Saw148015 /* wait a bit for threadflow to stop */ 2306084Saw148015 while (wait_cnt && threadflow->tf_running) { 2316084Saw148015 (void) sleep(1); 2326084Saw148015 wait_cnt--; 2336084Saw148015 } 2346084Saw148015 2355184Sek110237 #ifdef USE_PROCESS_MODEL 2365184Sek110237 #ifdef HAVE_SIGSEND 2375184Sek110237 (void) sigsend(P_PID, threadflow->tf_process->pf_pid, SIGUSR1); 2385184Sek110237 #else 2395184Sek110237 (void) kill(threadflow->tf_process->pf_pid, SIGUSR1); 2405184Sek110237 #endif 2415184Sek110237 #else /* USE_PROCESS_MODEL */ 2425184Sek110237 threadflow->tf_process->pf_running = 0; 2435184Sek110237 #endif /* USE_PROCESS_MODEL */ 2445184Sek110237 } 2455184Sek110237 2465184Sek110237 /* 2475184Sek110237 * Deletes the specified threadflow from the specified threadflow 2485184Sek110237 * list after first terminating the threadflow's thread, deleting 2495184Sek110237 * the threadflow's flowops, and finally freeing the threadflow 2505184Sek110237 * entity. It also subtracts the threadflow's shared memory 2515184Sek110237 * requirements from the total amount required, shm_required. If 2525184Sek110237 * the specified threadflow is found, returns 0, otherwise 2535184Sek110237 * returns -1. 2545184Sek110237 */ 2555184Sek110237 static int 2566084Saw148015 threadflow_delete(threadflow_t **threadlist, threadflow_t *threadflow, 2576084Saw148015 int wait_cnt) 2585184Sek110237 { 2595184Sek110237 threadflow_t *entry = *threadlist; 2605184Sek110237 2615184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Deleting thread: (%s-%d)", 2625184Sek110237 threadflow->tf_name, 2635184Sek110237 threadflow->tf_instance); 2645184Sek110237 2656212Saw148015 if (threadflow->tf_attrs & THREADFLOW_USEISM) 2666212Saw148015 filebench_shm->shm_required -= threadflow->tf_constmemsize; 2675184Sek110237 2685184Sek110237 if (threadflow == *threadlist) { 2695184Sek110237 /* First on list */ 2705184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Deleted thread: (%s-%d)", 2715184Sek110237 threadflow->tf_name, 2725184Sek110237 threadflow->tf_instance); 2735184Sek110237 2746084Saw148015 threadflow_kill(threadflow, wait_cnt); 2756550Saw148015 flowop_delete_all(&threadflow->tf_thrd_fops); 2765184Sek110237 *threadlist = threadflow->tf_next; 2776613Sek110237 (void) pthread_mutex_destroy(&threadflow->tf_lock); 2785184Sek110237 ipc_free(FILEBENCH_THREADFLOW, (char *)threadflow); 2795184Sek110237 return (0); 2805184Sek110237 } 2815184Sek110237 2825184Sek110237 while (entry->tf_next) { 2835184Sek110237 filebench_log(LOG_DEBUG_IMPL, 2845184Sek110237 "Delete thread: (%s-%d) == (%s-%d)", 2855184Sek110237 entry->tf_next->tf_name, 2865184Sek110237 entry->tf_next->tf_instance, 2875184Sek110237 threadflow->tf_name, 2885184Sek110237 threadflow->tf_instance); 2895184Sek110237 2905184Sek110237 if (threadflow == entry->tf_next) { 2915184Sek110237 /* Delete */ 2925184Sek110237 filebench_log(LOG_DEBUG_IMPL, 2935184Sek110237 "Deleted thread: (%s-%d)", 2945184Sek110237 entry->tf_next->tf_name, 2955184Sek110237 entry->tf_next->tf_instance); 2966084Saw148015 threadflow_kill(entry->tf_next, wait_cnt); 2976550Saw148015 flowop_delete_all(&entry->tf_next->tf_thrd_fops); 2986613Sek110237 (void) pthread_mutex_destroy(&threadflow->tf_lock); 2995184Sek110237 ipc_free(FILEBENCH_THREADFLOW, (char *)threadflow); 3005184Sek110237 entry->tf_next = entry->tf_next->tf_next; 3015184Sek110237 return (0); 3025184Sek110237 } 3035184Sek110237 entry = entry->tf_next; 3045184Sek110237 } 3055184Sek110237 3065184Sek110237 return (-1); 3075184Sek110237 } 3085184Sek110237 3095184Sek110237 /* 3105184Sek110237 * Given a pointer to the thread list of a procflow, cycles 3115184Sek110237 * through all the threadflows on the list, deleting each one 3125184Sek110237 * except the FLOW_MASTER. 3135184Sek110237 */ 3145184Sek110237 void 3156084Saw148015 threadflow_delete_all(threadflow_t **threadlist, int wait_cnt) 3165184Sek110237 { 3175184Sek110237 threadflow_t *threadflow = *threadlist; 3185184Sek110237 3196391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_threadflow_lock); 3205184Sek110237 3215184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Deleting all threads"); 3225184Sek110237 3235184Sek110237 while (threadflow) { 3245184Sek110237 if (threadflow->tf_instance && 3255184Sek110237 (threadflow->tf_instance == FLOW_MASTER)) { 3265184Sek110237 threadflow = threadflow->tf_next; 3275184Sek110237 continue; 3285184Sek110237 } 3296084Saw148015 (void) threadflow_delete(threadlist, threadflow, wait_cnt); 3305184Sek110237 threadflow = threadflow->tf_next; 3316084Saw148015 /* grow more impatient */ 3326084Saw148015 if (wait_cnt > 0) 3336084Saw148015 wait_cnt--; 3345184Sek110237 } 3355184Sek110237 3366391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_threadflow_lock); 3375184Sek110237 } 3385184Sek110237 3395184Sek110237 /* 3405184Sek110237 * Waits till all threadflows are started, or a timeout occurs. 3415184Sek110237 * Checks through the list of threadflows, waiting up to 10 3425184Sek110237 * seconds for each one to set its tf_running flag to 1. If not 3435184Sek110237 * set after 10 seconds, continues on to the next threadflow 3445184Sek110237 * anyway. 3455184Sek110237 */ 3465184Sek110237 void 3475184Sek110237 threadflow_allstarted(pid_t pid, threadflow_t *threadflow) 3485184Sek110237 { 3496391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_threadflow_lock); 3505184Sek110237 3515184Sek110237 while (threadflow) { 3525184Sek110237 int waits; 3535184Sek110237 3545184Sek110237 if ((threadflow->tf_instance == 0) || 3555184Sek110237 (threadflow->tf_instance == FLOW_MASTER)) { 3565184Sek110237 threadflow = threadflow->tf_next; 3575184Sek110237 continue; 3585184Sek110237 } 3595184Sek110237 3605184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Checking pid %d thread %s-%d", 3615184Sek110237 pid, 3625184Sek110237 threadflow->tf_name, 3635184Sek110237 threadflow->tf_instance); 3645184Sek110237 3655184Sek110237 waits = 10; 3666391Saw148015 while (waits && (threadflow->tf_running == 0) && 3676391Saw148015 (filebench_shm->shm_f_abort == 0)) { 3685184Sek110237 (void) ipc_mutex_unlock( 3696391Saw148015 &filebench_shm->shm_threadflow_lock); 3705184Sek110237 if (waits < 3) 3715184Sek110237 filebench_log(LOG_INFO, 3725184Sek110237 "Waiting for pid %d thread %s-%d", 3735184Sek110237 pid, 3745184Sek110237 threadflow->tf_name, 3755184Sek110237 threadflow->tf_instance); 3765184Sek110237 3775184Sek110237 (void) sleep(1); 3786391Saw148015 (void) ipc_mutex_lock( 3796391Saw148015 &filebench_shm->shm_threadflow_lock); 3805184Sek110237 waits--; 3815184Sek110237 } 3825184Sek110237 3835184Sek110237 threadflow = threadflow->tf_next; 3845184Sek110237 } 3855184Sek110237 3866391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_threadflow_lock); 3875184Sek110237 } 3885184Sek110237 3895184Sek110237 /* 3905184Sek110237 * Create an in-memory thread object linked to a parent procflow. 3915184Sek110237 * A threadflow entity is allocated from shared memory and 3925184Sek110237 * initialized from the "inherit" threadflow if supplied, 3935184Sek110237 * otherwise to zeros. The threadflow is assigned a unique 3945184Sek110237 * thread id, the supplied instance number, the supplied name 3955184Sek110237 * and added to the procflow's pf_thread list. If no name is 3965184Sek110237 * supplied or the threadflow can't be allocated, NULL is 3975184Sek110237 * returned Otherwise a pointer to the newly allocated threadflow 3985184Sek110237 * is returned. 3995184Sek110237 * 4006391Saw148015 * The filebench_shm->shm_threadflow_lock must be held by the caller. 4015184Sek110237 */ 4025184Sek110237 static threadflow_t * 4035184Sek110237 threadflow_define_common(procflow_t *procflow, char *name, 4045184Sek110237 threadflow_t *inherit, int instance) 4055184Sek110237 { 4065184Sek110237 threadflow_t *threadflow; 4075184Sek110237 threadflow_t **threadlistp = &procflow->pf_threads; 4085184Sek110237 4095184Sek110237 if (name == NULL) 4105184Sek110237 return (NULL); 4115184Sek110237 4125184Sek110237 threadflow = (threadflow_t *)ipc_malloc(FILEBENCH_THREADFLOW); 4135184Sek110237 4145184Sek110237 if (threadflow == NULL) 4155184Sek110237 return (NULL); 4165184Sek110237 4175184Sek110237 if (inherit) 4185184Sek110237 (void) memcpy(threadflow, inherit, sizeof (threadflow_t)); 4195184Sek110237 else 4205184Sek110237 (void) memset(threadflow, 0, sizeof (threadflow_t)); 4215184Sek110237 4226391Saw148015 threadflow->tf_utid = ++filebench_shm->shm_utid; 4235184Sek110237 4245184Sek110237 threadflow->tf_instance = instance; 4255184Sek110237 (void) strcpy(threadflow->tf_name, name); 4265184Sek110237 threadflow->tf_process = procflow; 427*7556SAndrew.W.Wilson@sun.com (void) pthread_mutex_init(&threadflow->tf_lock, 428*7556SAndrew.W.Wilson@sun.com ipc_mutexattr(IPC_MUTEX_NORMAL)); 4295184Sek110237 4305184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Defining thread %s-%d", 4315184Sek110237 name, instance); 4325184Sek110237 4335184Sek110237 /* Add threadflow to list */ 4345184Sek110237 if (*threadlistp == NULL) { 4355184Sek110237 *threadlistp = threadflow; 4365184Sek110237 threadflow->tf_next = NULL; 4375184Sek110237 } else { 4385184Sek110237 threadflow->tf_next = *threadlistp; 4395184Sek110237 *threadlistp = threadflow; 4405184Sek110237 } 4415184Sek110237 4425184Sek110237 return (threadflow); 4435184Sek110237 } 4445184Sek110237 4455184Sek110237 /* 4465184Sek110237 * Create an in memory FLOW_MASTER thread object as described 4476391Saw148015 * by the syntax. Acquire the filebench_shm->shm_threadflow_lock and 4485184Sek110237 * call threadflow_define_common() to create a threadflow entity. 4495184Sek110237 * Set the number of instances to create at runtime, 4505184Sek110237 * tf_instances, to "instances". Return the threadflow pointer 4515184Sek110237 * returned by the threadflow_define_common call. 4525184Sek110237 */ 4535184Sek110237 threadflow_t * 4545184Sek110237 threadflow_define(procflow_t *procflow, char *name, 4556212Saw148015 threadflow_t *inherit, avd_t instances) 4565184Sek110237 { 4575184Sek110237 threadflow_t *threadflow; 4585184Sek110237 4596391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_threadflow_lock); 4605184Sek110237 4615184Sek110237 if ((threadflow = threadflow_define_common(procflow, name, 4625184Sek110237 inherit, FLOW_MASTER)) == NULL) 4635184Sek110237 return (NULL); 4645184Sek110237 4655184Sek110237 threadflow->tf_instances = instances; 4665184Sek110237 4676391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_threadflow_lock); 4685184Sek110237 4695184Sek110237 return (threadflow); 4705184Sek110237 } 4715184Sek110237 4725184Sek110237 4735184Sek110237 /* 4745184Sek110237 * Searches the provided threadflow list for the named threadflow. 4755184Sek110237 * A pointer to the threadflow is returned, or NULL if threadflow 4765184Sek110237 * is not found. 4775184Sek110237 */ 4785184Sek110237 threadflow_t * 4795184Sek110237 threadflow_find(threadflow_t *threadlist, char *name) 4805184Sek110237 { 4815184Sek110237 threadflow_t *threadflow = threadlist; 4825184Sek110237 4836391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_threadflow_lock); 4845184Sek110237 4855184Sek110237 while (threadflow) { 4865184Sek110237 if (strcmp(name, threadflow->tf_name) == 0) { 4875184Sek110237 4885184Sek110237 (void) ipc_mutex_unlock( 4896391Saw148015 &filebench_shm->shm_threadflow_lock); 4905184Sek110237 4915184Sek110237 return (threadflow); 4925184Sek110237 } 4935184Sek110237 threadflow = threadflow->tf_next; 4945184Sek110237 } 4955184Sek110237 4966391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_threadflow_lock); 4975184Sek110237 4985184Sek110237 4995184Sek110237 return (NULL); 5005184Sek110237 } 501