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 #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);
445184Sek110237 
455184Sek110237 #ifdef USE_PROCESS_MODEL
465184Sek110237 
475184Sek110237 static enum create_n_wait {
485184Sek110237 	CNW_DONE,
495184Sek110237 	CNW_ERROR
505184Sek110237 } cnw_wait;
515184Sek110237 
525184Sek110237 #endif	/* USE_PROCESS_MODEL */
535184Sek110237 
545184Sek110237 
555184Sek110237 /*
565184Sek110237  * Procflows are filebench entities which manage processes. Each
575184Sek110237  * worker procflow spawns a separate filebench process, with attributes
585184Sek110237  * inherited from a FLOW_MASTER procflow created during f model language
595184Sek110237  * parsing. This section contains routines to define, create, control,
605184Sek110237  * and delete procflows.
615184Sek110237  *
625184Sek110237  * Each process defined in the f model creates a FLOW_MASTER
635184Sek110237  * procflow which encapsulates the defined attributes, and threads of
645184Sek110237  * the f process, including the number of instances to create. At
655184Sek110237  * runtime, a worker procflow instance with an associated filebench
665184Sek110237  * process is created, which runs until told to quite by the original
675184Sek110237  * filebench process or is specifically deleted.
685184Sek110237  */
695184Sek110237 
705184Sek110237 
715184Sek110237 /*
725184Sek110237  * Prints a summary of the syntax for setting procflow parameters.
735184Sek110237  */
745184Sek110237 void
755184Sek110237 procflow_usage(void)
765184Sek110237 {
775184Sek110237 	(void) fprintf(stderr,
785184Sek110237 	    "define process name=<name>[,instances=<count>]\n");
795184Sek110237 	(void) fprintf(stderr, "{\n");
805184Sek110237 	(void) fprintf(stderr, "  thread ...\n");
815184Sek110237 	(void) fprintf(stderr, "  thread ...\n");
825184Sek110237 	(void) fprintf(stderr, "  thread ...\n");
835184Sek110237 	(void) fprintf(stderr, "}\n");
845184Sek110237 	(void) fprintf(stderr, "\n");
855184Sek110237 	(void) fprintf(stderr, "\n");
865184Sek110237 }
875184Sek110237 
885184Sek110237 /*
895184Sek110237  * If filebench has been compiled to support multiple processes
905184Sek110237  * (USE_PROCESS_MODEL defined), this routine forks a child
915184Sek110237  * process and uses either system() or exec() to start up a new
925184Sek110237  * instance of filebench, passing it the procflow name, instance
935184Sek110237  * number and shared memory region address.
945184Sek110237  * If USE_PROCESS_MODEL is NOT defined, then the routine
955184Sek110237  * just creates a child thread which begins executing
965184Sek110237  * threadflow_init() for the specified procflow.
975184Sek110237  */
985184Sek110237 static int
995184Sek110237 procflow_createproc(procflow_t *procflow)
1005184Sek110237 {
1015184Sek110237 	char instance[128];
1025184Sek110237 	char shmaddr[128];
1035184Sek110237 	char procname[128];
1045184Sek110237 	pid_t pid;
1055184Sek110237 
1065184Sek110237 #ifdef USE_PROCESS_MODEL
1075184Sek110237 
1085184Sek110237 	(void) snprintf(instance, sizeof (instance), "%d",
1095184Sek110237 	    procflow->pf_instance);
1105184Sek110237 	(void) snprintf(procname, sizeof (procname), "%s", procflow->pf_name);
1115184Sek110237 #if defined(_LP64) || (__WORDSIZE == 64)
1125184Sek110237 	(void) snprintf(shmaddr, sizeof (shmaddr), "%llx", filebench_shm);
1135184Sek110237 #else
1145184Sek110237 	(void) snprintf(shmaddr, sizeof (shmaddr), "%x", filebench_shm);
1155184Sek110237 #endif
1165184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "creating process %s",
1175184Sek110237 	    procflow->pf_name);
1185184Sek110237 
1195184Sek110237 	procflow->pf_running = 0;
1205184Sek110237 
1215184Sek110237 #ifdef HAVE_FORK1
1225184Sek110237 	if ((pid = fork1()) < 0) {
1235184Sek110237 		filebench_log(LOG_ERROR,
1245184Sek110237 		    "procflow_createproc fork failed: %s",
1255184Sek110237 		    strerror(errno));
1265184Sek110237 		return (-1);
1275184Sek110237 	}
1285184Sek110237 #else
1295184Sek110237 	if ((pid = fork()) < 0) {
1305184Sek110237 		filebench_log(LOG_ERROR,
1315184Sek110237 		    "procflow_createproc fork failed: %s",
1325184Sek110237 		    strerror(errno));
1335184Sek110237 		return (-1);
1345184Sek110237 	}
1355184Sek110237 #endif /* HAVE_FORK1 */
1365184Sek110237 
1376084Saw148015 	/* if child, start up new copy of filebench */
1385184Sek110237 	if (pid == 0) {
1395184Sek110237 #ifdef USE_SYSTEM
1405184Sek110237 		char syscmd[1024];
1415184Sek110237 #endif
1425184Sek110237 
1435184Sek110237 		(void) sigignore(SIGINT);
1445184Sek110237 		filebench_log(LOG_DEBUG_SCRIPT,
1455184Sek110237 		    "Starting %s-%d", procflow->pf_name,
1465184Sek110237 		    procflow->pf_instance);
1475184Sek110237 		/* Child */
1485184Sek110237 
1495184Sek110237 #ifdef USE_SYSTEM
1505184Sek110237 		(void) snprintf(syscmd, sizeof (syscmd), "%s -a %s -i %s -s %s",
1515184Sek110237 		    execname,
1525184Sek110237 		    procname,
1535184Sek110237 		    instance,
1545184Sek110237 		    shmaddr);
1555184Sek110237 		if (system(syscmd) < 0) {
1565184Sek110237 			filebench_log(LOG_ERROR,
1575184Sek110237 			    "procflow exec proc failed: %s",
1585184Sek110237 			    strerror(errno));
1595184Sek110237 			filebench_shutdown(1);
1605184Sek110237 		}
1615184Sek110237 
1625184Sek110237 #else
1636613Sek110237 		if (execlp(execname, procname, "-a", procname, "-i",
1645184Sek110237 		    instance, "-s", shmaddr, "-m", shmpath, NULL) < 0) {
1655184Sek110237 			filebench_log(LOG_ERROR,
1665184Sek110237 			    "procflow exec proc failed: %s",
1675184Sek110237 			    strerror(errno));
1685184Sek110237 			filebench_shutdown(1);
1695184Sek110237 		}
1705184Sek110237 #endif
1715184Sek110237 		exit(1);
1725184Sek110237 	} else {
1736084Saw148015 		/* if parent, save pid and return */
1745184Sek110237 		procflow->pf_pid = pid;
1755184Sek110237 	}
1765184Sek110237 #else
1775184Sek110237 	procflow->pf_running = 1;
1785184Sek110237 	if (pthread_create(&procflow->pf_tid, NULL,
1795184Sek110237 	    (void *(*)(void*))threadflow_init, procflow) != 0) {
1805184Sek110237 		filebench_log(LOG_ERROR, "proc-thread create failed");
1815184Sek110237 		procflow->pf_running = 0;
1825184Sek110237 	}
1835184Sek110237 #endif
1845184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "procflow_createproc created pid %d",
1855184Sek110237 	    pid);
1865184Sek110237 
1875184Sek110237 	return (0);
1885184Sek110237 }
1895184Sek110237 
1905184Sek110237 /*
1915184Sek110237  * Find a procflow of name "name" and instance "instance" on the
1926391Saw148015  * master procflow list, filebench_shm->shm_proclist. Locks the list
1935184Sek110237  * and scans through it searching for a procflow with matching
1945184Sek110237  * name and instance number. If found returns a pointer to the
1955184Sek110237  * procflow, otherwise returns NULL.
1965184Sek110237  */
1975184Sek110237 static procflow_t *
1985184Sek110237 procflow_find(char *name, int instance)
1995184Sek110237 {
2006391Saw148015 	procflow_t *procflow = filebench_shm->shm_proclist;
2015184Sek110237 
2025184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "Find: (%s-%d) proclist = %zx",
2035184Sek110237 	    name, instance, procflow);
2045184Sek110237 
2056391Saw148015 	(void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock);
2065184Sek110237 
2075184Sek110237 	while (procflow) {
2085184Sek110237 		filebench_log(LOG_DEBUG_IMPL, "Find: (%s-%d) == (%s-%d)",
2095184Sek110237 		    name, instance,
2105184Sek110237 		    procflow->pf_name,
2115184Sek110237 		    procflow->pf_instance);
2125184Sek110237 		if ((strcmp(name, procflow->pf_name) == 0) &&
2135184Sek110237 		    (instance == procflow->pf_instance)) {
2145184Sek110237 
2156391Saw148015 			(void) ipc_mutex_unlock(
2166391Saw148015 			    &filebench_shm->shm_procflow_lock);
2175184Sek110237 
2185184Sek110237 			return (procflow);
2195184Sek110237 		}
2205184Sek110237 		procflow = procflow->pf_next;
2215184Sek110237 	}
2225184Sek110237 
2236391Saw148015 	(void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock);
2245184Sek110237 
2255184Sek110237 	return (NULL);
2265184Sek110237 }
2275184Sek110237 
2285184Sek110237 static int
2295184Sek110237 procflow_create_all_procs(void)
2305184Sek110237 {
2316391Saw148015 	procflow_t *procflow = filebench_shm->shm_proclist;
2325184Sek110237 	int	ret = 0;
2335184Sek110237 
2345184Sek110237 	while (procflow) {
2356212Saw148015 		int i, instances;
2365184Sek110237 
2376212Saw148015 		instances = (int)avd_get_int(procflow->pf_instances);
2386212Saw148015 		filebench_log(LOG_INFO, "Starting %d %s instances",
2396212Saw148015 		    instances, procflow->pf_name);
2405184Sek110237 
2415184Sek110237 		/* Create instances of procflow */
2426212Saw148015 		for (i = 0; (i < instances) && (ret == 0); i++) {
2435184Sek110237 			procflow_t *newproc;
2445184Sek110237 
2455184Sek110237 			/* Create processes */
2465184Sek110237 			newproc =
2476391Saw148015 			    procflow_define_common(&filebench_shm->shm_proclist,
2485184Sek110237 			    procflow->pf_name, procflow, i + 1);
2495184Sek110237 			if (newproc == NULL)
2505184Sek110237 				ret = -1;
2515184Sek110237 			else
2525184Sek110237 				ret = procflow_createproc(newproc);
2535184Sek110237 		}
2545184Sek110237 
2555184Sek110237 		if (ret != 0)
2565184Sek110237 			break;
2575184Sek110237 
2585184Sek110237 		procflow = procflow->pf_next;
2595184Sek110237 	}
2605184Sek110237 
2615184Sek110237 	return (ret);
2625184Sek110237 }
2635184Sek110237 
2645184Sek110237 #ifdef USE_PROCESS_MODEL
2655184Sek110237 /*
2665184Sek110237  * Used to start up threads on a child process, when filebench is
2675184Sek110237  * compiled to support multiple processes. Uses the name string
2685184Sek110237  * and instance number passed to the child to find the previously
2695184Sek110237  * created procflow entity. Then uses nice() to reduce the
2705184Sek110237  * process' priority by at least 10. A call is then made to
2715184Sek110237  * threadflow_init() which creates and runs the process' threads
2725184Sek110237  * and flowops to completion. When threadflow_init() returns,
2735184Sek110237  * a call to exit() terminates the child process.
2745184Sek110237  */
2755184Sek110237 int
2765184Sek110237 procflow_exec(char *name, int instance)
2775184Sek110237 {
2785184Sek110237 	procflow_t *procflow;
2795184Sek110237 	int proc_nice;
2805184Sek110237 #ifdef HAVE_SETRLIMIT
2815184Sek110237 	struct rlimit rlp;
2825184Sek110237 #endif
2836084Saw148015 	int ret;
2845184Sek110237 
2855184Sek110237 	filebench_log(LOG_DEBUG_IMPL,
2865184Sek110237 	    "procflow_execproc %s-%d",
2875184Sek110237 	    name, instance);
2885184Sek110237 
2895184Sek110237 	if ((procflow = procflow_find(name, instance)) == NULL) {
2905184Sek110237 		filebench_log(LOG_ERROR,
2915184Sek110237 		    "procflow_exec could not find %s-%d",
2925184Sek110237 		    name, instance);
2935184Sek110237 		return (-1);
2945184Sek110237 	}
2956084Saw148015 
2966084Saw148015 	/* set the slave process' procflow pointer */
2976084Saw148015 	my_procflow = procflow;
2986084Saw148015 
2996084Saw148015 	/* set its pid from value stored by main() */
3006084Saw148015 	procflow->pf_pid = my_pid;
3015184Sek110237 
3025184Sek110237 	filebench_log(LOG_DEBUG_IMPL,
3036084Saw148015 	    "Started up %s pid %d", procflow->pf_name, my_pid);
3045184Sek110237 
3055184Sek110237 	filebench_log(LOG_DEBUG_IMPL,
3065184Sek110237 	    "nice = %llx", procflow->pf_nice);
3075184Sek110237 
3086212Saw148015 	proc_nice = avd_get_int(procflow->pf_nice);
3095184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "Setting pri of %s-%d to %d",
3105184Sek110237 	    name, instance, nice(proc_nice + 10));
3115184Sek110237 
3125184Sek110237 	procflow->pf_running = 1;
3135184Sek110237 
3145184Sek110237 #ifdef HAVE_SETRLIMIT
3155184Sek110237 	/* Get resource limits */
3165184Sek110237 	(void) getrlimit(RLIMIT_NOFILE, &rlp);
3175184Sek110237 	filebench_log(LOG_DEBUG_SCRIPT, "%d file descriptors", rlp.rlim_cur);
3185184Sek110237 #endif
3195184Sek110237 
3206084Saw148015 	if ((ret = threadflow_init(procflow)) != FILEBENCH_OK) {
3216084Saw148015 		if (ret < 0) {
3226084Saw148015 			filebench_log(LOG_ERROR,
3236084Saw148015 			    "Failed to start threads for %s pid %d",
3246084Saw148015 			    procflow->pf_name, my_pid);
3256084Saw148015 		}
3266084Saw148015 	} else {
3276084Saw148015 		filebench_log(LOG_DEBUG_IMPL,
3286084Saw148015 		    "procflow_createproc exiting...");
3295184Sek110237 	}
3306084Saw148015 
3316701Saw148015 	(void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock);
3326701Saw148015 	filebench_shm->shm_procs_running --;
3336701Saw148015 	(void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock);
3345184Sek110237 	procflow->pf_running = 0;
3355184Sek110237 
3366084Saw148015 	return (ret);
3375184Sek110237 }
3385184Sek110237 
3395184Sek110237 
3405184Sek110237 /*
3415184Sek110237  * A special thread from which worker (child) processes are created, and
3425184Sek110237  * which then waits for worker processes to die. If they die unexpectedly,
3435184Sek110237  * that is not a simple exit(0), then report an error and terminate the
3445184Sek110237  * run.
3455184Sek110237  */
3465184Sek110237 /* ARGSUSED */
3475184Sek110237 static void *
3485184Sek110237 procflow_createnwait(void *nothing)
3495184Sek110237 {
3506391Saw148015 	(void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock);
3515184Sek110237 
3525184Sek110237 	if (procflow_create_all_procs() == 0)
3535184Sek110237 		cnw_wait = CNW_DONE;
3545184Sek110237 	else
3555184Sek110237 		cnw_wait = CNW_ERROR;
3565184Sek110237 
357*7556SAndrew.W.Wilson@sun.com 	if (pthread_cond_signal(&filebench_shm->shm_procflow_procs_cv) != 0)
3585184Sek110237 		exit(1);
3595184Sek110237 
3606391Saw148015 	(void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock);
3615184Sek110237 
3625184Sek110237 	/* CONSTCOND */
3635184Sek110237 	while (1) {
3645184Sek110237 		siginfo_t status;
3655184Sek110237 
3665184Sek110237 		/* wait for any child process to exit */
3675184Sek110237 		if (waitid(P_ALL, 0, &status, WEXITED) != 0)
3685184Sek110237 			pthread_exit(0);
3695184Sek110237 
3706701Saw148015 		(void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock);
3715184Sek110237 		/* if normal shutdown in progress, just quit */
3726391Saw148015 		if (filebench_shm->shm_f_abort)
3736701Saw148015 			(void) ipc_mutex_unlock(
3746701Saw148015 			    &filebench_shm->shm_procflow_lock);
3755184Sek110237 			pthread_exit(0);
3765184Sek110237 
3776701Saw148015 		/* if nothing running, exit */
3786701Saw148015 		if (filebench_shm->shm_procs_running == 0) {
3796701Saw148015 			filebench_shm->shm_f_abort = FILEBENCH_ABORT_RSRC;
3806701Saw148015 			(void) ipc_mutex_unlock(
3816701Saw148015 			    &filebench_shm->shm_procflow_lock);
3826701Saw148015 			pthread_exit(0);
3836701Saw148015 		}
3846701Saw148015 		(void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock);
3856701Saw148015 
3865184Sek110237 		if (status.si_code == CLD_EXITED) {
3875184Sek110237 			/* A process called exit(); check returned status */
3885184Sek110237 			if (status.si_status != 0) {
3895184Sek110237 				filebench_log(LOG_ERROR,
3905184Sek110237 				    "Unexpected Process termination; exiting",
3915184Sek110237 				    status.si_status);
3925184Sek110237 				filebench_shutdown(1);
3935184Sek110237 			}
3945184Sek110237 		} else {
3955184Sek110237 			/* A process quit because of some fatal error */
3965184Sek110237 			filebench_log(LOG_ERROR,
3975184Sek110237 			    "Unexpected Process termination Code %d, Errno %d",
3985184Sek110237 			    status.si_code, status.si_errno);
3995184Sek110237 			filebench_shutdown(1);
4005184Sek110237 		}
4015184Sek110237 
4025184Sek110237 	}
4035184Sek110237 	/* NOTREACHED */
4045184Sek110237 	return (NULL);
4055184Sek110237 }
4065184Sek110237 #endif	/* USE_PROCESS_MODEL */
4075184Sek110237 
4085184Sek110237 /*
4095184Sek110237  * Iterates through proclist, the master list of procflows,
4105184Sek110237  * creating the number of instances of each procflow specified
4115184Sek110237  * by its pf_instance attribute. Returns 0 on success, or -1
4125184Sek110237  * times the number of procflow instances that were not
4135184Sek110237  * successfully created.
4145184Sek110237  */
4155184Sek110237 int
4165184Sek110237 procflow_init(void)
4175184Sek110237 {
4186391Saw148015 	procflow_t *procflow = filebench_shm->shm_proclist;
4195184Sek110237 	pthread_t tid;
4205184Sek110237 	int ret = 0;
4215184Sek110237 
4225184Sek110237 	filebench_log(LOG_DEBUG_IMPL,
4236286Saw148015 	    "procflow_init %s, %llu",
4246286Saw148015 	    procflow->pf_name,
4256286Saw148015 	    (u_longlong_t)avd_get_int(procflow->pf_instances));
4265184Sek110237 
4275184Sek110237 #ifdef USE_PROCESS_MODEL
4285184Sek110237 
4295184Sek110237 	if ((pthread_create(&tid, NULL, procflow_createnwait, NULL)) != 0)
4305184Sek110237 		return (ret);
4315184Sek110237 
4326391Saw148015 	(void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock);
4335184Sek110237 
434*7556SAndrew.W.Wilson@sun.com 	if ((ret = pthread_cond_wait(&filebench_shm->shm_procflow_procs_cv,
4356391Saw148015 	    &filebench_shm->shm_procflow_lock)) != 0)
4365184Sek110237 		return (ret);
4375184Sek110237 
4385184Sek110237 	if (cnw_wait == CNW_ERROR)
4395184Sek110237 		ret = -1;
4405184Sek110237 
4415184Sek110237 #else /* USE_PROCESS_MODEL */
4426391Saw148015 	(void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock);
4435184Sek110237 
4445184Sek110237 	ret = procflow_create_all_procs();
4455184Sek110237 #endif /* USE_PROCESS_MODEL */
4465184Sek110237 
4476391Saw148015 	(void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock);
4485184Sek110237 
4495184Sek110237 	return (ret);
4505184Sek110237 }
4515184Sek110237 
4525184Sek110237 #ifdef USE_PROCESS_MODEL
4535184Sek110237 /*
4545184Sek110237  * Waits for child processes to finish and returns their exit
4555184Sek110237  * status. Used by procflow_delete() when the process model is
4565184Sek110237  * enabled to wait for a deleted process to exit.
4575184Sek110237  */
4585184Sek110237 static void
4595184Sek110237 procflow_wait(pid_t pid)
4605184Sek110237 {
4615184Sek110237 	pid_t wpid;
4625184Sek110237 	int stat;
4635184Sek110237 
4645184Sek110237 	(void) waitpid(pid, &stat, 0);
4655184Sek110237 	while ((wpid = waitpid(getpid() * -1, &stat, WNOHANG)) > 0)
4666286Saw148015 		filebench_log(LOG_DEBUG_IMPL, "Waited for pid %d", (int)wpid);
4675184Sek110237 }
4685184Sek110237 #endif
4695184Sek110237 
4705184Sek110237 /*
4715184Sek110237  * Deletes the designated procflow and all its threadflows except
4725184Sek110237  * for FLOW_MASTER ones. Waits 10 seconds if the procflow is still
4735184Sek110237  * running, then kills the associated process. Finally it frees the
4746391Saw148015  * procflow entity. filebench_shm->shm_procflow_lock must be held on entry.
4755184Sek110237  *
4765184Sek110237  * If the designated procflow is not found on the list it returns -1 and
4775184Sek110237  * the procflow is not deleted. Otherwise it returns 0.
4785184Sek110237  */
4795184Sek110237 static int
4806084Saw148015 procflow_delete(procflow_t *procflow, int wait_cnt)
4815184Sek110237 {
4825184Sek110237 	procflow_t *entry;
4835184Sek110237 
4846084Saw148015 	threadflow_delete_all(&procflow->pf_threads, wait_cnt);
4855184Sek110237 
4865184Sek110237 	filebench_log(LOG_DEBUG_SCRIPT,
4875184Sek110237 	    "Deleted proc: (%s-%d) pid %d",
4885184Sek110237 	    procflow->pf_name,
4895184Sek110237 	    procflow->pf_instance,
4905184Sek110237 	    procflow->pf_pid);
4915184Sek110237 
4925184Sek110237 	while (procflow->pf_running == 1) {
4935184Sek110237 		filebench_log(LOG_DEBUG_SCRIPT,
4945184Sek110237 		    "Waiting for process %s-%d %d",
4955184Sek110237 		    procflow->pf_name,
4965184Sek110237 		    procflow->pf_instance,
4975184Sek110237 		    procflow->pf_pid);
4985184Sek110237 
4996084Saw148015 		if (wait_cnt) {
5006391Saw148015 			(void) ipc_mutex_unlock(
5016391Saw148015 			    &filebench_shm->shm_procflow_lock);
5025184Sek110237 			(void) sleep(1);
5036391Saw148015 			(void) ipc_mutex_lock(
5046391Saw148015 			    &filebench_shm->shm_procflow_lock);
5056084Saw148015 			wait_cnt--;
5065184Sek110237 			continue;
5075184Sek110237 		}
5085184Sek110237 #ifdef USE_PROCESS_MODEL
5095184Sek110237 		(void) kill(procflow->pf_pid, SIGKILL);
5105184Sek110237 		filebench_log(LOG_DEBUG_SCRIPT,
5116701Saw148015 		    "procflow_delete: Had to kill process %s-%d %d!",
5125184Sek110237 		    procflow->pf_name,
5135184Sek110237 		    procflow->pf_instance,
5145184Sek110237 		    procflow->pf_pid);
5155184Sek110237 		procflow->pf_running = 0;
5165184Sek110237 #endif
5175184Sek110237 	}
5185184Sek110237 
5195184Sek110237 #ifdef USE_PROCESS_MODEL
5205184Sek110237 	procflow_wait(procflow->pf_pid);
5215184Sek110237 #endif
5225184Sek110237 	/* remove entry from proclist */
5236391Saw148015 	entry = filebench_shm->shm_proclist;
5245184Sek110237 
5255184Sek110237 	/* unlink procflow entity from proclist */
5265184Sek110237 	if (entry == procflow) {
5275184Sek110237 		/* at head of list */
5286391Saw148015 		filebench_shm->shm_proclist = procflow->pf_next;
5295184Sek110237 	} else {
5305184Sek110237 		/* search list for procflow */
5315184Sek110237 		while (entry && entry->pf_next != procflow)
5325184Sek110237 			entry = entry->pf_next;
5335184Sek110237 
5345184Sek110237 		/* if entity found, unlink it */
5355184Sek110237 		if (entry == NULL)
5365184Sek110237 			return (-1);
5375184Sek110237 		else
5385184Sek110237 			entry->pf_next = procflow->pf_next;
5395184Sek110237 	}
5405184Sek110237 
5415184Sek110237 	/* free up the procflow entity */
5425184Sek110237 	ipc_free(FILEBENCH_PROCFLOW, (char *)procflow);
5435184Sek110237 	return (0);
5445184Sek110237 }
5455184Sek110237 
5465184Sek110237 
5475184Sek110237 /*
5485184Sek110237  * Waits till all threadflows are started, or a timeout occurs.
5495184Sek110237  * Checks through the list of procflows, waiting up to 30
5505184Sek110237  * seconds for each one to set its pf_running flag to 1. If not
5515184Sek110237  * set after 30 seconds, continues on to the next procflow
5525184Sek110237  * anyway after logging the fact. Once pf_running is set
5535184Sek110237  * to 1 for a given procflow or the timeout is reached,
5545184Sek110237  * threadflow_allstarted() is called to start the threads.
5556391Saw148015  * Returns 0 (OK), unless filebench_shm->shm_f_abort is signaled,
5565184Sek110237  * in which case it returns -1.
5575184Sek110237  */
5585184Sek110237 int
5595184Sek110237 procflow_allstarted()
5605184Sek110237 {
5616391Saw148015 	procflow_t *procflow = filebench_shm->shm_proclist;
5626084Saw148015 	int running_procs = 0;
5635184Sek110237 	int ret = 0;
5645184Sek110237 
5656391Saw148015 	(void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock);
5665184Sek110237 
5675184Sek110237 	(void) sleep(1);
5685184Sek110237 
5695184Sek110237 	while (procflow) {
5705184Sek110237 		int waits;
5715184Sek110237 
5725184Sek110237 		if (procflow->pf_instance &&
5735184Sek110237 		    (procflow->pf_instance == FLOW_MASTER)) {
5745184Sek110237 			procflow = procflow->pf_next;
5755184Sek110237 			continue;
5765184Sek110237 		}
5775184Sek110237 
5785184Sek110237 		waits = 10;
5795184Sek110237 		while (waits && procflow->pf_running == 0) {
5806391Saw148015 			(void) ipc_mutex_unlock(
5816391Saw148015 			    &filebench_shm->shm_procflow_lock);
5826391Saw148015 			if (filebench_shm->shm_f_abort == 1)
5835184Sek110237 				return (-1);
5845184Sek110237 
5855184Sek110237 			if (waits < 3)
5865184Sek110237 				filebench_log(LOG_INFO,
5875184Sek110237 				    "Waiting for process %s-%d %d",
5885184Sek110237 				    procflow->pf_name,
5895184Sek110237 				    procflow->pf_instance,
5905184Sek110237 				    procflow->pf_pid);
5915184Sek110237 
5925184Sek110237 			(void) sleep(3);
5935184Sek110237 			waits--;
5946391Saw148015 			(void) ipc_mutex_lock(
5956391Saw148015 			    &filebench_shm->shm_procflow_lock);
5965184Sek110237 		}
5975184Sek110237 
5985184Sek110237 		if (waits == 0)
5996084Saw148015 			filebench_log(LOG_INFO,
6006084Saw148015 			    "Failed to start process %s-%d",
6015184Sek110237 			    procflow->pf_name,
6025184Sek110237 			    procflow->pf_instance);
6035184Sek110237 
6046084Saw148015 		running_procs++;
6055184Sek110237 		threadflow_allstarted(procflow->pf_pid, procflow->pf_threads);
6065184Sek110237 
6075184Sek110237 		procflow = procflow->pf_next;
6085184Sek110237 	}
6096701Saw148015 	(void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock);
6106701Saw148015 	filebench_shm->shm_procs_running = running_procs;
6116701Saw148015 	(void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock);
6125184Sek110237 
6136391Saw148015 	(void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock);
6145184Sek110237 
6155184Sek110237 
6165184Sek110237 	return (ret);
6175184Sek110237 }
6185184Sek110237 
6195184Sek110237 
6205184Sek110237 /*
6216084Saw148015  * Sets the f_abort flag and clears the running count to stop
6225184Sek110237  * all the flowop execution threads from running. Iterates
6235184Sek110237  * through the procflow list and deletes all procflows except
6245184Sek110237  * for the FLOW_MASTER procflow. Resets the f_abort flag when
6255184Sek110237  * finished.
6266701Saw148015  *
6275184Sek110237  */
6285184Sek110237 void
6295184Sek110237 procflow_shutdown(void)
6305184Sek110237 {
6316391Saw148015 	procflow_t *procflow = filebench_shm->shm_proclist;
6326084Saw148015 	int wait_cnt;
6335184Sek110237 
6346701Saw148015 	(void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock);
635*7556SAndrew.W.Wilson@sun.com 	if (filebench_shm->shm_procs_running <= 0) {
6366701Saw148015 		/* No processes running, so no need to do anything */
6376701Saw148015 		(void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock);
6386701Saw148015 		return;
6396701Saw148015 	}
6406701Saw148015 	(void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock);
6416701Saw148015 
6426391Saw148015 	(void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock);
6436391Saw148015 	filebench_shm->shm_f_abort = 1;
6446084Saw148015 	wait_cnt = SHUTDOWN_WAIT_SECONDS;
6455184Sek110237 
6465184Sek110237 	while (procflow) {
6475184Sek110237 		if (procflow->pf_instance &&
6485184Sek110237 		    (procflow->pf_instance == FLOW_MASTER)) {
6495184Sek110237 			procflow = procflow->pf_next;
6505184Sek110237 			continue;
6515184Sek110237 		}
6525184Sek110237 		filebench_log(LOG_DEBUG_IMPL, "Deleting process %s-%d %d",
6535184Sek110237 		    procflow->pf_name,
6545184Sek110237 		    procflow->pf_instance,
6555184Sek110237 		    procflow->pf_pid);
6566084Saw148015 		(void) procflow_delete(procflow, wait_cnt);
6575184Sek110237 		procflow = procflow->pf_next;
6586084Saw148015 		/* grow more impatient */
6596084Saw148015 		if (wait_cnt)
6606084Saw148015 			wait_cnt--;
6615184Sek110237 	}
6625184Sek110237 
6636391Saw148015 	filebench_shm->shm_f_abort = 0;
6645184Sek110237 
6656391Saw148015 	(void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock);
666*7556SAndrew.W.Wilson@sun.com 
667*7556SAndrew.W.Wilson@sun.com 	/* indicate all processes are stopped, even if some are "stuck" */
668*7556SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock);
669*7556SAndrew.W.Wilson@sun.com 	filebench_shm->shm_procs_running = 0;
670*7556SAndrew.W.Wilson@sun.com 	(void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock);
6715184Sek110237 }
6725184Sek110237 
6735184Sek110237 
6745184Sek110237 /*
6755184Sek110237  * Create an in-memory process object. Allocates a procflow
6765184Sek110237  * entity, initialized from the "inherit" procflow if supplied.
6775184Sek110237  * The name and instance number are set from the supplied name
6785184Sek110237  * and instance number and the procflow is added to the head of
6795184Sek110237  * the master procflow list. Returns pointer to the allocated
6805184Sek110237  * procflow, or NULL if a name isn't supplied or the procflow
6815184Sek110237  * entity cannot be allocated.
6825184Sek110237  *
6836391Saw148015  * The calling routine must hold the filebench_shm->shm_procflow_lock.
6845184Sek110237  */
6855184Sek110237 static procflow_t *
6865184Sek110237 procflow_define_common(procflow_t **list, char *name,
6875184Sek110237     procflow_t *inherit, int instance)
6885184Sek110237 {
6895184Sek110237 	procflow_t *procflow;
6905184Sek110237 
6915184Sek110237 	if (name == NULL)
6925184Sek110237 		return (NULL);
6935184Sek110237 
6945184Sek110237 	procflow = (procflow_t *)ipc_malloc(FILEBENCH_PROCFLOW);
6955184Sek110237 
6965184Sek110237 	if (procflow == NULL)
6975184Sek110237 		return (NULL);
6985184Sek110237 
6995184Sek110237 	if (inherit)
7005184Sek110237 		(void) memcpy(procflow, inherit, sizeof (procflow_t));
7015184Sek110237 	else
7025184Sek110237 		(void) memset(procflow, 0, sizeof (procflow_t));
7035184Sek110237 
7045184Sek110237 	procflow->pf_instance = instance;
7055184Sek110237 	(void) strcpy(procflow->pf_name, name);
7065184Sek110237 
7075184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "defining process %s-%d", name, instance);
7085184Sek110237 
7095184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "process %s-%d proclist %zx",
7106391Saw148015 	    name, instance, filebench_shm->shm_proclist);
7115184Sek110237 	/* Add procflow to list, lock is being held already */
7125184Sek110237 	if (*list == NULL) {
7135184Sek110237 		*list = procflow;
7145184Sek110237 		procflow->pf_next = NULL;
7155184Sek110237 	} else {
7165184Sek110237 		procflow->pf_next = *list;
7175184Sek110237 		*list = procflow;
7185184Sek110237 	}
7195184Sek110237 	filebench_log(LOG_DEBUG_IMPL, "process %s-%d proclist %zx",
7206391Saw148015 	    name, instance, filebench_shm->shm_proclist);
7215184Sek110237 
7225184Sek110237 	return (procflow);
7235184Sek110237 }
7245184Sek110237 
7255184Sek110237 /*
7265184Sek110237  * Create an in-memory process object as described by the syntax.
7276391Saw148015  * Acquires the filebench_shm->shm_procflow_lock and calls
7285184Sek110237  * procflow_define_common() to create and initialize a
7295184Sek110237  * FLOW_MASTER procflow entity from the optional "inherit"
7305184Sek110237  * procflow with the given name and configured for "instances"
7315184Sek110237  * number of worker procflows. Currently only called from
7325184Sek110237  * parser_proc_define().
7335184Sek110237  */
7345184Sek110237 procflow_t *
7356212Saw148015 procflow_define(char *name, procflow_t *inherit, avd_t instances)
7365184Sek110237 {
7375184Sek110237 	procflow_t *procflow;
7385184Sek110237 
7396391Saw148015 	(void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock);
7405184Sek110237 
7416391Saw148015 	procflow = procflow_define_common(&filebench_shm->shm_proclist,
7425184Sek110237 	    name, inherit, FLOW_MASTER);
7435184Sek110237 	procflow->pf_instances = instances;
7445184Sek110237 
7456391Saw148015 	(void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock);
7465184Sek110237 
7475184Sek110237 	return (procflow);
7485184Sek110237 }
749