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 #pragma ident "%Z%%M% %I% %E% SMI" 295184Sek110237 305184Sek110237 #include <signal.h> 315184Sek110237 #include <fcntl.h> 325184Sek110237 #include <sys/stat.h> 335184Sek110237 #include <sys/wait.h> 345184Sek110237 356613Sek110237 #include "filebench.h" 365184Sek110237 #include "procflow.h" 375184Sek110237 #include "flowop.h" 385184Sek110237 #include "ipc.h" 395184Sek110237 406084Saw148015 /* pid and procflow pointer for this process */ 416084Saw148015 pid_t my_pid; 426084Saw148015 procflow_t *my_procflow = NULL; 435184Sek110237 445184Sek110237 static procflow_t *procflow_define_common(procflow_t **list, char *name, 455184Sek110237 procflow_t *inherit, int instance); 465184Sek110237 475184Sek110237 #ifdef USE_PROCESS_MODEL 485184Sek110237 495184Sek110237 static enum create_n_wait { 505184Sek110237 CNW_DONE, 515184Sek110237 CNW_ERROR 525184Sek110237 } cnw_wait; 535184Sek110237 545184Sek110237 static pthread_cond_t procflow_procs_created; 555184Sek110237 565184Sek110237 #endif /* USE_PROCESS_MODEL */ 575184Sek110237 585184Sek110237 595184Sek110237 /* 605184Sek110237 * Procflows are filebench entities which manage processes. Each 615184Sek110237 * worker procflow spawns a separate filebench process, with attributes 625184Sek110237 * inherited from a FLOW_MASTER procflow created during f model language 635184Sek110237 * parsing. This section contains routines to define, create, control, 645184Sek110237 * and delete procflows. 655184Sek110237 * 665184Sek110237 * Each process defined in the f model creates a FLOW_MASTER 675184Sek110237 * procflow which encapsulates the defined attributes, and threads of 685184Sek110237 * the f process, including the number of instances to create. At 695184Sek110237 * runtime, a worker procflow instance with an associated filebench 705184Sek110237 * process is created, which runs until told to quite by the original 715184Sek110237 * filebench process or is specifically deleted. 725184Sek110237 */ 735184Sek110237 745184Sek110237 755184Sek110237 /* 765184Sek110237 * Prints a summary of the syntax for setting procflow parameters. 775184Sek110237 */ 785184Sek110237 void 795184Sek110237 procflow_usage(void) 805184Sek110237 { 815184Sek110237 (void) fprintf(stderr, 825184Sek110237 "define process name=<name>[,instances=<count>]\n"); 835184Sek110237 (void) fprintf(stderr, "{\n"); 845184Sek110237 (void) fprintf(stderr, " thread ...\n"); 855184Sek110237 (void) fprintf(stderr, " thread ...\n"); 865184Sek110237 (void) fprintf(stderr, " thread ...\n"); 875184Sek110237 (void) fprintf(stderr, "}\n"); 885184Sek110237 (void) fprintf(stderr, "\n"); 895184Sek110237 (void) fprintf(stderr, "\n"); 905184Sek110237 } 915184Sek110237 925184Sek110237 /* 935184Sek110237 * If filebench has been compiled to support multiple processes 945184Sek110237 * (USE_PROCESS_MODEL defined), this routine forks a child 955184Sek110237 * process and uses either system() or exec() to start up a new 965184Sek110237 * instance of filebench, passing it the procflow name, instance 975184Sek110237 * number and shared memory region address. 985184Sek110237 * If USE_PROCESS_MODEL is NOT defined, then the routine 995184Sek110237 * just creates a child thread which begins executing 1005184Sek110237 * threadflow_init() for the specified procflow. 1015184Sek110237 */ 1025184Sek110237 static int 1035184Sek110237 procflow_createproc(procflow_t *procflow) 1045184Sek110237 { 1055184Sek110237 char instance[128]; 1065184Sek110237 char shmaddr[128]; 1075184Sek110237 char procname[128]; 1085184Sek110237 pid_t pid; 1095184Sek110237 1105184Sek110237 #ifdef USE_PROCESS_MODEL 1115184Sek110237 1125184Sek110237 (void) snprintf(instance, sizeof (instance), "%d", 1135184Sek110237 procflow->pf_instance); 1145184Sek110237 (void) snprintf(procname, sizeof (procname), "%s", procflow->pf_name); 1155184Sek110237 #if defined(_LP64) || (__WORDSIZE == 64) 1165184Sek110237 (void) snprintf(shmaddr, sizeof (shmaddr), "%llx", filebench_shm); 1175184Sek110237 #else 1185184Sek110237 (void) snprintf(shmaddr, sizeof (shmaddr), "%x", filebench_shm); 1195184Sek110237 #endif 1205184Sek110237 filebench_log(LOG_DEBUG_IMPL, "creating process %s", 1215184Sek110237 procflow->pf_name); 1225184Sek110237 1235184Sek110237 procflow->pf_running = 0; 1245184Sek110237 1255184Sek110237 #ifdef HAVE_FORK1 1265184Sek110237 if ((pid = fork1()) < 0) { 1275184Sek110237 filebench_log(LOG_ERROR, 1285184Sek110237 "procflow_createproc fork failed: %s", 1295184Sek110237 strerror(errno)); 1305184Sek110237 return (-1); 1315184Sek110237 } 1325184Sek110237 #else 1335184Sek110237 if ((pid = fork()) < 0) { 1345184Sek110237 filebench_log(LOG_ERROR, 1355184Sek110237 "procflow_createproc fork failed: %s", 1365184Sek110237 strerror(errno)); 1375184Sek110237 return (-1); 1385184Sek110237 } 1395184Sek110237 #endif /* HAVE_FORK1 */ 1405184Sek110237 1416084Saw148015 /* if child, start up new copy of filebench */ 1425184Sek110237 if (pid == 0) { 1435184Sek110237 #ifdef USE_SYSTEM 1445184Sek110237 char syscmd[1024]; 1455184Sek110237 #endif 1465184Sek110237 1475184Sek110237 (void) sigignore(SIGINT); 1485184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, 1495184Sek110237 "Starting %s-%d", procflow->pf_name, 1505184Sek110237 procflow->pf_instance); 1515184Sek110237 /* Child */ 1525184Sek110237 1535184Sek110237 #ifdef USE_SYSTEM 1545184Sek110237 (void) snprintf(syscmd, sizeof (syscmd), "%s -a %s -i %s -s %s", 1555184Sek110237 execname, 1565184Sek110237 procname, 1575184Sek110237 instance, 1585184Sek110237 shmaddr); 1595184Sek110237 if (system(syscmd) < 0) { 1605184Sek110237 filebench_log(LOG_ERROR, 1615184Sek110237 "procflow exec proc failed: %s", 1625184Sek110237 strerror(errno)); 1635184Sek110237 filebench_shutdown(1); 1645184Sek110237 } 1655184Sek110237 1665184Sek110237 #else 1676613Sek110237 if (execlp(execname, procname, "-a", procname, "-i", 1685184Sek110237 instance, "-s", shmaddr, "-m", shmpath, NULL) < 0) { 1695184Sek110237 filebench_log(LOG_ERROR, 1705184Sek110237 "procflow exec proc failed: %s", 1715184Sek110237 strerror(errno)); 1725184Sek110237 filebench_shutdown(1); 1735184Sek110237 } 1745184Sek110237 #endif 1755184Sek110237 exit(1); 1765184Sek110237 } else { 1776084Saw148015 /* if parent, save pid and return */ 1785184Sek110237 procflow->pf_pid = pid; 1795184Sek110237 } 1805184Sek110237 #else 1815184Sek110237 procflow->pf_running = 1; 1825184Sek110237 if (pthread_create(&procflow->pf_tid, NULL, 1835184Sek110237 (void *(*)(void*))threadflow_init, procflow) != 0) { 1845184Sek110237 filebench_log(LOG_ERROR, "proc-thread create failed"); 1855184Sek110237 procflow->pf_running = 0; 1865184Sek110237 } 1875184Sek110237 #endif 1885184Sek110237 filebench_log(LOG_DEBUG_IMPL, "procflow_createproc created pid %d", 1895184Sek110237 pid); 1905184Sek110237 1915184Sek110237 return (0); 1925184Sek110237 } 1935184Sek110237 1945184Sek110237 /* 1955184Sek110237 * Find a procflow of name "name" and instance "instance" on the 1966391Saw148015 * master procflow list, filebench_shm->shm_proclist. Locks the list 1975184Sek110237 * and scans through it searching for a procflow with matching 1985184Sek110237 * name and instance number. If found returns a pointer to the 1995184Sek110237 * procflow, otherwise returns NULL. 2005184Sek110237 */ 2015184Sek110237 static procflow_t * 2025184Sek110237 procflow_find(char *name, int instance) 2035184Sek110237 { 2046391Saw148015 procflow_t *procflow = filebench_shm->shm_proclist; 2055184Sek110237 2065184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Find: (%s-%d) proclist = %zx", 2075184Sek110237 name, instance, procflow); 2085184Sek110237 2096391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 2105184Sek110237 2115184Sek110237 while (procflow) { 2125184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Find: (%s-%d) == (%s-%d)", 2135184Sek110237 name, instance, 2145184Sek110237 procflow->pf_name, 2155184Sek110237 procflow->pf_instance); 2165184Sek110237 if ((strcmp(name, procflow->pf_name) == 0) && 2175184Sek110237 (instance == procflow->pf_instance)) { 2185184Sek110237 2196391Saw148015 (void) ipc_mutex_unlock( 2206391Saw148015 &filebench_shm->shm_procflow_lock); 2215184Sek110237 2225184Sek110237 return (procflow); 2235184Sek110237 } 2245184Sek110237 procflow = procflow->pf_next; 2255184Sek110237 } 2265184Sek110237 2276391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); 2285184Sek110237 2295184Sek110237 return (NULL); 2305184Sek110237 } 2315184Sek110237 2325184Sek110237 static int 2335184Sek110237 procflow_create_all_procs(void) 2345184Sek110237 { 2356391Saw148015 procflow_t *procflow = filebench_shm->shm_proclist; 2365184Sek110237 int ret = 0; 2375184Sek110237 2385184Sek110237 while (procflow) { 2396212Saw148015 int i, instances; 2405184Sek110237 2416212Saw148015 instances = (int)avd_get_int(procflow->pf_instances); 2426212Saw148015 filebench_log(LOG_INFO, "Starting %d %s instances", 2436212Saw148015 instances, procflow->pf_name); 2445184Sek110237 2455184Sek110237 /* Create instances of procflow */ 2466212Saw148015 for (i = 0; (i < instances) && (ret == 0); i++) { 2475184Sek110237 procflow_t *newproc; 2485184Sek110237 2495184Sek110237 /* Create processes */ 2505184Sek110237 newproc = 2516391Saw148015 procflow_define_common(&filebench_shm->shm_proclist, 2525184Sek110237 procflow->pf_name, procflow, i + 1); 2535184Sek110237 if (newproc == NULL) 2545184Sek110237 ret = -1; 2555184Sek110237 else 2565184Sek110237 ret = procflow_createproc(newproc); 2575184Sek110237 } 2585184Sek110237 2595184Sek110237 if (ret != 0) 2605184Sek110237 break; 2615184Sek110237 2625184Sek110237 procflow = procflow->pf_next; 2635184Sek110237 } 2645184Sek110237 2655184Sek110237 return (ret); 2665184Sek110237 } 2675184Sek110237 2685184Sek110237 #ifdef USE_PROCESS_MODEL 2695184Sek110237 /* 2705184Sek110237 * Used to start up threads on a child process, when filebench is 2715184Sek110237 * compiled to support multiple processes. Uses the name string 2725184Sek110237 * and instance number passed to the child to find the previously 2735184Sek110237 * created procflow entity. Then uses nice() to reduce the 2745184Sek110237 * process' priority by at least 10. A call is then made to 2755184Sek110237 * threadflow_init() which creates and runs the process' threads 2765184Sek110237 * and flowops to completion. When threadflow_init() returns, 2775184Sek110237 * a call to exit() terminates the child process. 2785184Sek110237 */ 2795184Sek110237 int 2805184Sek110237 procflow_exec(char *name, int instance) 2815184Sek110237 { 2825184Sek110237 procflow_t *procflow; 2835184Sek110237 int proc_nice; 2845184Sek110237 #ifdef HAVE_SETRLIMIT 2855184Sek110237 struct rlimit rlp; 2865184Sek110237 #endif 2876084Saw148015 int ret; 2885184Sek110237 2895184Sek110237 filebench_log(LOG_DEBUG_IMPL, 2905184Sek110237 "procflow_execproc %s-%d", 2915184Sek110237 name, instance); 2925184Sek110237 2935184Sek110237 if ((procflow = procflow_find(name, instance)) == NULL) { 2945184Sek110237 filebench_log(LOG_ERROR, 2955184Sek110237 "procflow_exec could not find %s-%d", 2965184Sek110237 name, instance); 2975184Sek110237 return (-1); 2985184Sek110237 } 2996084Saw148015 3006084Saw148015 /* set the slave process' procflow pointer */ 3016084Saw148015 my_procflow = procflow; 3026084Saw148015 3036084Saw148015 /* set its pid from value stored by main() */ 3046084Saw148015 procflow->pf_pid = my_pid; 3055184Sek110237 3065184Sek110237 filebench_log(LOG_DEBUG_IMPL, 3076084Saw148015 "Started up %s pid %d", procflow->pf_name, my_pid); 3085184Sek110237 3095184Sek110237 filebench_log(LOG_DEBUG_IMPL, 3105184Sek110237 "nice = %llx", procflow->pf_nice); 3115184Sek110237 3126212Saw148015 proc_nice = avd_get_int(procflow->pf_nice); 3135184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Setting pri of %s-%d to %d", 3145184Sek110237 name, instance, nice(proc_nice + 10)); 3155184Sek110237 3165184Sek110237 procflow->pf_running = 1; 3175184Sek110237 3185184Sek110237 #ifdef HAVE_SETRLIMIT 3195184Sek110237 /* Get resource limits */ 3205184Sek110237 (void) getrlimit(RLIMIT_NOFILE, &rlp); 3215184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, "%d file descriptors", rlp.rlim_cur); 3225184Sek110237 #endif 3235184Sek110237 3246084Saw148015 if ((ret = threadflow_init(procflow)) != FILEBENCH_OK) { 3256084Saw148015 if (ret < 0) { 3266084Saw148015 filebench_log(LOG_ERROR, 3276084Saw148015 "Failed to start threads for %s pid %d", 3286084Saw148015 procflow->pf_name, my_pid); 3296084Saw148015 } 3306084Saw148015 } else { 3316084Saw148015 filebench_log(LOG_DEBUG_IMPL, 3326084Saw148015 "procflow_createproc exiting..."); 3335184Sek110237 } 3346084Saw148015 335*6701Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock); 336*6701Saw148015 filebench_shm->shm_procs_running --; 337*6701Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock); 3385184Sek110237 procflow->pf_running = 0; 3395184Sek110237 3406084Saw148015 return (ret); 3415184Sek110237 } 3425184Sek110237 3435184Sek110237 3445184Sek110237 /* 3455184Sek110237 * A special thread from which worker (child) processes are created, and 3465184Sek110237 * which then waits for worker processes to die. If they die unexpectedly, 3475184Sek110237 * that is not a simple exit(0), then report an error and terminate the 3485184Sek110237 * run. 3495184Sek110237 */ 3505184Sek110237 /* ARGSUSED */ 3515184Sek110237 static void * 3525184Sek110237 procflow_createnwait(void *nothing) 3535184Sek110237 { 3546391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 3555184Sek110237 3565184Sek110237 if (procflow_create_all_procs() == 0) 3575184Sek110237 cnw_wait = CNW_DONE; 3585184Sek110237 else 3595184Sek110237 cnw_wait = CNW_ERROR; 3605184Sek110237 3615184Sek110237 if (pthread_cond_signal(&procflow_procs_created) != 0) 3625184Sek110237 exit(1); 3635184Sek110237 3646391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); 3655184Sek110237 3665184Sek110237 /* CONSTCOND */ 3675184Sek110237 while (1) { 3685184Sek110237 siginfo_t status; 3695184Sek110237 3705184Sek110237 /* wait for any child process to exit */ 3715184Sek110237 if (waitid(P_ALL, 0, &status, WEXITED) != 0) 3725184Sek110237 pthread_exit(0); 3735184Sek110237 374*6701Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 3755184Sek110237 /* if normal shutdown in progress, just quit */ 3766391Saw148015 if (filebench_shm->shm_f_abort) 377*6701Saw148015 (void) ipc_mutex_unlock( 378*6701Saw148015 &filebench_shm->shm_procflow_lock); 3795184Sek110237 pthread_exit(0); 3805184Sek110237 381*6701Saw148015 /* if nothing running, exit */ 382*6701Saw148015 if (filebench_shm->shm_procs_running == 0) { 383*6701Saw148015 filebench_shm->shm_f_abort = FILEBENCH_ABORT_RSRC; 384*6701Saw148015 (void) ipc_mutex_unlock( 385*6701Saw148015 &filebench_shm->shm_procflow_lock); 386*6701Saw148015 pthread_exit(0); 387*6701Saw148015 } 388*6701Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); 389*6701Saw148015 3905184Sek110237 if (status.si_code == CLD_EXITED) { 3915184Sek110237 /* A process called exit(); check returned status */ 3925184Sek110237 if (status.si_status != 0) { 3935184Sek110237 filebench_log(LOG_ERROR, 3945184Sek110237 "Unexpected Process termination; exiting", 3955184Sek110237 status.si_status); 3965184Sek110237 filebench_shutdown(1); 3975184Sek110237 } 3985184Sek110237 } else { 3995184Sek110237 /* A process quit because of some fatal error */ 4005184Sek110237 filebench_log(LOG_ERROR, 4015184Sek110237 "Unexpected Process termination Code %d, Errno %d", 4025184Sek110237 status.si_code, status.si_errno); 4035184Sek110237 filebench_shutdown(1); 4045184Sek110237 } 4055184Sek110237 4065184Sek110237 } 4075184Sek110237 /* NOTREACHED */ 4085184Sek110237 return (NULL); 4095184Sek110237 } 4105184Sek110237 #endif /* USE_PROCESS_MODEL */ 4115184Sek110237 4125184Sek110237 /* 4135184Sek110237 * Iterates through proclist, the master list of procflows, 4145184Sek110237 * creating the number of instances of each procflow specified 4155184Sek110237 * by its pf_instance attribute. Returns 0 on success, or -1 4165184Sek110237 * times the number of procflow instances that were not 4175184Sek110237 * successfully created. 4185184Sek110237 */ 4195184Sek110237 int 4205184Sek110237 procflow_init(void) 4215184Sek110237 { 4226391Saw148015 procflow_t *procflow = filebench_shm->shm_proclist; 4235184Sek110237 pthread_t tid; 4245184Sek110237 int ret = 0; 4255184Sek110237 4265184Sek110237 filebench_log(LOG_DEBUG_IMPL, 4276286Saw148015 "procflow_init %s, %llu", 4286286Saw148015 procflow->pf_name, 4296286Saw148015 (u_longlong_t)avd_get_int(procflow->pf_instances)); 4305184Sek110237 4315184Sek110237 #ifdef USE_PROCESS_MODEL 4325184Sek110237 if ((ret = pthread_cond_init(&procflow_procs_created, NULL)) != 0) 4335184Sek110237 return (ret); 4345184Sek110237 4355184Sek110237 if ((pthread_create(&tid, NULL, procflow_createnwait, NULL)) != 0) 4365184Sek110237 return (ret); 4375184Sek110237 4386391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 4395184Sek110237 4405184Sek110237 if ((ret = pthread_cond_wait(&procflow_procs_created, 4416391Saw148015 &filebench_shm->shm_procflow_lock)) != 0) 4425184Sek110237 return (ret); 4435184Sek110237 4445184Sek110237 if (cnw_wait == CNW_ERROR) 4455184Sek110237 ret = -1; 4465184Sek110237 4475184Sek110237 #else /* USE_PROCESS_MODEL */ 4486391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 4495184Sek110237 4505184Sek110237 ret = procflow_create_all_procs(); 4515184Sek110237 #endif /* USE_PROCESS_MODEL */ 4525184Sek110237 4536391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); 4545184Sek110237 4555184Sek110237 return (ret); 4565184Sek110237 } 4575184Sek110237 4585184Sek110237 #ifdef USE_PROCESS_MODEL 4595184Sek110237 /* 4605184Sek110237 * Waits for child processes to finish and returns their exit 4615184Sek110237 * status. Used by procflow_delete() when the process model is 4625184Sek110237 * enabled to wait for a deleted process to exit. 4635184Sek110237 */ 4645184Sek110237 static void 4655184Sek110237 procflow_wait(pid_t pid) 4665184Sek110237 { 4675184Sek110237 pid_t wpid; 4685184Sek110237 int stat; 4695184Sek110237 4705184Sek110237 (void) waitpid(pid, &stat, 0); 4715184Sek110237 while ((wpid = waitpid(getpid() * -1, &stat, WNOHANG)) > 0) 4726286Saw148015 filebench_log(LOG_DEBUG_IMPL, "Waited for pid %d", (int)wpid); 4735184Sek110237 } 4745184Sek110237 #endif 4755184Sek110237 4765184Sek110237 /* 4775184Sek110237 * Deletes the designated procflow and all its threadflows except 4785184Sek110237 * for FLOW_MASTER ones. Waits 10 seconds if the procflow is still 4795184Sek110237 * running, then kills the associated process. Finally it frees the 4806391Saw148015 * procflow entity. filebench_shm->shm_procflow_lock must be held on entry. 4815184Sek110237 * 4825184Sek110237 * If the designated procflow is not found on the list it returns -1 and 4835184Sek110237 * the procflow is not deleted. Otherwise it returns 0. 4845184Sek110237 */ 4855184Sek110237 static int 4866084Saw148015 procflow_delete(procflow_t *procflow, int wait_cnt) 4875184Sek110237 { 4885184Sek110237 procflow_t *entry; 4895184Sek110237 4906084Saw148015 threadflow_delete_all(&procflow->pf_threads, wait_cnt); 4915184Sek110237 4925184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, 4935184Sek110237 "Deleted proc: (%s-%d) pid %d", 4945184Sek110237 procflow->pf_name, 4955184Sek110237 procflow->pf_instance, 4965184Sek110237 procflow->pf_pid); 4975184Sek110237 4985184Sek110237 while (procflow->pf_running == 1) { 4995184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, 5005184Sek110237 "Waiting for process %s-%d %d", 5015184Sek110237 procflow->pf_name, 5025184Sek110237 procflow->pf_instance, 5035184Sek110237 procflow->pf_pid); 5045184Sek110237 5056084Saw148015 if (wait_cnt) { 5066391Saw148015 (void) ipc_mutex_unlock( 5076391Saw148015 &filebench_shm->shm_procflow_lock); 5085184Sek110237 (void) sleep(1); 5096391Saw148015 (void) ipc_mutex_lock( 5106391Saw148015 &filebench_shm->shm_procflow_lock); 5116084Saw148015 wait_cnt--; 5125184Sek110237 continue; 5135184Sek110237 } 5145184Sek110237 #ifdef USE_PROCESS_MODEL 5155184Sek110237 (void) kill(procflow->pf_pid, SIGKILL); 5165184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, 517*6701Saw148015 "procflow_delete: Had to kill process %s-%d %d!", 5185184Sek110237 procflow->pf_name, 5195184Sek110237 procflow->pf_instance, 5205184Sek110237 procflow->pf_pid); 5215184Sek110237 procflow->pf_running = 0; 5225184Sek110237 #endif 5235184Sek110237 } 5245184Sek110237 5255184Sek110237 #ifdef USE_PROCESS_MODEL 5265184Sek110237 procflow_wait(procflow->pf_pid); 5275184Sek110237 #endif 5285184Sek110237 /* remove entry from proclist */ 5296391Saw148015 entry = filebench_shm->shm_proclist; 5305184Sek110237 5315184Sek110237 /* unlink procflow entity from proclist */ 5325184Sek110237 if (entry == procflow) { 5335184Sek110237 /* at head of list */ 5346391Saw148015 filebench_shm->shm_proclist = procflow->pf_next; 5355184Sek110237 } else { 5365184Sek110237 /* search list for procflow */ 5375184Sek110237 while (entry && entry->pf_next != procflow) 5385184Sek110237 entry = entry->pf_next; 5395184Sek110237 5405184Sek110237 /* if entity found, unlink it */ 5415184Sek110237 if (entry == NULL) 5425184Sek110237 return (-1); 5435184Sek110237 else 5445184Sek110237 entry->pf_next = procflow->pf_next; 5455184Sek110237 } 5465184Sek110237 5475184Sek110237 /* free up the procflow entity */ 5485184Sek110237 ipc_free(FILEBENCH_PROCFLOW, (char *)procflow); 5495184Sek110237 return (0); 5505184Sek110237 } 5515184Sek110237 5525184Sek110237 5535184Sek110237 /* 5545184Sek110237 * Waits till all threadflows are started, or a timeout occurs. 5555184Sek110237 * Checks through the list of procflows, waiting up to 30 5565184Sek110237 * seconds for each one to set its pf_running flag to 1. If not 5575184Sek110237 * set after 30 seconds, continues on to the next procflow 5585184Sek110237 * anyway after logging the fact. Once pf_running is set 5595184Sek110237 * to 1 for a given procflow or the timeout is reached, 5605184Sek110237 * threadflow_allstarted() is called to start the threads. 5616391Saw148015 * Returns 0 (OK), unless filebench_shm->shm_f_abort is signaled, 5625184Sek110237 * in which case it returns -1. 5635184Sek110237 */ 5645184Sek110237 int 5655184Sek110237 procflow_allstarted() 5665184Sek110237 { 5676391Saw148015 procflow_t *procflow = filebench_shm->shm_proclist; 5686084Saw148015 int running_procs = 0; 5695184Sek110237 int ret = 0; 5705184Sek110237 5716391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 5725184Sek110237 5735184Sek110237 (void) sleep(1); 5745184Sek110237 5755184Sek110237 while (procflow) { 5765184Sek110237 int waits; 5775184Sek110237 5785184Sek110237 if (procflow->pf_instance && 5795184Sek110237 (procflow->pf_instance == FLOW_MASTER)) { 5805184Sek110237 procflow = procflow->pf_next; 5815184Sek110237 continue; 5825184Sek110237 } 5835184Sek110237 5845184Sek110237 waits = 10; 5855184Sek110237 while (waits && procflow->pf_running == 0) { 5866391Saw148015 (void) ipc_mutex_unlock( 5876391Saw148015 &filebench_shm->shm_procflow_lock); 5886391Saw148015 if (filebench_shm->shm_f_abort == 1) 5895184Sek110237 return (-1); 5905184Sek110237 5915184Sek110237 if (waits < 3) 5925184Sek110237 filebench_log(LOG_INFO, 5935184Sek110237 "Waiting for process %s-%d %d", 5945184Sek110237 procflow->pf_name, 5955184Sek110237 procflow->pf_instance, 5965184Sek110237 procflow->pf_pid); 5975184Sek110237 5985184Sek110237 (void) sleep(3); 5995184Sek110237 waits--; 6006391Saw148015 (void) ipc_mutex_lock( 6016391Saw148015 &filebench_shm->shm_procflow_lock); 6025184Sek110237 } 6035184Sek110237 6045184Sek110237 if (waits == 0) 6056084Saw148015 filebench_log(LOG_INFO, 6066084Saw148015 "Failed to start process %s-%d", 6075184Sek110237 procflow->pf_name, 6085184Sek110237 procflow->pf_instance); 6095184Sek110237 6106084Saw148015 running_procs++; 6115184Sek110237 threadflow_allstarted(procflow->pf_pid, procflow->pf_threads); 6125184Sek110237 6135184Sek110237 procflow = procflow->pf_next; 6145184Sek110237 } 615*6701Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock); 616*6701Saw148015 filebench_shm->shm_procs_running = running_procs; 617*6701Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock); 6185184Sek110237 6196391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); 6205184Sek110237 6215184Sek110237 6225184Sek110237 return (ret); 6235184Sek110237 } 6245184Sek110237 6255184Sek110237 6265184Sek110237 /* 6276084Saw148015 * Sets the f_abort flag and clears the running count to stop 6285184Sek110237 * all the flowop execution threads from running. Iterates 6295184Sek110237 * through the procflow list and deletes all procflows except 6305184Sek110237 * for the FLOW_MASTER procflow. Resets the f_abort flag when 6315184Sek110237 * finished. 632*6701Saw148015 * 6335184Sek110237 */ 6345184Sek110237 void 6355184Sek110237 procflow_shutdown(void) 6365184Sek110237 { 6376391Saw148015 procflow_t *procflow = filebench_shm->shm_proclist; 6386084Saw148015 int wait_cnt; 6395184Sek110237 640*6701Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock); 641*6701Saw148015 if (filebench_shm->shm_procs_running == 0) { 642*6701Saw148015 /* No processes running, so no need to do anything */ 643*6701Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock); 644*6701Saw148015 return; 645*6701Saw148015 } 646*6701Saw148015 filebench_shm->shm_procs_running = 0; 647*6701Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock); 648*6701Saw148015 6496391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 6506391Saw148015 filebench_shm->shm_f_abort = 1; 6516084Saw148015 wait_cnt = SHUTDOWN_WAIT_SECONDS; 6525184Sek110237 6535184Sek110237 while (procflow) { 6545184Sek110237 if (procflow->pf_instance && 6555184Sek110237 (procflow->pf_instance == FLOW_MASTER)) { 6565184Sek110237 procflow = procflow->pf_next; 6575184Sek110237 continue; 6585184Sek110237 } 6595184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Deleting process %s-%d %d", 6605184Sek110237 procflow->pf_name, 6615184Sek110237 procflow->pf_instance, 6625184Sek110237 procflow->pf_pid); 6636084Saw148015 (void) procflow_delete(procflow, wait_cnt); 6645184Sek110237 procflow = procflow->pf_next; 6656084Saw148015 /* grow more impatient */ 6666084Saw148015 if (wait_cnt) 6676084Saw148015 wait_cnt--; 6685184Sek110237 } 6695184Sek110237 6706391Saw148015 filebench_shm->shm_f_abort = 0; 6715184Sek110237 6726391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); 6735184Sek110237 } 6745184Sek110237 6755184Sek110237 6765184Sek110237 /* 6775184Sek110237 * Create an in-memory process object. Allocates a procflow 6785184Sek110237 * entity, initialized from the "inherit" procflow if supplied. 6795184Sek110237 * The name and instance number are set from the supplied name 6805184Sek110237 * and instance number and the procflow is added to the head of 6815184Sek110237 * the master procflow list. Returns pointer to the allocated 6825184Sek110237 * procflow, or NULL if a name isn't supplied or the procflow 6835184Sek110237 * entity cannot be allocated. 6845184Sek110237 * 6856391Saw148015 * The calling routine must hold the filebench_shm->shm_procflow_lock. 6865184Sek110237 */ 6875184Sek110237 static procflow_t * 6885184Sek110237 procflow_define_common(procflow_t **list, char *name, 6895184Sek110237 procflow_t *inherit, int instance) 6905184Sek110237 { 6915184Sek110237 procflow_t *procflow; 6925184Sek110237 6935184Sek110237 if (name == NULL) 6945184Sek110237 return (NULL); 6955184Sek110237 6965184Sek110237 procflow = (procflow_t *)ipc_malloc(FILEBENCH_PROCFLOW); 6975184Sek110237 6985184Sek110237 if (procflow == NULL) 6995184Sek110237 return (NULL); 7005184Sek110237 7015184Sek110237 if (inherit) 7025184Sek110237 (void) memcpy(procflow, inherit, sizeof (procflow_t)); 7035184Sek110237 else 7045184Sek110237 (void) memset(procflow, 0, sizeof (procflow_t)); 7055184Sek110237 7065184Sek110237 procflow->pf_instance = instance; 7075184Sek110237 (void) strcpy(procflow->pf_name, name); 7085184Sek110237 7095184Sek110237 filebench_log(LOG_DEBUG_IMPL, "defining process %s-%d", name, instance); 7105184Sek110237 7115184Sek110237 filebench_log(LOG_DEBUG_IMPL, "process %s-%d proclist %zx", 7126391Saw148015 name, instance, filebench_shm->shm_proclist); 7135184Sek110237 /* Add procflow to list, lock is being held already */ 7145184Sek110237 if (*list == NULL) { 7155184Sek110237 *list = procflow; 7165184Sek110237 procflow->pf_next = NULL; 7175184Sek110237 } else { 7185184Sek110237 procflow->pf_next = *list; 7195184Sek110237 *list = procflow; 7205184Sek110237 } 7215184Sek110237 filebench_log(LOG_DEBUG_IMPL, "process %s-%d proclist %zx", 7226391Saw148015 name, instance, filebench_shm->shm_proclist); 7235184Sek110237 7245184Sek110237 return (procflow); 7255184Sek110237 } 7265184Sek110237 7275184Sek110237 /* 7285184Sek110237 * Create an in-memory process object as described by the syntax. 7296391Saw148015 * Acquires the filebench_shm->shm_procflow_lock and calls 7305184Sek110237 * procflow_define_common() to create and initialize a 7315184Sek110237 * FLOW_MASTER procflow entity from the optional "inherit" 7325184Sek110237 * procflow with the given name and configured for "instances" 7335184Sek110237 * number of worker procflows. Currently only called from 7345184Sek110237 * parser_proc_define(). 7355184Sek110237 */ 7365184Sek110237 procflow_t * 7376212Saw148015 procflow_define(char *name, procflow_t *inherit, avd_t instances) 7385184Sek110237 { 7395184Sek110237 procflow_t *procflow; 7405184Sek110237 7416391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 7425184Sek110237 7436391Saw148015 procflow = procflow_define_common(&filebench_shm->shm_proclist, 7445184Sek110237 name, inherit, FLOW_MASTER); 7455184Sek110237 procflow->pf_instances = instances; 7465184Sek110237 7476391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); 7485184Sek110237 7495184Sek110237 return (procflow); 7505184Sek110237 } 751