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
procflow_usage(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
procflow_createproc(procflow_t * procflow)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 *
procflow_find(char * name,int instance)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
procflow_create_all_procs(void)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
procflow_exec(char * name,int instance)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 *
procflow_createnwait(void * nothing)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
procflow_cancel(int arg1)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
procflow_init(void)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
procflow_wait(pid_t pid)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
procflow_sleep(procflow_t * procflow,int wait_cnt)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
procflow_cleanup(procflow_t * procflow)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
procflow_allstarted()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
procflow_shutdown(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 *
procflow_define_common(procflow_t ** list,char * name,procflow_t * inherit,int instance)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 *
procflow_define(char * name,procflow_t * inherit,avd_t instances)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