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