xref: /onnv-gate/usr/src/cmd/filebench/common/procflow.c (revision 9326:475779da8c08)
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