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 #include <pthread.h> 30*5184Sek110237 #ifdef HAVE_LWPS 31*5184Sek110237 #include <sys/lwp.h> 32*5184Sek110237 #endif 33*5184Sek110237 #include <signal.h> 34*5184Sek110237 #include "threadflow.h" 35*5184Sek110237 #include "filebench.h" 36*5184Sek110237 #include "flowop.h" 37*5184Sek110237 #include "ipc.h" 38*5184Sek110237 39*5184Sek110237 static threadflow_t *threadflow_define_common(procflow_t *procflow, 40*5184Sek110237 char *name, threadflow_t *inherit, int instance); 41*5184Sek110237 42*5184Sek110237 /* 43*5184Sek110237 * Threadflows are filebench entities which manage operating system 44*5184Sek110237 * threads. Each worker threadflow spawns a separate filebench thread, 45*5184Sek110237 * with attributes inherited from a FLOW_MASTER threadflow created during 46*5184Sek110237 * f model language parsing. This section contains routines to define, 47*5184Sek110237 * create, control, and delete threadflows. 48*5184Sek110237 * 49*5184Sek110237 * Each thread defined in the f model creates a FLOW_MASTER 50*5184Sek110237 * threadflow which encapsulates the defined attributes and flowops of 51*5184Sek110237 * the f language thread, including the number of instances to create. 52*5184Sek110237 * At runtime, a worker threadflow instance with an associated filebench 53*5184Sek110237 * thread is created, which runs until told to quit or is specifically 54*5184Sek110237 * deleted. 55*5184Sek110237 */ 56*5184Sek110237 57*5184Sek110237 58*5184Sek110237 /* 59*5184Sek110237 * Prints information about threadflow syntax. 60*5184Sek110237 */ 61*5184Sek110237 void 62*5184Sek110237 threadflow_usage(void) 63*5184Sek110237 { 64*5184Sek110237 (void) fprintf(stderr, " thread name=<name>[,instances=<count>]\n"); 65*5184Sek110237 (void) fprintf(stderr, "\n"); 66*5184Sek110237 (void) fprintf(stderr, " {\n"); 67*5184Sek110237 (void) fprintf(stderr, " flowop ...\n"); 68*5184Sek110237 (void) fprintf(stderr, " flowop ...\n"); 69*5184Sek110237 (void) fprintf(stderr, " flowop ...\n"); 70*5184Sek110237 (void) fprintf(stderr, " }\n"); 71*5184Sek110237 (void) fprintf(stderr, "\n"); 72*5184Sek110237 } 73*5184Sek110237 74*5184Sek110237 /* 75*5184Sek110237 * Creates a thread for the supplied threadflow. If interprocess 76*5184Sek110237 * shared memory is desired, then increments the amount of shared 77*5184Sek110237 * memory needed by the amount specified in the threadflow's 78*5184Sek110237 * tf_memsize parameter. The thread starts in routine 79*5184Sek110237 * flowop_start() with a poineter to the threadflow supplied 80*5184Sek110237 * as the argument. 81*5184Sek110237 */ 82*5184Sek110237 static int 83*5184Sek110237 threadflow_createthread(threadflow_t *threadflow) 84*5184Sek110237 { 85*5184Sek110237 int fp = 0; 86*5184Sek110237 87*5184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, "Creating thread %s, memory = %ld", 88*5184Sek110237 threadflow->tf_name, 89*5184Sek110237 *threadflow->tf_memsize); 90*5184Sek110237 91*5184Sek110237 if (threadflow->tf_attrs & THREADFLOW_USEISM) 92*5184Sek110237 filebench_shm->shm_required += (*threadflow->tf_memsize); 93*5184Sek110237 94*5184Sek110237 if (pthread_create(&threadflow->tf_tid, NULL, 95*5184Sek110237 (void *(*)(void*))flowop_start, threadflow) != 0) { 96*5184Sek110237 filebench_log(LOG_ERROR, "thread create failed"); 97*5184Sek110237 filebench_shutdown(1); 98*5184Sek110237 } 99*5184Sek110237 100*5184Sek110237 /* XXX */ 101*5184Sek110237 return (fp < 0); 102*5184Sek110237 } 103*5184Sek110237 104*5184Sek110237 #ifndef USE_PROCESS_MODEL 105*5184Sek110237 static procflow_t *my_procflow; 106*5184Sek110237 107*5184Sek110237 /* 108*5184Sek110237 * Terminates (exits) all the threads of the procflow (process). 109*5184Sek110237 * The procflow is determined from a process private pointer 110*5184Sek110237 * initialized by threadflow_init(). 111*5184Sek110237 */ 112*5184Sek110237 /* ARGSUSED */ 113*5184Sek110237 static void 114*5184Sek110237 threadflow_cancel(int arg1) 115*5184Sek110237 { 116*5184Sek110237 threadflow_t *threadflow = my_procflow->pf_threads; 117*5184Sek110237 118*5184Sek110237 #ifdef HAVE_LWPS 119*5184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Thread signal handler on tid %d", 120*5184Sek110237 _lwp_self()); 121*5184Sek110237 #endif 122*5184Sek110237 123*5184Sek110237 my_procflow->pf_running = 0; 124*5184Sek110237 exit(0); 125*5184Sek110237 126*5184Sek110237 while (threadflow) { 127*5184Sek110237 if (threadflow->tf_tid) { 128*5184Sek110237 (void) pthread_cancel(threadflow->tf_tid); 129*5184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Thread %d cancelled...", 130*5184Sek110237 threadflow->tf_tid); 131*5184Sek110237 } 132*5184Sek110237 threadflow = threadflow->tf_next; 133*5184Sek110237 } 134*5184Sek110237 } 135*5184Sek110237 #endif /* USE_PROCESS_MODEL */ 136*5184Sek110237 137*5184Sek110237 /* 138*5184Sek110237 * Creates threads for the threadflows associated with a procflow. 139*5184Sek110237 * The routine iterates through the list of threadflows in the 140*5184Sek110237 * supplied procflow's pf_threads list. For each threadflow on 141*5184Sek110237 * the list, it defines tf_instances number of cloned 142*5184Sek110237 * threadflows, and then calls threadflow_createthread() for 143*5184Sek110237 * each to create and start the actual operating system thread. 144*5184Sek110237 * Note that each of the newly defined threadflows will be linked 145*5184Sek110237 * into the procflows threadflow list, but at the head of the 146*5184Sek110237 * list, so they will not become part of the supplied set. After 147*5184Sek110237 * all the threads have been created, threadflow_init enters 148*5184Sek110237 * a join loop for all the threads in the newly defined 149*5184Sek110237 * threadflows. Once all the created threads have exited, 150*5184Sek110237 * threadflow_init will return 0. If errors are encountered, it 151*5184Sek110237 * will return a non zero value. 152*5184Sek110237 */ 153*5184Sek110237 int 154*5184Sek110237 threadflow_init(procflow_t *procflow) 155*5184Sek110237 { 156*5184Sek110237 threadflow_t *threadflow = procflow->pf_threads; 157*5184Sek110237 int ret = 0; 158*5184Sek110237 159*5184Sek110237 (void) ipc_mutex_lock(&filebench_shm->threadflow_lock); 160*5184Sek110237 #ifndef USE_PROCESS_MODEL 161*5184Sek110237 my_procflow = procflow; 162*5184Sek110237 163*5184Sek110237 (void) signal(SIGUSR1, threadflow_cancel); 164*5184Sek110237 #endif 165*5184Sek110237 while (threadflow) { 166*5184Sek110237 threadflow_t *newthread; 167*5184Sek110237 int i; 168*5184Sek110237 169*5184Sek110237 filebench_log(LOG_VERBOSE, 170*5184Sek110237 "Starting %lld %s threads", 171*5184Sek110237 *(threadflow->tf_instances), 172*5184Sek110237 threadflow->tf_name); 173*5184Sek110237 174*5184Sek110237 for (i = 1; i < *threadflow->tf_instances; i++) { 175*5184Sek110237 /* Create threads */ 176*5184Sek110237 newthread = 177*5184Sek110237 threadflow_define_common(procflow, 178*5184Sek110237 threadflow->tf_name, threadflow, i + 1); 179*5184Sek110237 if (newthread == NULL) 180*5184Sek110237 return (-1); 181*5184Sek110237 ret += threadflow_createthread(newthread); 182*5184Sek110237 } 183*5184Sek110237 184*5184Sek110237 newthread = threadflow_define_common(procflow, 185*5184Sek110237 threadflow->tf_name, 186*5184Sek110237 threadflow, 1); 187*5184Sek110237 188*5184Sek110237 if (newthread == NULL) 189*5184Sek110237 return (-1); 190*5184Sek110237 191*5184Sek110237 /* Create threads */ 192*5184Sek110237 ret += threadflow_createthread(newthread); 193*5184Sek110237 194*5184Sek110237 threadflow = threadflow->tf_next; 195*5184Sek110237 } 196*5184Sek110237 197*5184Sek110237 threadflow = procflow->pf_threads; 198*5184Sek110237 199*5184Sek110237 (void) ipc_mutex_unlock(&filebench_shm->threadflow_lock); 200*5184Sek110237 201*5184Sek110237 while (threadflow) { 202*5184Sek110237 void *status; 203*5184Sek110237 204*5184Sek110237 if (threadflow->tf_tid) 205*5184Sek110237 (void) pthread_join(threadflow->tf_tid, &status); 206*5184Sek110237 207*5184Sek110237 ret += *(int *)status; 208*5184Sek110237 threadflow = threadflow->tf_next; 209*5184Sek110237 } 210*5184Sek110237 211*5184Sek110237 procflow->pf_running = 0; 212*5184Sek110237 213*5184Sek110237 return (ret); 214*5184Sek110237 } 215*5184Sek110237 216*5184Sek110237 /* 217*5184Sek110237 * Tells the threadflow's thread to stop and optionally signals 218*5184Sek110237 * its associated process to end the thread. 219*5184Sek110237 */ 220*5184Sek110237 static void 221*5184Sek110237 threadflow_kill(threadflow_t *threadflow) 222*5184Sek110237 { 223*5184Sek110237 /* Tell thread to finish */ 224*5184Sek110237 threadflow->tf_abort = 1; 225*5184Sek110237 226*5184Sek110237 #ifdef USE_PROCESS_MODEL 227*5184Sek110237 #ifdef HAVE_SIGSEND 228*5184Sek110237 (void) sigsend(P_PID, threadflow->tf_process->pf_pid, SIGUSR1); 229*5184Sek110237 #else 230*5184Sek110237 (void) kill(threadflow->tf_process->pf_pid, SIGUSR1); 231*5184Sek110237 #endif 232*5184Sek110237 #else /* USE_PROCESS_MODEL */ 233*5184Sek110237 threadflow->tf_process->pf_running = 0; 234*5184Sek110237 #endif /* USE_PROCESS_MODEL */ 235*5184Sek110237 } 236*5184Sek110237 237*5184Sek110237 /* 238*5184Sek110237 * Deletes the specified threadflow from the specified threadflow 239*5184Sek110237 * list after first terminating the threadflow's thread, deleting 240*5184Sek110237 * the threadflow's flowops, and finally freeing the threadflow 241*5184Sek110237 * entity. It also subtracts the threadflow's shared memory 242*5184Sek110237 * requirements from the total amount required, shm_required. If 243*5184Sek110237 * the specified threadflow is found, returns 0, otherwise 244*5184Sek110237 * returns -1. 245*5184Sek110237 */ 246*5184Sek110237 static int 247*5184Sek110237 threadflow_delete(threadflow_t **threadlist, threadflow_t *threadflow) 248*5184Sek110237 { 249*5184Sek110237 threadflow_t *entry = *threadlist; 250*5184Sek110237 251*5184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Deleting thread: (%s-%d)", 252*5184Sek110237 threadflow->tf_name, 253*5184Sek110237 threadflow->tf_instance); 254*5184Sek110237 255*5184Sek110237 if (threadflow->tf_attrs & THREADFLOW_USEISM) { 256*5184Sek110237 filebench_shm->shm_required -= (*threadflow->tf_memsize); 257*5184Sek110237 } 258*5184Sek110237 259*5184Sek110237 if (threadflow == *threadlist) { 260*5184Sek110237 /* First on list */ 261*5184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Deleted thread: (%s-%d)", 262*5184Sek110237 threadflow->tf_name, 263*5184Sek110237 threadflow->tf_instance); 264*5184Sek110237 265*5184Sek110237 threadflow_kill(threadflow); 266*5184Sek110237 flowop_delete_all(&threadflow->tf_ops); 267*5184Sek110237 *threadlist = threadflow->tf_next; 268*5184Sek110237 ipc_free(FILEBENCH_THREADFLOW, (char *)threadflow); 269*5184Sek110237 return (0); 270*5184Sek110237 } 271*5184Sek110237 272*5184Sek110237 while (entry->tf_next) { 273*5184Sek110237 filebench_log(LOG_DEBUG_IMPL, 274*5184Sek110237 "Delete thread: (%s-%d) == (%s-%d)", 275*5184Sek110237 entry->tf_next->tf_name, 276*5184Sek110237 entry->tf_next->tf_instance, 277*5184Sek110237 threadflow->tf_name, 278*5184Sek110237 threadflow->tf_instance); 279*5184Sek110237 280*5184Sek110237 if (threadflow == entry->tf_next) { 281*5184Sek110237 /* Delete */ 282*5184Sek110237 filebench_log(LOG_DEBUG_IMPL, 283*5184Sek110237 "Deleted thread: (%s-%d)", 284*5184Sek110237 entry->tf_next->tf_name, 285*5184Sek110237 entry->tf_next->tf_instance); 286*5184Sek110237 threadflow_kill(entry->tf_next); 287*5184Sek110237 flowop_delete_all(&entry->tf_next->tf_ops); 288*5184Sek110237 ipc_free(FILEBENCH_THREADFLOW, (char *)threadflow); 289*5184Sek110237 entry->tf_next = entry->tf_next->tf_next; 290*5184Sek110237 return (0); 291*5184Sek110237 } 292*5184Sek110237 entry = entry->tf_next; 293*5184Sek110237 } 294*5184Sek110237 295*5184Sek110237 return (-1); 296*5184Sek110237 } 297*5184Sek110237 298*5184Sek110237 /* 299*5184Sek110237 * Given a pointer to the thread list of a procflow, cycles 300*5184Sek110237 * through all the threadflows on the list, deleting each one 301*5184Sek110237 * except the FLOW_MASTER. 302*5184Sek110237 */ 303*5184Sek110237 void 304*5184Sek110237 threadflow_delete_all(threadflow_t **threadlist) 305*5184Sek110237 { 306*5184Sek110237 threadflow_t *threadflow = *threadlist; 307*5184Sek110237 308*5184Sek110237 (void) ipc_mutex_lock(&filebench_shm->threadflow_lock); 309*5184Sek110237 310*5184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Deleting all threads"); 311*5184Sek110237 312*5184Sek110237 while (threadflow) { 313*5184Sek110237 if (threadflow->tf_instance && 314*5184Sek110237 (threadflow->tf_instance == FLOW_MASTER)) { 315*5184Sek110237 threadflow = threadflow->tf_next; 316*5184Sek110237 continue; 317*5184Sek110237 } 318*5184Sek110237 (void) threadflow_delete(threadlist, threadflow); 319*5184Sek110237 threadflow = threadflow->tf_next; 320*5184Sek110237 } 321*5184Sek110237 322*5184Sek110237 (void) ipc_mutex_unlock(&filebench_shm->threadflow_lock); 323*5184Sek110237 } 324*5184Sek110237 325*5184Sek110237 /* 326*5184Sek110237 * Waits till all threadflows are started, or a timeout occurs. 327*5184Sek110237 * Checks through the list of threadflows, waiting up to 10 328*5184Sek110237 * seconds for each one to set its tf_running flag to 1. If not 329*5184Sek110237 * set after 10 seconds, continues on to the next threadflow 330*5184Sek110237 * anyway. 331*5184Sek110237 */ 332*5184Sek110237 void 333*5184Sek110237 threadflow_allstarted(pid_t pid, threadflow_t *threadflow) 334*5184Sek110237 { 335*5184Sek110237 (void) ipc_mutex_lock(&filebench_shm->threadflow_lock); 336*5184Sek110237 337*5184Sek110237 while (threadflow) { 338*5184Sek110237 int waits; 339*5184Sek110237 340*5184Sek110237 if ((threadflow->tf_instance == 0) || 341*5184Sek110237 (threadflow->tf_instance == FLOW_MASTER)) { 342*5184Sek110237 threadflow = threadflow->tf_next; 343*5184Sek110237 continue; 344*5184Sek110237 } 345*5184Sek110237 346*5184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Checking pid %d thread %s-%d", 347*5184Sek110237 pid, 348*5184Sek110237 threadflow->tf_name, 349*5184Sek110237 threadflow->tf_instance); 350*5184Sek110237 351*5184Sek110237 waits = 10; 352*5184Sek110237 while (waits && threadflow->tf_running == 0) { 353*5184Sek110237 (void) ipc_mutex_unlock( 354*5184Sek110237 &filebench_shm->threadflow_lock); 355*5184Sek110237 if (waits < 3) 356*5184Sek110237 filebench_log(LOG_INFO, 357*5184Sek110237 "Waiting for pid %d thread %s-%d", 358*5184Sek110237 pid, 359*5184Sek110237 threadflow->tf_name, 360*5184Sek110237 threadflow->tf_instance); 361*5184Sek110237 362*5184Sek110237 (void) sleep(1); 363*5184Sek110237 (void) ipc_mutex_lock(&filebench_shm->threadflow_lock); 364*5184Sek110237 waits--; 365*5184Sek110237 } 366*5184Sek110237 367*5184Sek110237 threadflow = threadflow->tf_next; 368*5184Sek110237 } 369*5184Sek110237 370*5184Sek110237 (void) ipc_mutex_unlock(&filebench_shm->threadflow_lock); 371*5184Sek110237 } 372*5184Sek110237 373*5184Sek110237 /* 374*5184Sek110237 * Create an in-memory thread object linked to a parent procflow. 375*5184Sek110237 * A threadflow entity is allocated from shared memory and 376*5184Sek110237 * initialized from the "inherit" threadflow if supplied, 377*5184Sek110237 * otherwise to zeros. The threadflow is assigned a unique 378*5184Sek110237 * thread id, the supplied instance number, the supplied name 379*5184Sek110237 * and added to the procflow's pf_thread list. If no name is 380*5184Sek110237 * supplied or the threadflow can't be allocated, NULL is 381*5184Sek110237 * returned Otherwise a pointer to the newly allocated threadflow 382*5184Sek110237 * is returned. 383*5184Sek110237 * 384*5184Sek110237 * The filebench_shm->threadflow_lock must be held by the caller. 385*5184Sek110237 */ 386*5184Sek110237 static threadflow_t * 387*5184Sek110237 threadflow_define_common(procflow_t *procflow, char *name, 388*5184Sek110237 threadflow_t *inherit, int instance) 389*5184Sek110237 { 390*5184Sek110237 threadflow_t *threadflow; 391*5184Sek110237 threadflow_t **threadlistp = &procflow->pf_threads; 392*5184Sek110237 393*5184Sek110237 if (name == NULL) 394*5184Sek110237 return (NULL); 395*5184Sek110237 396*5184Sek110237 threadflow = (threadflow_t *)ipc_malloc(FILEBENCH_THREADFLOW); 397*5184Sek110237 398*5184Sek110237 if (threadflow == NULL) 399*5184Sek110237 return (NULL); 400*5184Sek110237 401*5184Sek110237 if (inherit) 402*5184Sek110237 (void) memcpy(threadflow, inherit, sizeof (threadflow_t)); 403*5184Sek110237 else 404*5184Sek110237 (void) memset(threadflow, 0, sizeof (threadflow_t)); 405*5184Sek110237 406*5184Sek110237 threadflow->tf_utid = ++filebench_shm->utid; 407*5184Sek110237 408*5184Sek110237 threadflow->tf_instance = instance; 409*5184Sek110237 (void) strcpy(threadflow->tf_name, name); 410*5184Sek110237 threadflow->tf_process = procflow; 411*5184Sek110237 412*5184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Defining thread %s-%d", 413*5184Sek110237 name, instance); 414*5184Sek110237 415*5184Sek110237 /* Add threadflow to list */ 416*5184Sek110237 if (*threadlistp == NULL) { 417*5184Sek110237 *threadlistp = threadflow; 418*5184Sek110237 threadflow->tf_next = NULL; 419*5184Sek110237 } else { 420*5184Sek110237 threadflow->tf_next = *threadlistp; 421*5184Sek110237 *threadlistp = threadflow; 422*5184Sek110237 } 423*5184Sek110237 424*5184Sek110237 return (threadflow); 425*5184Sek110237 } 426*5184Sek110237 427*5184Sek110237 /* 428*5184Sek110237 * Create an in memory FLOW_MASTER thread object as described 429*5184Sek110237 * by the syntax. Acquire the filebench_shm->threadflow_lock and 430*5184Sek110237 * call threadflow_define_common() to create a threadflow entity. 431*5184Sek110237 * Set the number of instances to create at runtime, 432*5184Sek110237 * tf_instances, to "instances". Return the threadflow pointer 433*5184Sek110237 * returned by the threadflow_define_common call. 434*5184Sek110237 */ 435*5184Sek110237 threadflow_t * 436*5184Sek110237 threadflow_define(procflow_t *procflow, char *name, 437*5184Sek110237 threadflow_t *inherit, var_integer_t instances) 438*5184Sek110237 { 439*5184Sek110237 threadflow_t *threadflow; 440*5184Sek110237 441*5184Sek110237 (void) ipc_mutex_lock(&filebench_shm->threadflow_lock); 442*5184Sek110237 443*5184Sek110237 if ((threadflow = threadflow_define_common(procflow, name, 444*5184Sek110237 inherit, FLOW_MASTER)) == NULL) 445*5184Sek110237 return (NULL); 446*5184Sek110237 447*5184Sek110237 threadflow->tf_instances = instances; 448*5184Sek110237 449*5184Sek110237 (void) ipc_mutex_unlock(&filebench_shm->threadflow_lock); 450*5184Sek110237 451*5184Sek110237 return (threadflow); 452*5184Sek110237 } 453*5184Sek110237 454*5184Sek110237 455*5184Sek110237 /* 456*5184Sek110237 * Searches the provided threadflow list for the named threadflow. 457*5184Sek110237 * A pointer to the threadflow is returned, or NULL if threadflow 458*5184Sek110237 * is not found. 459*5184Sek110237 */ 460*5184Sek110237 threadflow_t * 461*5184Sek110237 threadflow_find(threadflow_t *threadlist, char *name) 462*5184Sek110237 { 463*5184Sek110237 threadflow_t *threadflow = threadlist; 464*5184Sek110237 465*5184Sek110237 (void) ipc_mutex_lock(&filebench_shm->threadflow_lock); 466*5184Sek110237 467*5184Sek110237 while (threadflow) { 468*5184Sek110237 if (strcmp(name, threadflow->tf_name) == 0) { 469*5184Sek110237 470*5184Sek110237 (void) ipc_mutex_unlock( 471*5184Sek110237 &filebench_shm->threadflow_lock); 472*5184Sek110237 473*5184Sek110237 return (threadflow); 474*5184Sek110237 } 475*5184Sek110237 threadflow = threadflow->tf_next; 476*5184Sek110237 } 477*5184Sek110237 478*5184Sek110237 (void) ipc_mutex_unlock(&filebench_shm->threadflow_lock); 479*5184Sek110237 480*5184Sek110237 481*5184Sek110237 return (NULL); 482*5184Sek110237 } 483