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 */ 3736391Saw148015 if (filebench_shm->shm_f_abort) 3746701Saw148015 (void) ipc_mutex_unlock( 3756701Saw148015 &filebench_shm->shm_procflow_lock); 3765184Sek110237 pthread_exit(0); 3775184Sek110237 3786701Saw148015 /* if nothing running, exit */ 3796701Saw148015 if (filebench_shm->shm_procs_running == 0) { 3806701Saw148015 filebench_shm->shm_f_abort = FILEBENCH_ABORT_RSRC; 3816701Saw148015 (void) ipc_mutex_unlock( 3826701Saw148015 &filebench_shm->shm_procflow_lock); 3836701Saw148015 pthread_exit(0); 3846701Saw148015 } 3856701Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); 3866701Saw148015 3875184Sek110237 if (status.si_code == CLD_EXITED) { 3885184Sek110237 /* A process called exit(); check returned status */ 3895184Sek110237 if (status.si_status != 0) { 3905184Sek110237 filebench_log(LOG_ERROR, 3915184Sek110237 "Unexpected Process termination; exiting", 3925184Sek110237 status.si_status); 3935184Sek110237 filebench_shutdown(1); 3945184Sek110237 } 3955184Sek110237 } else { 3965184Sek110237 /* A process quit because of some fatal error */ 3975184Sek110237 filebench_log(LOG_ERROR, 3985184Sek110237 "Unexpected Process termination Code %d, Errno %d", 3995184Sek110237 status.si_code, status.si_errno); 4005184Sek110237 filebench_shutdown(1); 4015184Sek110237 } 4025184Sek110237 4035184Sek110237 } 4045184Sek110237 /* NOTREACHED */ 4055184Sek110237 return (NULL); 4065184Sek110237 } 4078762SAndrew.W.Wilson@sun.com 4088762SAndrew.W.Wilson@sun.com /* 4098762SAndrew.W.Wilson@sun.com * Cancel all threads within a processes, as well as the process itself. 4108762SAndrew.W.Wilson@sun.com * Called by ^c or by sig_kill 4118762SAndrew.W.Wilson@sun.com */ 4128762SAndrew.W.Wilson@sun.com /* ARGSUSED */ 4138762SAndrew.W.Wilson@sun.com static void 4148762SAndrew.W.Wilson@sun.com procflow_cancel(int arg1) 4158762SAndrew.W.Wilson@sun.com { 4168762SAndrew.W.Wilson@sun.com filebench_log(LOG_DEBUG_IMPL, "Process signal handler on pid %", 4178762SAndrew.W.Wilson@sun.com my_procflow->pf_pid); 4188762SAndrew.W.Wilson@sun.com 4198762SAndrew.W.Wilson@sun.com procflow_sleep(my_procflow, SHUTDOWN_WAIT_SECONDS); 4208762SAndrew.W.Wilson@sun.com 4218762SAndrew.W.Wilson@sun.com threadflow_delete_all(&my_procflow->pf_threads); 4228762SAndrew.W.Wilson@sun.com 4238762SAndrew.W.Wilson@sun.com /* quit the main procflow thread and hence the process */ 4248762SAndrew.W.Wilson@sun.com exit(0); 4258762SAndrew.W.Wilson@sun.com } 4268762SAndrew.W.Wilson@sun.com 4275184Sek110237 #endif /* USE_PROCESS_MODEL */ 4285184Sek110237 4295184Sek110237 /* 4305184Sek110237 * Iterates through proclist, the master list of procflows, 4315184Sek110237 * creating the number of instances of each procflow specified 4325184Sek110237 * by its pf_instance attribute. Returns 0 on success, or -1 4335184Sek110237 * times the number of procflow instances that were not 4345184Sek110237 * successfully created. 4355184Sek110237 */ 4365184Sek110237 int 4375184Sek110237 procflow_init(void) 4385184Sek110237 { 4396391Saw148015 procflow_t *procflow = filebench_shm->shm_proclist; 4405184Sek110237 pthread_t tid; 4415184Sek110237 int ret = 0; 4425184Sek110237 4435184Sek110237 filebench_log(LOG_DEBUG_IMPL, 4446286Saw148015 "procflow_init %s, %llu", 4456286Saw148015 procflow->pf_name, 4466286Saw148015 (u_longlong_t)avd_get_int(procflow->pf_instances)); 4475184Sek110237 4485184Sek110237 #ifdef USE_PROCESS_MODEL 4495184Sek110237 4505184Sek110237 if ((pthread_create(&tid, NULL, procflow_createnwait, NULL)) != 0) 4515184Sek110237 return (ret); 4525184Sek110237 4536391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 4545184Sek110237 4558762SAndrew.W.Wilson@sun.com (void) signal(SIGUSR1, procflow_cancel); 4568762SAndrew.W.Wilson@sun.com 4577556SAndrew.W.Wilson@sun.com if ((ret = pthread_cond_wait(&filebench_shm->shm_procflow_procs_cv, 4586391Saw148015 &filebench_shm->shm_procflow_lock)) != 0) 4595184Sek110237 return (ret); 4605184Sek110237 4615184Sek110237 if (cnw_wait == CNW_ERROR) 4625184Sek110237 ret = -1; 4635184Sek110237 4645184Sek110237 #else /* USE_PROCESS_MODEL */ 4656391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 4665184Sek110237 4675184Sek110237 ret = procflow_create_all_procs(); 4685184Sek110237 #endif /* USE_PROCESS_MODEL */ 4695184Sek110237 4706391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); 4715184Sek110237 4725184Sek110237 return (ret); 4735184Sek110237 } 4745184Sek110237 4755184Sek110237 #ifdef USE_PROCESS_MODEL 4765184Sek110237 /* 4775184Sek110237 * Waits for child processes to finish and returns their exit 4785184Sek110237 * status. Used by procflow_delete() when the process model is 4795184Sek110237 * enabled to wait for a deleted process to exit. 4805184Sek110237 */ 4815184Sek110237 static void 4825184Sek110237 procflow_wait(pid_t pid) 4835184Sek110237 { 4845184Sek110237 pid_t wpid; 4855184Sek110237 int stat; 4865184Sek110237 4875184Sek110237 (void) waitpid(pid, &stat, 0); 4885184Sek110237 while ((wpid = waitpid(getpid() * -1, &stat, WNOHANG)) > 0) 4896286Saw148015 filebench_log(LOG_DEBUG_IMPL, "Waited for pid %d", (int)wpid); 4905184Sek110237 } 4915184Sek110237 #endif 4925184Sek110237 4935184Sek110237 /* 4948762SAndrew.W.Wilson@sun.com * Common routine to sleep for wait_cnt seconds or for pf_running to 4958762SAndrew.W.Wilson@sun.com * go false. Checks once a second to see if pf_running has gone false. 4968762SAndrew.W.Wilson@sun.com */ 4978762SAndrew.W.Wilson@sun.com static void 4988762SAndrew.W.Wilson@sun.com procflow_sleep(procflow_t *procflow, int wait_cnt) 4998762SAndrew.W.Wilson@sun.com { 5008762SAndrew.W.Wilson@sun.com while (procflow->pf_running & wait_cnt) { 501*8769SAndrew.W.Wilson@sun.com (void) sleep(1); 5028762SAndrew.W.Wilson@sun.com wait_cnt--; 5038762SAndrew.W.Wilson@sun.com } 5048762SAndrew.W.Wilson@sun.com } 5058762SAndrew.W.Wilson@sun.com 5068762SAndrew.W.Wilson@sun.com /* 5078762SAndrew.W.Wilson@sun.com * Deletes the designated procflow. Finally it frees the 5086391Saw148015 * procflow entity. filebench_shm->shm_procflow_lock must be held on entry. 5095184Sek110237 * 5105184Sek110237 * If the designated procflow is not found on the list it returns -1 and 5115184Sek110237 * the procflow is not deleted. Otherwise it returns 0. 5125184Sek110237 */ 5135184Sek110237 static int 5148762SAndrew.W.Wilson@sun.com procflow_cleanup(procflow_t *procflow) 5155184Sek110237 { 5165184Sek110237 procflow_t *entry; 5175184Sek110237 5185184Sek110237 filebench_log(LOG_DEBUG_SCRIPT, 5195184Sek110237 "Deleted proc: (%s-%d) pid %d", 5205184Sek110237 procflow->pf_name, 5215184Sek110237 procflow->pf_instance, 5225184Sek110237 procflow->pf_pid); 5235184Sek110237 5248762SAndrew.W.Wilson@sun.com procflow->pf_running = 0; 5255184Sek110237 5265184Sek110237 /* remove entry from proclist */ 5276391Saw148015 entry = filebench_shm->shm_proclist; 5285184Sek110237 5295184Sek110237 /* unlink procflow entity from proclist */ 5305184Sek110237 if (entry == procflow) { 5315184Sek110237 /* at head of list */ 5326391Saw148015 filebench_shm->shm_proclist = procflow->pf_next; 5335184Sek110237 } else { 5345184Sek110237 /* search list for procflow */ 5355184Sek110237 while (entry && entry->pf_next != procflow) 5365184Sek110237 entry = entry->pf_next; 5375184Sek110237 5385184Sek110237 /* if entity found, unlink it */ 5395184Sek110237 if (entry == NULL) 5405184Sek110237 return (-1); 5415184Sek110237 else 5425184Sek110237 entry->pf_next = procflow->pf_next; 5435184Sek110237 } 5445184Sek110237 5455184Sek110237 /* free up the procflow entity */ 5465184Sek110237 ipc_free(FILEBENCH_PROCFLOW, (char *)procflow); 5475184Sek110237 return (0); 5485184Sek110237 } 5495184Sek110237 5505184Sek110237 5515184Sek110237 /* 5525184Sek110237 * Waits till all threadflows are started, or a timeout occurs. 5535184Sek110237 * Checks through the list of procflows, waiting up to 30 5545184Sek110237 * seconds for each one to set its pf_running flag to 1. If not 5555184Sek110237 * set after 30 seconds, continues on to the next procflow 5565184Sek110237 * anyway after logging the fact. Once pf_running is set 5575184Sek110237 * to 1 for a given procflow or the timeout is reached, 5585184Sek110237 * threadflow_allstarted() is called to start the threads. 5596391Saw148015 * Returns 0 (OK), unless filebench_shm->shm_f_abort is signaled, 5605184Sek110237 * in which case it returns -1. 5615184Sek110237 */ 5625184Sek110237 int 5635184Sek110237 procflow_allstarted() 5645184Sek110237 { 5656391Saw148015 procflow_t *procflow = filebench_shm->shm_proclist; 5666084Saw148015 int running_procs = 0; 5675184Sek110237 int ret = 0; 5685184Sek110237 5696391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 5705184Sek110237 5715184Sek110237 (void) sleep(1); 5725184Sek110237 5735184Sek110237 while (procflow) { 5745184Sek110237 int waits; 5755184Sek110237 5765184Sek110237 if (procflow->pf_instance && 5775184Sek110237 (procflow->pf_instance == FLOW_MASTER)) { 5785184Sek110237 procflow = procflow->pf_next; 5795184Sek110237 continue; 5805184Sek110237 } 5815184Sek110237 5825184Sek110237 waits = 10; 5835184Sek110237 while (waits && procflow->pf_running == 0) { 5846391Saw148015 (void) ipc_mutex_unlock( 5856391Saw148015 &filebench_shm->shm_procflow_lock); 5866391Saw148015 if (filebench_shm->shm_f_abort == 1) 5875184Sek110237 return (-1); 5885184Sek110237 5895184Sek110237 if (waits < 3) 5905184Sek110237 filebench_log(LOG_INFO, 5915184Sek110237 "Waiting for process %s-%d %d", 5925184Sek110237 procflow->pf_name, 5935184Sek110237 procflow->pf_instance, 5945184Sek110237 procflow->pf_pid); 5955184Sek110237 5965184Sek110237 (void) sleep(3); 5975184Sek110237 waits--; 5986391Saw148015 (void) ipc_mutex_lock( 5996391Saw148015 &filebench_shm->shm_procflow_lock); 6005184Sek110237 } 6015184Sek110237 6025184Sek110237 if (waits == 0) 6036084Saw148015 filebench_log(LOG_INFO, 6046084Saw148015 "Failed to start process %s-%d", 6055184Sek110237 procflow->pf_name, 6065184Sek110237 procflow->pf_instance); 6075184Sek110237 6086084Saw148015 running_procs++; 6095184Sek110237 threadflow_allstarted(procflow->pf_pid, procflow->pf_threads); 6105184Sek110237 6115184Sek110237 procflow = procflow->pf_next; 6125184Sek110237 } 6136701Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock); 6146701Saw148015 filebench_shm->shm_procs_running = running_procs; 6156701Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock); 6165184Sek110237 6176391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); 6185184Sek110237 6195184Sek110237 6205184Sek110237 return (ret); 6215184Sek110237 } 6225184Sek110237 6235184Sek110237 6245184Sek110237 /* 6256084Saw148015 * Sets the f_abort flag and clears the running count to stop 6265184Sek110237 * all the flowop execution threads from running. Iterates 6275184Sek110237 * through the procflow list and deletes all procflows except 6285184Sek110237 * for the FLOW_MASTER procflow. Resets the f_abort flag when 6295184Sek110237 * finished. 6306701Saw148015 * 6315184Sek110237 */ 6325184Sek110237 void 6335184Sek110237 procflow_shutdown(void) 6345184Sek110237 { 6358762SAndrew.W.Wilson@sun.com procflow_t *procflow, *next_procflow; 6368762SAndrew.W.Wilson@sun.com int wait_cnt = SHUTDOWN_WAIT_SECONDS; 6375184Sek110237 6386701Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock); 6397556SAndrew.W.Wilson@sun.com if (filebench_shm->shm_procs_running <= 0) { 6406701Saw148015 /* No processes running, so no need to do anything */ 6416701Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock); 6426701Saw148015 return; 6436701Saw148015 } 6446701Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock); 6456701Saw148015 6466391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 6478615SAndrew.W.Wilson@sun.com procflow = filebench_shm->shm_proclist; 6486391Saw148015 filebench_shm->shm_f_abort = 1; 6495184Sek110237 6505184Sek110237 while (procflow) { 6515184Sek110237 if (procflow->pf_instance && 6525184Sek110237 (procflow->pf_instance == FLOW_MASTER)) { 6535184Sek110237 procflow = procflow->pf_next; 6545184Sek110237 continue; 6555184Sek110237 } 6565184Sek110237 filebench_log(LOG_DEBUG_IMPL, "Deleting process %s-%d %d", 6575184Sek110237 procflow->pf_name, 6585184Sek110237 procflow->pf_instance, 6595184Sek110237 procflow->pf_pid); 6608762SAndrew.W.Wilson@sun.com 6618762SAndrew.W.Wilson@sun.com next_procflow = procflow->pf_next; 6628762SAndrew.W.Wilson@sun.com 6638762SAndrew.W.Wilson@sun.com /* 6648762SAndrew.W.Wilson@sun.com * Signalling the process with SIGUSR1 will result in it 6658762SAndrew.W.Wilson@sun.com * gracefully shutting down and exiting 6668762SAndrew.W.Wilson@sun.com */ 6678762SAndrew.W.Wilson@sun.com procflow_sleep(procflow, wait_cnt); 6688762SAndrew.W.Wilson@sun.com if (procflow->pf_running) { 6698762SAndrew.W.Wilson@sun.com #ifdef USE_PROCESS_MODEL 6708762SAndrew.W.Wilson@sun.com pid_t pid; 6718762SAndrew.W.Wilson@sun.com 6728762SAndrew.W.Wilson@sun.com pid = procflow->pf_pid; 6738762SAndrew.W.Wilson@sun.com #ifdef HAVE_SIGSEND 6748762SAndrew.W.Wilson@sun.com (void) sigsend(P_PID, pid, SIGUSR1); 6758762SAndrew.W.Wilson@sun.com #else 6768762SAndrew.W.Wilson@sun.com (void) kill(pid, SIGUSR1); 6778762SAndrew.W.Wilson@sun.com #endif 6788762SAndrew.W.Wilson@sun.com procflow_wait(pid); 6798762SAndrew.W.Wilson@sun.com 6808762SAndrew.W.Wilson@sun.com #else /* USE_PROCESS_MODEL */ 6818762SAndrew.W.Wilson@sun.com threadflow_delete_all(&procflow->pf_threads); 6828762SAndrew.W.Wilson@sun.com #endif /* USE_PROCESS_MODEL */ 6838762SAndrew.W.Wilson@sun.com } 6848762SAndrew.W.Wilson@sun.com (void) procflow_cleanup(procflow); 6858762SAndrew.W.Wilson@sun.com procflow = next_procflow; 6868762SAndrew.W.Wilson@sun.com if (wait_cnt > 0) 6876084Saw148015 wait_cnt--; 6885184Sek110237 } 6895184Sek110237 6906391Saw148015 filebench_shm->shm_f_abort = 0; 6915184Sek110237 6926391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); 6937556SAndrew.W.Wilson@sun.com 6947556SAndrew.W.Wilson@sun.com /* indicate all processes are stopped, even if some are "stuck" */ 6957556SAndrew.W.Wilson@sun.com (void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock); 6967556SAndrew.W.Wilson@sun.com filebench_shm->shm_procs_running = 0; 6977556SAndrew.W.Wilson@sun.com (void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock); 6985184Sek110237 } 6995184Sek110237 7005184Sek110237 7015184Sek110237 /* 7025184Sek110237 * Create an in-memory process object. Allocates a procflow 7035184Sek110237 * entity, initialized from the "inherit" procflow if supplied. 7045184Sek110237 * The name and instance number are set from the supplied name 7055184Sek110237 * and instance number and the procflow is added to the head of 7065184Sek110237 * the master procflow list. Returns pointer to the allocated 7075184Sek110237 * procflow, or NULL if a name isn't supplied or the procflow 7085184Sek110237 * entity cannot be allocated. 7095184Sek110237 * 7106391Saw148015 * The calling routine must hold the filebench_shm->shm_procflow_lock. 7115184Sek110237 */ 7125184Sek110237 static procflow_t * 7135184Sek110237 procflow_define_common(procflow_t **list, char *name, 7145184Sek110237 procflow_t *inherit, int instance) 7155184Sek110237 { 7165184Sek110237 procflow_t *procflow; 7175184Sek110237 7185184Sek110237 if (name == NULL) 7195184Sek110237 return (NULL); 7205184Sek110237 7215184Sek110237 procflow = (procflow_t *)ipc_malloc(FILEBENCH_PROCFLOW); 7225184Sek110237 7235184Sek110237 if (procflow == NULL) 7245184Sek110237 return (NULL); 7255184Sek110237 7265184Sek110237 if (inherit) 7275184Sek110237 (void) memcpy(procflow, inherit, sizeof (procflow_t)); 7285184Sek110237 else 7295184Sek110237 (void) memset(procflow, 0, sizeof (procflow_t)); 7305184Sek110237 7315184Sek110237 procflow->pf_instance = instance; 7325184Sek110237 (void) strcpy(procflow->pf_name, name); 7335184Sek110237 7345184Sek110237 filebench_log(LOG_DEBUG_IMPL, "defining process %s-%d", name, instance); 7355184Sek110237 7365184Sek110237 /* Add procflow to list, lock is being held already */ 7375184Sek110237 if (*list == NULL) { 7385184Sek110237 *list = procflow; 7395184Sek110237 procflow->pf_next = NULL; 7405184Sek110237 } else { 7415184Sek110237 procflow->pf_next = *list; 7425184Sek110237 *list = procflow; 7435184Sek110237 } 7445184Sek110237 filebench_log(LOG_DEBUG_IMPL, "process %s-%d proclist %zx", 7456391Saw148015 name, instance, filebench_shm->shm_proclist); 7465184Sek110237 7475184Sek110237 return (procflow); 7485184Sek110237 } 7495184Sek110237 7505184Sek110237 /* 7515184Sek110237 * Create an in-memory process object as described by the syntax. 7526391Saw148015 * Acquires the filebench_shm->shm_procflow_lock and calls 7535184Sek110237 * procflow_define_common() to create and initialize a 7545184Sek110237 * FLOW_MASTER procflow entity from the optional "inherit" 7555184Sek110237 * procflow with the given name and configured for "instances" 7565184Sek110237 * number of worker procflows. Currently only called from 7575184Sek110237 * parser_proc_define(). 7585184Sek110237 */ 7595184Sek110237 procflow_t * 7606212Saw148015 procflow_define(char *name, procflow_t *inherit, avd_t instances) 7615184Sek110237 { 7625184Sek110237 procflow_t *procflow; 7635184Sek110237 7646391Saw148015 (void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock); 7655184Sek110237 7666391Saw148015 procflow = procflow_define_common(&filebench_shm->shm_proclist, 7675184Sek110237 name, inherit, FLOW_MASTER); 7685184Sek110237 procflow->pf_instances = instances; 7695184Sek110237 7706391Saw148015 (void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock); 7715184Sek110237 7725184Sek110237 return (procflow); 7735184Sek110237 } 774