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 /* 228615SAndrew.W.Wilson@sun.com * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235184Sek110237 * Use is subject to license terms. 246613Sek110237 * 256613Sek110237 * Portions Copyright 2008 Denis Cheng 265184Sek110237 */ 275184Sek110237 285184Sek110237 #include <signal.h> 295184Sek110237 #include <fcntl.h> 305184Sek110237 #include <sys/stat.h> 315184Sek110237 #include <sys/wait.h> 325184Sek110237 336613Sek110237 #include "filebench.h" 345184Sek110237 #include "procflow.h" 355184Sek110237 #include "flowop.h" 365184Sek110237 #include "ipc.h" 375184Sek110237 386084Saw148015 /* pid and procflow pointer for this process */ 396084Saw148015 pid_t my_pid; 406084Saw148015 procflow_t *my_procflow = NULL; 415184Sek110237 425184Sek110237 static procflow_t *procflow_define_common(procflow_t **list, char *name, 435184Sek110237 procflow_t *inherit, int instance); 448762SAndrew.W.Wilson@sun.com static void procflow_sleep(procflow_t *procflow, int wait_cnt); 455184Sek110237 465184Sek110237 #ifdef USE_PROCESS_MODEL 475184Sek110237 485184Sek110237 static enum create_n_wait { 495184Sek110237 CNW_DONE, 505184Sek110237 CNW_ERROR 515184Sek110237 } cnw_wait; 525184Sek110237 535184Sek110237 #endif /* USE_PROCESS_MODEL */ 545184Sek110237 555184Sek110237 565184Sek110237 /* 575184Sek110237 * Procflows are filebench entities which manage processes. Each 585184Sek110237 * worker procflow spawns a separate filebench process, with attributes 595184Sek110237 * inherited from a FLOW_MASTER procflow created during f model language 605184Sek110237 * parsing. This section contains routines to define, create, control, 615184Sek110237 * and delete procflows. 625184Sek110237 * 635184Sek110237 * Each process defined in the f model creates a FLOW_MASTER 645184Sek110237 * procflow which encapsulates the defined attributes, and threads of 655184Sek110237 * the f process, including the number of instances to create. At 665184Sek110237 * runtime, a worker procflow instance with an associated filebench 675184Sek110237 * process is created, which runs until told to quite by the original 685184Sek110237 * filebench process or is specifically deleted. 695184Sek110237 */ 705184Sek110237 715184Sek110237 725184Sek110237 /* 735184Sek110237 * Prints a summary of the syntax for setting procflow parameters. 745184Sek110237 */ 755184Sek110237 void 765184Sek110237 procflow_usage(void) 775184Sek110237 { 785184Sek110237 (void) fprintf(stderr, 795184Sek110237 "define process name=<name>[,instances=<count>]\n"); 805184Sek110237 (void) fprintf(stderr, "{\n"); 815184Sek110237 (void) fprintf(stderr, " thread ...\n"); 825184Sek110237 (void) fprintf(stderr, " thread ...\n"); 835184Sek110237 (void) fprintf(stderr, " thread ...\n"); 845184Sek110237 (void) fprintf(stderr, "}\n"); 855184Sek110237 (void) fprintf(stderr, "\n"); 865184Sek110237 (void) fprintf(stderr, "\n"); 875184Sek110237 } 885184Sek110237 895184Sek110237 /* 905184Sek110237 * If filebench has been compiled to support multiple processes 915184Sek110237 * (USE_PROCESS_MODEL defined), this routine forks a child 925184Sek110237 * process and uses either system() or exec() to start up a new 935184Sek110237 * instance of filebench, passing it the procflow name, instance 945184Sek110237 * number and shared memory region address. 955184Sek110237 * If USE_PROCESS_MODEL is NOT defined, then the routine 965184Sek110237 * just creates a child thread which begins executing 975184Sek110237 * threadflow_init() for the specified procflow. 985184Sek110237 */ 995184Sek110237 static int 1005184Sek110237 procflow_createproc(procflow_t *procflow) 1015184Sek110237 { 1025184Sek110237 char instance[128]; 1035184Sek110237 char shmaddr[128]; 1045184Sek110237 char procname[128]; 1055184Sek110237 pid_t pid; 1065184Sek110237 1075184Sek110237 #ifdef USE_PROCESS_MODEL 1085184Sek110237 1095184Sek110237 (void) snprintf(instance, sizeof (instance), "%d", 1105184Sek110237 procflow->pf_instance); 1115184Sek110237 (void) snprintf(procname, sizeof (procname), "%s", procflow->pf_name); 1125184Sek110237 #if defined(_LP64) || (__WORDSIZE == 64) 1135184Sek110237 (void) snprintf(shmaddr, sizeof (shmaddr), "%llx", filebench_shm); 1145184Sek110237 #else 1155184Sek110237 (void) snprintf(shmaddr, sizeof (shmaddr), "%x", filebench_shm); 1165184Sek110237 #endif 1175184Sek110237 filebench_log(LOG_DEBUG_IMPL, "creating process %s", 1185184Sek110237 procflow->pf_name); 1195184Sek110237 1205184Sek110237 procflow->pf_running = 0; 1215184Sek110237 1225184Sek110237 #ifdef HAVE_FORK1 1235184Sek110237 if ((pid = fork1()) < 0) { 1245184Sek110237 filebench_log(LOG_ERROR, 1255184Sek110237 "procflow_createproc fork failed: %s", 1265184Sek110237 strerror(errno)); 1275184Sek110237 return (-1); 1285184Sek110237 } 1295184Sek110237 #else 1305184Sek110237 if ((pid = fork()) < 0) { 1315184Sek110237 filebench_log(LOG_ERROR, 1325184Sek110237 "procflow_createproc fork failed: %s", 1335184Sek110237 strerror(errno)); 1345184Sek110237 return (-1); 1355184Sek110237 } 1365184Sek110237 #endif /* HAVE_FORK1 */ 1375184Sek110237 1386084Saw148015 /* if child, start up new copy of filebench */ 1395184Sek110237 if (pid == 0) { 1405184Sek110237 #ifdef USE_SYSTEM 1415184Sek110237 char syscmd[1024]; 1425184Sek110237 #endif 1435184Sek110237 1445184Sek110237 (void) sigignore(SIGINT); 1455184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, 1465184Sek110237 "Starting %s-%d", procflow->pf_name, 1475184Sek110237 procflow->pf_instance); 1485184Sek110237 /* Child */ 1495184Sek110237 1505184Sek110237 #ifdef USE_SYSTEM 1515184Sek110237 (void) snprintf(syscmd, sizeof (syscmd), "%s -a %s -i %s -s %s", 1525184Sek110237 execname, 1535184Sek110237 procname, 1545184Sek110237 instance, 1555184Sek110237 shmaddr); 1565184Sek110237 if (system(syscmd) < 0) { 1575184Sek110237 filebench_log(LOG_ERROR, 1585184Sek110237 "procflow exec proc failed: %s", 1595184Sek110237 strerror(errno)); 1605184Sek110237 filebench_shutdown(1); 1615184Sek110237 } 1625184Sek110237 1635184Sek110237 #else 1646613Sek110237 if (execlp(execname, procname, "-a", procname, "-i", 1655184Sek110237 instance, "-s", shmaddr, "-m", shmpath, NULL) < 0) { 1665184Sek110237 filebench_log(LOG_ERROR, 1675184Sek110237 "procflow exec proc failed: %s", 1685184Sek110237 strerror(errno)); 1695184Sek110237 filebench_shutdown(1); 1705184Sek110237 } 1715184Sek110237 #endif 1725184Sek110237 exit(1); 1735184Sek110237 } else { 1746084Saw148015 /* if parent, save pid and return */ 1755184Sek110237 procflow->pf_pid = pid; 1765184Sek110237 } 1775184Sek110237 #else 1785184Sek110237 procflow->pf_running = 1; 1795184Sek110237 if (pthread_create(&procflow->pf_tid, NULL, 1805184Sek110237 (void *(*)(void*))threadflow_init, procflow) != 0) { 1815184Sek110237 filebench_log(LOG_ERROR, "proc-thread create failed"); 1825184Sek110237 procflow->pf_running = 0; 1835184Sek110237 } 1845184Sek110237 #endif 1855184Sek110237 filebench_log(LOG_DEBUG_IMPL, "procflow_createproc created pid %d", 1865184Sek110237 pid); 1875184Sek110237 1885184Sek110237 return (0); 1895184Sek110237 } 1905184Sek110237 1915184Sek110237 /* 1925184Sek110237 * Find a procflow of name "name" and instance "instance" on the 1936391Saw148015 * master procflow list, filebench_shm->shm_proclist. Locks the list 1945184Sek110237 * and scans through it searching for a procflow with matching 1955184Sek110237 * name and instance number. If found returns a pointer to the 1965184Sek110237 * procflow, otherwise returns NULL. 1975184Sek110237 */ 1985184Sek110237 static procflow_t * 1995184Sek110237 procflow_find(char *name, int instance) 2005184Sek110237 { 2016391Saw148015 procflow_t *procflow = filebench_shm->shm_proclist; 2025184Sek110237 2035184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Find: (%s-%d) proclist = %zx", 2045184Sek110237 name, instance, procflow); 2055184Sek110237 2066391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 2075184Sek110237 2085184Sek110237 while (procflow) { 2095184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Find: (%s-%d) == (%s-%d)", 2105184Sek110237 name, instance, 2115184Sek110237 procflow->pf_name, 2125184Sek110237 procflow->pf_instance); 2135184Sek110237 if ((strcmp(name, procflow->pf_name) == 0) && 2145184Sek110237 (instance == procflow->pf_instance)) { 2155184Sek110237 2166391Saw148015 (void) ipc_mutex_unlock( 2176391Saw148015 &filebench_shm->shm_procflow_lock); 2185184Sek110237 2195184Sek110237 return (procflow); 2205184Sek110237 } 2215184Sek110237 procflow = procflow->pf_next; 2225184Sek110237 } 2235184Sek110237 2246391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); 2255184Sek110237 2265184Sek110237 return (NULL); 2275184Sek110237 } 2285184Sek110237 2295184Sek110237 static int 2305184Sek110237 procflow_create_all_procs(void) 2315184Sek110237 { 2326391Saw148015 procflow_t *procflow = filebench_shm->shm_proclist; 2335184Sek110237 int ret = 0; 2345184Sek110237 2355184Sek110237 while (procflow) { 2366212Saw148015 int i, instances; 2375184Sek110237 2386212Saw148015 instances = (int)avd_get_int(procflow->pf_instances); 2396212Saw148015 filebench_log(LOG_INFO, "Starting %d %s instances", 2406212Saw148015 instances, procflow->pf_name); 2415184Sek110237 2425184Sek110237 /* Create instances of procflow */ 2436212Saw148015 for (i = 0; (i < instances) && (ret == 0); i++) { 2445184Sek110237 procflow_t *newproc; 2455184Sek110237 2465184Sek110237 /* Create processes */ 2475184Sek110237 newproc = 2486391Saw148015 procflow_define_common(&filebench_shm->shm_proclist, 2495184Sek110237 procflow->pf_name, procflow, i + 1); 2505184Sek110237 if (newproc == NULL) 2515184Sek110237 ret = -1; 2525184Sek110237 else 2535184Sek110237 ret = procflow_createproc(newproc); 2545184Sek110237 } 2555184Sek110237 2565184Sek110237 if (ret != 0) 2575184Sek110237 break; 2585184Sek110237 2595184Sek110237 procflow = procflow->pf_next; 2605184Sek110237 } 2615184Sek110237 2625184Sek110237 return (ret); 2635184Sek110237 } 2645184Sek110237 2655184Sek110237 #ifdef USE_PROCESS_MODEL 2665184Sek110237 /* 2675184Sek110237 * Used to start up threads on a child process, when filebench is 2685184Sek110237 * compiled to support multiple processes. Uses the name string 2695184Sek110237 * and instance number passed to the child to find the previously 2705184Sek110237 * created procflow entity. Then uses nice() to reduce the 2715184Sek110237 * process' priority by at least 10. A call is then made to 2725184Sek110237 * threadflow_init() which creates and runs the process' threads 2735184Sek110237 * and flowops to completion. When threadflow_init() returns, 2745184Sek110237 * a call to exit() terminates the child process. 2755184Sek110237 */ 2765184Sek110237 int 2775184Sek110237 procflow_exec(char *name, int instance) 2785184Sek110237 { 2795184Sek110237 procflow_t *procflow; 2805184Sek110237 int proc_nice; 2815184Sek110237 #ifdef HAVE_SETRLIMIT 2825184Sek110237 struct rlimit rlp; 2835184Sek110237 #endif 2846084Saw148015 int ret; 2855184Sek110237 2865184Sek110237 filebench_log(LOG_DEBUG_IMPL, 2875184Sek110237 "procflow_execproc %s-%d", 2885184Sek110237 name, instance); 2895184Sek110237 2905184Sek110237 if ((procflow = procflow_find(name, instance)) == NULL) { 2915184Sek110237 filebench_log(LOG_ERROR, 2925184Sek110237 "procflow_exec could not find %s-%d", 2935184Sek110237 name, instance); 2945184Sek110237 return (-1); 2955184Sek110237 } 2966084Saw148015 2976084Saw148015 /* set the slave process' procflow pointer */ 2986084Saw148015 my_procflow = procflow; 2996084Saw148015 3006084Saw148015 /* set its pid from value stored by main() */ 3016084Saw148015 procflow->pf_pid = my_pid; 3025184Sek110237 3035184Sek110237 filebench_log(LOG_DEBUG_IMPL, 3046084Saw148015 "Started up %s pid %d", procflow->pf_name, my_pid); 3055184Sek110237 3065184Sek110237 filebench_log(LOG_DEBUG_IMPL, 3075184Sek110237 "nice = %llx", procflow->pf_nice); 3085184Sek110237 3096212Saw148015 proc_nice = avd_get_int(procflow->pf_nice); 3105184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Setting pri of %s-%d to %d", 3115184Sek110237 name, instance, nice(proc_nice + 10)); 3125184Sek110237 3135184Sek110237 procflow->pf_running = 1; 3145184Sek110237 3155184Sek110237 #ifdef HAVE_SETRLIMIT 3165184Sek110237 /* Get resource limits */ 3175184Sek110237 (void) getrlimit(RLIMIT_NOFILE, &rlp); 3185184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, "%d file descriptors", rlp.rlim_cur); 3195184Sek110237 #endif 3205184Sek110237 3216084Saw148015 if ((ret = threadflow_init(procflow)) != FILEBENCH_OK) { 3226084Saw148015 if (ret < 0) { 3236084Saw148015 filebench_log(LOG_ERROR, 3246084Saw148015 "Failed to start threads for %s pid %d", 3256084Saw148015 procflow->pf_name, my_pid); 3266084Saw148015 } 3276084Saw148015 } else { 3286084Saw148015 filebench_log(LOG_DEBUG_IMPL, 3296084Saw148015 "procflow_createproc exiting..."); 3305184Sek110237 } 3316084Saw148015 3326701Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock); 3336701Saw148015 filebench_shm->shm_procs_running --; 3346701Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock); 3355184Sek110237 procflow->pf_running = 0; 3365184Sek110237 3376084Saw148015 return (ret); 3385184Sek110237 } 3395184Sek110237 3405184Sek110237 3415184Sek110237 /* 3425184Sek110237 * A special thread from which worker (child) processes are created, and 3435184Sek110237 * which then waits for worker processes to die. If they die unexpectedly, 3445184Sek110237 * that is not a simple exit(0), then report an error and terminate the 3455184Sek110237 * run. 3465184Sek110237 */ 3475184Sek110237 /* ARGSUSED */ 3485184Sek110237 static void * 3495184Sek110237 procflow_createnwait(void *nothing) 3505184Sek110237 { 3516391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 3525184Sek110237 3535184Sek110237 if (procflow_create_all_procs() == 0) 3545184Sek110237 cnw_wait = CNW_DONE; 3555184Sek110237 else 3565184Sek110237 cnw_wait = CNW_ERROR; 3575184Sek110237 3587556SAndrew.W.Wilson@sun.com if (pthread_cond_signal(&filebench_shm->shm_procflow_procs_cv) != 0) 3595184Sek110237 exit(1); 3605184Sek110237 3616391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); 3625184Sek110237 3635184Sek110237 /* CONSTCOND */ 3645184Sek110237 while (1) { 3655184Sek110237 siginfo_t status; 3665184Sek110237 3675184Sek110237 /* wait for any child process to exit */ 3685184Sek110237 if (waitid(P_ALL, 0, &status, WEXITED) != 0) 3695184Sek110237 pthread_exit(0); 3705184Sek110237 3716701Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 3725184Sek110237 /* if normal shutdown in progress, just quit */ 373*9326SAndrew.W.Wilson@sun.com if (filebench_shm->shm_f_abort) { 3746701Saw148015 (void) ipc_mutex_unlock( 3756701Saw148015 &filebench_shm->shm_procflow_lock); 3765184Sek110237 pthread_exit(0); 377*9326SAndrew.W.Wilson@sun.com } 3785184Sek110237 3796701Saw148015 /* if nothing running, exit */ 3806701Saw148015 if (filebench_shm->shm_procs_running == 0) { 3816701Saw148015 filebench_shm->shm_f_abort = FILEBENCH_ABORT_RSRC; 3826701Saw148015 (void) ipc_mutex_unlock( 3836701Saw148015 &filebench_shm->shm_procflow_lock); 3846701Saw148015 pthread_exit(0); 3856701Saw148015 } 3866701Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); 3876701Saw148015 3885184Sek110237 if (status.si_code == CLD_EXITED) { 3895184Sek110237 /* A process called exit(); check returned status */ 3905184Sek110237 if (status.si_status != 0) { 3915184Sek110237 filebench_log(LOG_ERROR, 3925184Sek110237 "Unexpected Process termination; exiting", 3935184Sek110237 status.si_status); 3945184Sek110237 filebench_shutdown(1); 3955184Sek110237 } 3965184Sek110237 } else { 3975184Sek110237 /* A process quit because of some fatal error */ 3985184Sek110237 filebench_log(LOG_ERROR, 3995184Sek110237 "Unexpected Process termination Code %d, Errno %d", 4005184Sek110237 status.si_code, status.si_errno); 4015184Sek110237 filebench_shutdown(1); 4025184Sek110237 } 4035184Sek110237 4045184Sek110237 } 4055184Sek110237 /* NOTREACHED */ 4065184Sek110237 return (NULL); 4075184Sek110237 } 4088762SAndrew.W.Wilson@sun.com 4098762SAndrew.W.Wilson@sun.com /* 4108762SAndrew.W.Wilson@sun.com * Cancel all threads within a processes, as well as the process itself. 4118762SAndrew.W.Wilson@sun.com * Called by ^c or by sig_kill 4128762SAndrew.W.Wilson@sun.com */ 4138762SAndrew.W.Wilson@sun.com /* ARGSUSED */ 4148762SAndrew.W.Wilson@sun.com static void 4158762SAndrew.W.Wilson@sun.com procflow_cancel(int arg1) 4168762SAndrew.W.Wilson@sun.com { 4178762SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_IMPL, "Process signal handler on pid %", 4188762SAndrew.W.Wilson@sun.com my_procflow->pf_pid); 4198762SAndrew.W.Wilson@sun.com 4208762SAndrew.W.Wilson@sun.com procflow_sleep(my_procflow, SHUTDOWN_WAIT_SECONDS); 4218762SAndrew.W.Wilson@sun.com 4228762SAndrew.W.Wilson@sun.com threadflow_delete_all(&my_procflow->pf_threads); 4238762SAndrew.W.Wilson@sun.com 4248762SAndrew.W.Wilson@sun.com /* quit the main procflow thread and hence the process */ 4258762SAndrew.W.Wilson@sun.com exit(0); 4268762SAndrew.W.Wilson@sun.com } 4278762SAndrew.W.Wilson@sun.com 4285184Sek110237 #endif /* USE_PROCESS_MODEL */ 4295184Sek110237 4305184Sek110237 /* 4315184Sek110237 * Iterates through proclist, the master list of procflows, 4325184Sek110237 * creating the number of instances of each procflow specified 4335184Sek110237 * by its pf_instance attribute. Returns 0 on success, or -1 4345184Sek110237 * times the number of procflow instances that were not 4355184Sek110237 * successfully created. 4365184Sek110237 */ 4375184Sek110237 int 4385184Sek110237 procflow_init(void) 4395184Sek110237 { 4406391Saw148015 procflow_t *procflow = filebench_shm->shm_proclist; 4415184Sek110237 pthread_t tid; 4425184Sek110237 int ret = 0; 4435184Sek110237 444*9326SAndrew.W.Wilson@sun.com if (procflow == NULL) { 445*9326SAndrew.W.Wilson@sun.com filebench_log(LOG_ERROR, "Workload has no processes"); 446*9326SAndrew.W.Wilson@sun.com return (FILEBENCH_ERROR); 447*9326SAndrew.W.Wilson@sun.com } 448*9326SAndrew.W.Wilson@sun.com 4495184Sek110237 filebench_log(LOG_DEBUG_IMPL, 4506286Saw148015 "procflow_init %s, %llu", 4516286Saw148015 procflow->pf_name, 4526286Saw148015 (u_longlong_t)avd_get_int(procflow->pf_instances)); 4535184Sek110237 4545184Sek110237 #ifdef USE_PROCESS_MODEL 4555184Sek110237 if ((pthread_create(&tid, NULL, procflow_createnwait, NULL)) != 0) 4565184Sek110237 return (ret); 4575184Sek110237 4586391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 4595184Sek110237 4608762SAndrew.W.Wilson@sun.com (void) signal(SIGUSR1, procflow_cancel); 4618762SAndrew.W.Wilson@sun.com 4627556SAndrew.W.Wilson@sun.com if ((ret = pthread_cond_wait(&filebench_shm->shm_procflow_procs_cv, 4636391Saw148015 &filebench_shm->shm_procflow_lock)) != 0) 4645184Sek110237 return (ret); 4655184Sek110237 4665184Sek110237 if (cnw_wait == CNW_ERROR) 4675184Sek110237 ret = -1; 4685184Sek110237 4695184Sek110237 #else /* USE_PROCESS_MODEL */ 4706391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 4715184Sek110237 4725184Sek110237 ret = procflow_create_all_procs(); 4735184Sek110237 #endif /* USE_PROCESS_MODEL */ 4745184Sek110237 4756391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); 4765184Sek110237 4775184Sek110237 return (ret); 4785184Sek110237 } 4795184Sek110237 4805184Sek110237 #ifdef USE_PROCESS_MODEL 4815184Sek110237 /* 4825184Sek110237 * Waits for child processes to finish and returns their exit 4835184Sek110237 * status. Used by procflow_delete() when the process model is 4845184Sek110237 * enabled to wait for a deleted process to exit. 4855184Sek110237 */ 4865184Sek110237 static void 4875184Sek110237 procflow_wait(pid_t pid) 4885184Sek110237 { 4895184Sek110237 pid_t wpid; 4905184Sek110237 int stat; 4915184Sek110237 4925184Sek110237 (void) waitpid(pid, &stat, 0); 4935184Sek110237 while ((wpid = waitpid(getpid() * -1, &stat, WNOHANG)) > 0) 4946286Saw148015 filebench_log(LOG_DEBUG_IMPL, "Waited for pid %d", (int)wpid); 4955184Sek110237 } 4965184Sek110237 #endif 4975184Sek110237 4985184Sek110237 /* 4998762SAndrew.W.Wilson@sun.com * Common routine to sleep for wait_cnt seconds or for pf_running to 5008762SAndrew.W.Wilson@sun.com * go false. Checks once a second to see if pf_running has gone false. 5018762SAndrew.W.Wilson@sun.com */ 5028762SAndrew.W.Wilson@sun.com static void 5038762SAndrew.W.Wilson@sun.com procflow_sleep(procflow_t *procflow, int wait_cnt) 5048762SAndrew.W.Wilson@sun.com { 5058762SAndrew.W.Wilson@sun.com while (procflow->pf_running & wait_cnt) { 5068769SAndrew.W.Wilson@sun.com (void) sleep(1); 5078762SAndrew.W.Wilson@sun.com wait_cnt--; 5088762SAndrew.W.Wilson@sun.com } 5098762SAndrew.W.Wilson@sun.com } 5108762SAndrew.W.Wilson@sun.com 5118762SAndrew.W.Wilson@sun.com /* 5128762SAndrew.W.Wilson@sun.com * Deletes the designated procflow. Finally it frees the 5136391Saw148015 * procflow entity. filebench_shm->shm_procflow_lock must be held on entry. 5145184Sek110237 * 5155184Sek110237 * If the designated procflow is not found on the list it returns -1 and 5165184Sek110237 * the procflow is not deleted. Otherwise it returns 0. 5175184Sek110237 */ 5185184Sek110237 static int 5198762SAndrew.W.Wilson@sun.com procflow_cleanup(procflow_t *procflow) 5205184Sek110237 { 5215184Sek110237 procflow_t *entry; 5225184Sek110237 5235184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, 5245184Sek110237 "Deleted proc: (%s-%d) pid %d", 5255184Sek110237 procflow->pf_name, 5265184Sek110237 procflow->pf_instance, 5275184Sek110237 procflow->pf_pid); 5285184Sek110237 5298762SAndrew.W.Wilson@sun.com procflow->pf_running = 0; 5305184Sek110237 5315184Sek110237 /* remove entry from proclist */ 5326391Saw148015 entry = filebench_shm->shm_proclist; 5335184Sek110237 5345184Sek110237 /* unlink procflow entity from proclist */ 5355184Sek110237 if (entry == procflow) { 5365184Sek110237 /* at head of list */ 5376391Saw148015 filebench_shm->shm_proclist = procflow->pf_next; 5385184Sek110237 } else { 5395184Sek110237 /* search list for procflow */ 5405184Sek110237 while (entry && entry->pf_next != procflow) 5415184Sek110237 entry = entry->pf_next; 5425184Sek110237 5435184Sek110237 /* if entity found, unlink it */ 5445184Sek110237 if (entry == NULL) 5455184Sek110237 return (-1); 5465184Sek110237 else 5475184Sek110237 entry->pf_next = procflow->pf_next; 5485184Sek110237 } 5495184Sek110237 5505184Sek110237 /* free up the procflow entity */ 5515184Sek110237 ipc_free(FILEBENCH_PROCFLOW, (char *)procflow); 5525184Sek110237 return (0); 5535184Sek110237 } 5545184Sek110237 5555184Sek110237 5565184Sek110237 /* 5575184Sek110237 * Waits till all threadflows are started, or a timeout occurs. 5585184Sek110237 * Checks through the list of procflows, waiting up to 30 5595184Sek110237 * seconds for each one to set its pf_running flag to 1. If not 5605184Sek110237 * set after 30 seconds, continues on to the next procflow 5615184Sek110237 * anyway after logging the fact. Once pf_running is set 5625184Sek110237 * to 1 for a given procflow or the timeout is reached, 5635184Sek110237 * threadflow_allstarted() is called to start the threads. 5646391Saw148015 * Returns 0 (OK), unless filebench_shm->shm_f_abort is signaled, 5655184Sek110237 * in which case it returns -1. 5665184Sek110237 */ 5675184Sek110237 int 5685184Sek110237 procflow_allstarted() 5695184Sek110237 { 5706391Saw148015 procflow_t *procflow = filebench_shm->shm_proclist; 5716084Saw148015 int running_procs = 0; 5725184Sek110237 int ret = 0; 5735184Sek110237 5746391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 5755184Sek110237 5765184Sek110237 (void) sleep(1); 5775184Sek110237 5785184Sek110237 while (procflow) { 5795184Sek110237 int waits; 5805184Sek110237 5815184Sek110237 if (procflow->pf_instance && 5825184Sek110237 (procflow->pf_instance == FLOW_MASTER)) { 5835184Sek110237 procflow = procflow->pf_next; 5845184Sek110237 continue; 5855184Sek110237 } 5865184Sek110237 5875184Sek110237 waits = 10; 5885184Sek110237 while (waits && procflow->pf_running == 0) { 5896391Saw148015 (void) ipc_mutex_unlock( 5906391Saw148015 &filebench_shm->shm_procflow_lock); 5916391Saw148015 if (filebench_shm->shm_f_abort == 1) 5925184Sek110237 return (-1); 5935184Sek110237 5945184Sek110237 if (waits < 3) 5955184Sek110237 filebench_log(LOG_INFO, 5965184Sek110237 "Waiting for process %s-%d %d", 5975184Sek110237 procflow->pf_name, 5985184Sek110237 procflow->pf_instance, 5995184Sek110237 procflow->pf_pid); 6005184Sek110237 6015184Sek110237 (void) sleep(3); 6025184Sek110237 waits--; 6036391Saw148015 (void) ipc_mutex_lock( 6046391Saw148015 &filebench_shm->shm_procflow_lock); 6055184Sek110237 } 6065184Sek110237 6075184Sek110237 if (waits == 0) 6086084Saw148015 filebench_log(LOG_INFO, 6096084Saw148015 "Failed to start process %s-%d", 6105184Sek110237 procflow->pf_name, 6115184Sek110237 procflow->pf_instance); 6125184Sek110237 6136084Saw148015 running_procs++; 6145184Sek110237 threadflow_allstarted(procflow->pf_pid, procflow->pf_threads); 6155184Sek110237 6165184Sek110237 procflow = procflow->pf_next; 6175184Sek110237 } 6186701Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock); 6196701Saw148015 filebench_shm->shm_procs_running = running_procs; 6206701Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock); 6215184Sek110237 6226391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); 6235184Sek110237 6245184Sek110237 6255184Sek110237 return (ret); 6265184Sek110237 } 6275184Sek110237 6285184Sek110237 6295184Sek110237 /* 6306084Saw148015 * Sets the f_abort flag and clears the running count to stop 6315184Sek110237 * all the flowop execution threads from running. Iterates 6325184Sek110237 * through the procflow list and deletes all procflows except 6335184Sek110237 * for the FLOW_MASTER procflow. Resets the f_abort flag when 6345184Sek110237 * finished. 6356701Saw148015 * 6365184Sek110237 */ 6375184Sek110237 void 6385184Sek110237 procflow_shutdown(void) 6395184Sek110237 { 6408762SAndrew.W.Wilson@sun.com procflow_t *procflow, *next_procflow; 6418762SAndrew.W.Wilson@sun.com int wait_cnt = SHUTDOWN_WAIT_SECONDS; 6425184Sek110237 6436701Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock); 6447556SAndrew.W.Wilson@sun.com if (filebench_shm->shm_procs_running <= 0) { 6456701Saw148015 /* No processes running, so no need to do anything */ 6466701Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock); 6476701Saw148015 return; 6486701Saw148015 } 6496701Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock); 6506701Saw148015 6516391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 652*9326SAndrew.W.Wilson@sun.com if (filebench_shm->shm_f_abort == FILEBENCH_ABORT_FINI) { 653*9326SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock( 654*9326SAndrew.W.Wilson@sun.com &filebench_shm->shm_procflow_lock); 655*9326SAndrew.W.Wilson@sun.com return; 656*9326SAndrew.W.Wilson@sun.com } 657*9326SAndrew.W.Wilson@sun.com 6588615SAndrew.W.Wilson@sun.com procflow = filebench_shm->shm_proclist; 659*9326SAndrew.W.Wilson@sun.com if (filebench_shm->shm_f_abort == FILEBENCH_OK) 660*9326SAndrew.W.Wilson@sun.com filebench_shm->shm_f_abort = FILEBENCH_ABORT_DONE; 6615184Sek110237 6625184Sek110237 while (procflow) { 6635184Sek110237 if (procflow->pf_instance && 6645184Sek110237 (procflow->pf_instance == FLOW_MASTER)) { 6655184Sek110237 procflow = procflow->pf_next; 6665184Sek110237 continue; 6675184Sek110237 } 6685184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Deleting process %s-%d %d", 6695184Sek110237 procflow->pf_name, 6705184Sek110237 procflow->pf_instance, 6715184Sek110237 procflow->pf_pid); 6728762SAndrew.W.Wilson@sun.com 6738762SAndrew.W.Wilson@sun.com next_procflow = procflow->pf_next; 6748762SAndrew.W.Wilson@sun.com 6758762SAndrew.W.Wilson@sun.com /* 6768762SAndrew.W.Wilson@sun.com * Signalling the process with SIGUSR1 will result in it 6778762SAndrew.W.Wilson@sun.com * gracefully shutting down and exiting 6788762SAndrew.W.Wilson@sun.com */ 6798762SAndrew.W.Wilson@sun.com procflow_sleep(procflow, wait_cnt); 6808762SAndrew.W.Wilson@sun.com if (procflow->pf_running) { 6818762SAndrew.W.Wilson@sun.com #ifdef USE_PROCESS_MODEL 6828762SAndrew.W.Wilson@sun.com pid_t pid; 6838762SAndrew.W.Wilson@sun.com 6848762SAndrew.W.Wilson@sun.com pid = procflow->pf_pid; 6858762SAndrew.W.Wilson@sun.com #ifdef HAVE_SIGSEND 6868762SAndrew.W.Wilson@sun.com (void) sigsend(P_PID, pid, SIGUSR1); 6878762SAndrew.W.Wilson@sun.com #else 6888762SAndrew.W.Wilson@sun.com (void) kill(pid, SIGUSR1); 6898762SAndrew.W.Wilson@sun.com #endif 6908762SAndrew.W.Wilson@sun.com procflow_wait(pid); 6918762SAndrew.W.Wilson@sun.com 6928762SAndrew.W.Wilson@sun.com #else /* USE_PROCESS_MODEL */ 6938762SAndrew.W.Wilson@sun.com threadflow_delete_all(&procflow->pf_threads); 6948762SAndrew.W.Wilson@sun.com #endif /* USE_PROCESS_MODEL */ 6958762SAndrew.W.Wilson@sun.com } 6968762SAndrew.W.Wilson@sun.com (void) procflow_cleanup(procflow); 6978762SAndrew.W.Wilson@sun.com procflow = next_procflow; 6988762SAndrew.W.Wilson@sun.com if (wait_cnt > 0) 6996084Saw148015 wait_cnt--; 7005184Sek110237 } 7015184Sek110237 702*9326SAndrew.W.Wilson@sun.com filebench_shm->shm_f_abort = FILEBENCH_ABORT_FINI; 7036391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); 7047556SAndrew.W.Wilson@sun.com 7057556SAndrew.W.Wilson@sun.com /* indicate all processes are stopped, even if some are "stuck" */ 7067556SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock); 7077556SAndrew.W.Wilson@sun.com filebench_shm->shm_procs_running = 0; 7087556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock); 7095184Sek110237 } 7105184Sek110237 7115184Sek110237 7125184Sek110237 /* 7135184Sek110237 * Create an in-memory process object. Allocates a procflow 7145184Sek110237 * entity, initialized from the "inherit" procflow if supplied. 7155184Sek110237 * The name and instance number are set from the supplied name 7165184Sek110237 * and instance number and the procflow is added to the head of 7175184Sek110237 * the master procflow list. Returns pointer to the allocated 7185184Sek110237 * procflow, or NULL if a name isn't supplied or the procflow 7195184Sek110237 * entity cannot be allocated. 7205184Sek110237 * 7216391Saw148015 * The calling routine must hold the filebench_shm->shm_procflow_lock. 7225184Sek110237 */ 7235184Sek110237 static procflow_t * 7245184Sek110237 procflow_define_common(procflow_t **list, char *name, 7255184Sek110237 procflow_t *inherit, int instance) 7265184Sek110237 { 7275184Sek110237 procflow_t *procflow; 7285184Sek110237 7295184Sek110237 if (name == NULL) 7305184Sek110237 return (NULL); 7315184Sek110237 7325184Sek110237 procflow = (procflow_t *)ipc_malloc(FILEBENCH_PROCFLOW); 7335184Sek110237 7345184Sek110237 if (procflow == NULL) 7355184Sek110237 return (NULL); 7365184Sek110237 7375184Sek110237 if (inherit) 7385184Sek110237 (void) memcpy(procflow, inherit, sizeof (procflow_t)); 7395184Sek110237 else 7405184Sek110237 (void) memset(procflow, 0, sizeof (procflow_t)); 7415184Sek110237 7425184Sek110237 procflow->pf_instance = instance; 7435184Sek110237 (void) strcpy(procflow->pf_name, name); 7445184Sek110237 7455184Sek110237 filebench_log(LOG_DEBUG_IMPL, "defining process %s-%d", name, instance); 7465184Sek110237 7475184Sek110237 /* Add procflow to list, lock is being held already */ 7485184Sek110237 if (*list == NULL) { 7495184Sek110237 *list = procflow; 7505184Sek110237 procflow->pf_next = NULL; 7515184Sek110237 } else { 7525184Sek110237 procflow->pf_next = *list; 7535184Sek110237 *list = procflow; 7545184Sek110237 } 7555184Sek110237 filebench_log(LOG_DEBUG_IMPL, "process %s-%d proclist %zx", 7566391Saw148015 name, instance, filebench_shm->shm_proclist); 7575184Sek110237 7585184Sek110237 return (procflow); 7595184Sek110237 } 7605184Sek110237 7615184Sek110237 /* 7625184Sek110237 * Create an in-memory process object as described by the syntax. 7636391Saw148015 * Acquires the filebench_shm->shm_procflow_lock and calls 7645184Sek110237 * procflow_define_common() to create and initialize a 7655184Sek110237 * FLOW_MASTER procflow entity from the optional "inherit" 7665184Sek110237 * procflow with the given name and configured for "instances" 7675184Sek110237 * number of worker procflows. Currently only called from 7685184Sek110237 * parser_proc_define(). 7695184Sek110237 */ 7705184Sek110237 procflow_t * 7716212Saw148015 procflow_define(char *name, procflow_t *inherit, avd_t instances) 7725184Sek110237 { 7735184Sek110237 procflow_t *procflow; 7745184Sek110237 7756391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 7765184Sek110237 7776391Saw148015 procflow = procflow_define_common(&filebench_shm->shm_proclist, 7785184Sek110237 name, inherit, FLOW_MASTER); 7795184Sek110237 procflow->pf_instances = instances; 7805184Sek110237 7816391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); 7825184Sek110237 7835184Sek110237 return (procflow); 7845184Sek110237 } 785