Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  *
     25  * Portions Copyright 2008 Denis Cheng
     26  */
     27 
     28 #include <signal.h>
     29 #include <fcntl.h>
     30 #include <sys/stat.h>
     31 #include <sys/wait.h>
     32 
     33 #include "filebench.h"
     34 #include "procflow.h"
     35 #include "flowop.h"
     36 #include "ipc.h"
     37 
     38 /* pid and procflow pointer for this process */
     39 pid_t my_pid;
     40 procflow_t *my_procflow = NULL;
     41 
     42 static procflow_t *procflow_define_common(procflow_t **list, char *name,
     43     procflow_t *inherit, int instance);
     44 static void procflow_sleep(procflow_t *procflow, int wait_cnt);
     45 
     46 #ifdef USE_PROCESS_MODEL
     47 
     48 static enum create_n_wait {
     49 	CNW_DONE,
     50 	CNW_ERROR
     51 } cnw_wait;
     52 
     53 #endif	/* USE_PROCESS_MODEL */
     54 
     55 
     56 /*
     57  * Procflows are filebench entities which manage processes. Each
     58  * worker procflow spawns a separate filebench process, with attributes
     59  * inherited from a FLOW_MASTER procflow created during f model language
     60  * parsing. This section contains routines to define, create, control,
     61  * and delete procflows.
     62  *
     63  * Each process defined in the f model creates a FLOW_MASTER
     64  * procflow which encapsulates the defined attributes, and threads of
     65  * the f process, including the number of instances to create. At
     66  * runtime, a worker procflow instance with an associated filebench
     67  * process is created, which runs until told to quite by the original
     68  * filebench process or is specifically deleted.
     69  */
     70 
     71 
     72 /*
     73  * Prints a summary of the syntax for setting procflow parameters.
     74  */
     75 void
     76 procflow_usage(void)
     77 {
     78 	(void) fprintf(stderr,
     79 	    "define process name=<name>[,instances=<count>]\n");
     80 	(void) fprintf(stderr, "{\n");
     81 	(void) fprintf(stderr, "  thread ...\n");
     82 	(void) fprintf(stderr, "  thread ...\n");
     83 	(void) fprintf(stderr, "  thread ...\n");
     84 	(void) fprintf(stderr, "}\n");
     85 	(void) fprintf(stderr, "\n");
     86 	(void) fprintf(stderr, "\n");
     87 }
     88 
     89 /*
     90  * If filebench has been compiled to support multiple processes
     91  * (USE_PROCESS_MODEL defined), this routine forks a child
     92  * process and uses either system() or exec() to start up a new
     93  * instance of filebench, passing it the procflow name, instance
     94  * number and shared memory region address.
     95  * If USE_PROCESS_MODEL is NOT defined, then the routine
     96  * just creates a child thread which begins executing
     97  * threadflow_init() for the specified procflow.
     98  */
     99 static int
    100 procflow_createproc(procflow_t *procflow)
    101 {
    102 	char instance[128];
    103 	char shmaddr[128];
    104 	char procname[128];
    105 	pid_t pid;
    106 
    107 #ifdef USE_PROCESS_MODEL
    108 
    109 	(void) snprintf(instance, sizeof (instance), "%d",
    110 	    procflow->pf_instance);
    111 	(void) snprintf(procname, sizeof (procname), "%s", procflow->pf_name);
    112 #if defined(_LP64) || (__WORDSIZE == 64)
    113 	(void) snprintf(shmaddr, sizeof (shmaddr), "%llx", filebench_shm);
    114 #else
    115 	(void) snprintf(shmaddr, sizeof (shmaddr), "%x", filebench_shm);
    116 #endif
    117 	filebench_log(LOG_DEBUG_IMPL, "creating process %s",
    118 	    procflow->pf_name);
    119 
    120 	procflow->pf_running = 0;
    121 
    122 #ifdef HAVE_FORK1
    123 	if ((pid = fork1()) < 0) {
    124 		filebench_log(LOG_ERROR,
    125 		    "procflow_createproc fork failed: %s",
    126 		    strerror(errno));
    127 		return (-1);
    128 	}
    129 #else
    130 	if ((pid = fork()) < 0) {
    131 		filebench_log(LOG_ERROR,
    132 		    "procflow_createproc fork failed: %s",
    133 		    strerror(errno));
    134 		return (-1);
    135 	}
    136 #endif /* HAVE_FORK1 */
    137 
    138 	/* if child, start up new copy of filebench */
    139 	if (pid == 0) {
    140 #ifdef USE_SYSTEM
    141 		char syscmd[1024];
    142 #endif
    143 
    144 		(void) sigignore(SIGINT);
    145 		filebench_log(LOG_DEBUG_SCRIPT,
    146 		    "Starting %s-%d", procflow->pf_name,
    147 		    procflow->pf_instance);
    148 		/* Child */
    149 
    150 #ifdef USE_SYSTEM
    151 		(void) snprintf(syscmd, sizeof (syscmd), "%s -a %s -i %s -s %s",
    152 		    execname,
    153 		    procname,
    154 		    instance,
    155 		    shmaddr);
    156 		if (system(syscmd) < 0) {
    157 			filebench_log(LOG_ERROR,
    158 			    "procflow exec proc failed: %s",
    159 			    strerror(errno));
    160 			filebench_shutdown(1);
    161 		}
    162 
    163 #else
    164 		if (execlp(execname, procname, "-a", procname, "-i",
    165 		    instance, "-s", shmaddr, "-m", shmpath, NULL) < 0) {
    166 			filebench_log(LOG_ERROR,
    167 			    "procflow exec proc failed: %s",
    168 			    strerror(errno));
    169 			filebench_shutdown(1);
    170 		}
    171 #endif
    172 		exit(1);
    173 	} else {
    174 		/* if parent, save pid and return */
    175 		procflow->pf_pid = pid;
    176 	}
    177 #else
    178 	procflow->pf_running = 1;
    179 	if (pthread_create(&procflow->pf_tid, NULL,
    180 	    (void *(*)(void*))threadflow_init, procflow) != 0) {
    181 		filebench_log(LOG_ERROR, "proc-thread create failed");
    182 		procflow->pf_running = 0;
    183 	}
    184 #endif
    185 	filebench_log(LOG_DEBUG_IMPL, "procflow_createproc created pid %d",
    186 	    pid);
    187 
    188 	return (0);
    189 }
    190 
    191 /*
    192  * Find a procflow of name "name" and instance "instance" on the
    193  * master procflow list, filebench_shm->shm_proclist. Locks the list
    194  * and scans through it searching for a procflow with matching
    195  * name and instance number. If found returns a pointer to the
    196  * procflow, otherwise returns NULL.
    197  */
    198 static procflow_t *
    199 procflow_find(char *name, int instance)
    200 {
    201 	procflow_t *procflow = filebench_shm->shm_proclist;
    202 
    203 	filebench_log(LOG_DEBUG_IMPL, "Find: (%s-%d) proclist = %zx",
    204 	    name, instance, procflow);
    205 
    206 	(void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock);
    207 
    208 	while (procflow) {
    209 		filebench_log(LOG_DEBUG_IMPL, "Find: (%s-%d) == (%s-%d)",
    210 		    name, instance,
    211 		    procflow->pf_name,
    212 		    procflow->pf_instance);
    213 		if ((strcmp(name, procflow->pf_name) == 0) &&
    214 		    (instance == procflow->pf_instance)) {
    215 
    216 			(void) ipc_mutex_unlock(
    217 			    &filebench_shm->shm_procflow_lock);
    218 
    219 			return (procflow);
    220 		}
    221 		procflow = procflow->pf_next;
    222 	}
    223 
    224 	(void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock);
    225 
    226 	return (NULL);
    227 }
    228 
    229 static int
    230 procflow_create_all_procs(void)
    231 {
    232 	procflow_t *procflow = filebench_shm->shm_proclist;
    233 	int	ret = 0;
    234 
    235 	while (procflow) {
    236 		int i, instances;
    237 
    238 		instances = (int)avd_get_int(procflow->pf_instances);
    239 		filebench_log(LOG_INFO, "Starting %d %s instances",
    240 		    instances, procflow->pf_name);
    241 
    242 		/* Create instances of procflow */
    243 		for (i = 0; (i < instances) && (ret == 0); i++) {
    244 			procflow_t *newproc;
    245 
    246 			/* Create processes */
    247 			newproc =
    248 			    procflow_define_common(&filebench_shm->shm_proclist,
    249 			    procflow->pf_name, procflow, i + 1);
    250 			if (newproc == NULL)
    251 				ret = -1;
    252 			else
    253 				ret = procflow_createproc(newproc);
    254 		}
    255 
    256 		if (ret != 0)
    257 			break;
    258 
    259 		procflow = procflow->pf_next;
    260 	}
    261 
    262 	return (ret);
    263 }
    264 
    265 #ifdef USE_PROCESS_MODEL
    266 /*
    267  * Used to start up threads on a child process, when filebench is
    268  * compiled to support multiple processes. Uses the name string
    269  * and instance number passed to the child to find the previously
    270  * created procflow entity. Then uses nice() to reduce the
    271  * process' priority by at least 10. A call is then made to
    272  * threadflow_init() which creates and runs the process' threads
    273  * and flowops to completion. When threadflow_init() returns,
    274  * a call to exit() terminates the child process.
    275  */
    276 int
    277 procflow_exec(char *name, int instance)
    278 {
    279 	procflow_t *procflow;
    280 	int proc_nice;
    281 #ifdef HAVE_SETRLIMIT
    282 	struct rlimit rlp;
    283 #endif
    284 	int ret;
    285 
    286 	filebench_log(LOG_DEBUG_IMPL,
    287 	    "procflow_execproc %s-%d",
    288 	    name, instance);
    289 
    290 	if ((procflow = procflow_find(name, instance)) == NULL) {
    291 		filebench_log(LOG_ERROR,
    292 		    "procflow_exec could not find %s-%d",
    293 		    name, instance);
    294 		return (-1);
    295 	}
    296 
    297 	/* set the slave process' procflow pointer */
    298 	my_procflow = procflow;
    299 
    300 	/* set its pid from value stored by main() */
    301 	procflow->pf_pid = my_pid;
    302 
    303 	filebench_log(LOG_DEBUG_IMPL,
    304 	    "Started up %s pid %d", procflow->pf_name, my_pid);
    305 
    306 	filebench_log(LOG_DEBUG_IMPL,
    307 	    "nice = %llx", procflow->pf_nice);
    308 
    309 	proc_nice = avd_get_int(procflow->pf_nice);
    310 	filebench_log(LOG_DEBUG_IMPL, "Setting pri of %s-%d to %d",
    311 	    name, instance, nice(proc_nice + 10));
    312 
    313 	procflow->pf_running = 1;
    314 
    315 #ifdef HAVE_SETRLIMIT
    316 	/* Get resource limits */
    317 	(void) getrlimit(RLIMIT_NOFILE, &rlp);
    318 	filebench_log(LOG_DEBUG_SCRIPT, "%d file descriptors", rlp.rlim_cur);
    319 #endif
    320 
    321 	if ((ret = threadflow_init(procflow)) != FILEBENCH_OK) {
    322 		if (ret < 0) {
    323 			filebench_log(LOG_ERROR,
    324 			    "Failed to start threads for %s pid %d",
    325 			    procflow->pf_name, my_pid);
    326 		}
    327 	} else {
    328 		filebench_log(LOG_DEBUG_IMPL,
    329 		    "procflow_createproc exiting...");
    330 	}
    331 
    332 	(void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock);
    333 	filebench_shm->shm_procs_running --;
    334 	(void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock);
    335 	procflow->pf_running = 0;
    336 
    337 	return (ret);
    338 }
    339 
    340 
    341 /*
    342  * A special thread from which worker (child) processes are created, and
    343  * which then waits for worker processes to die. If they die unexpectedly,
    344  * that is not a simple exit(0), then report an error and terminate the
    345  * run.
    346  */
    347 /* ARGSUSED */
    348 static void *
    349 procflow_createnwait(void *nothing)
    350 {
    351 	(void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock);
    352 
    353 	if (procflow_create_all_procs() == 0)
    354 		cnw_wait = CNW_DONE;
    355 	else
    356 		cnw_wait = CNW_ERROR;
    357 
    358 	if (pthread_cond_signal(&filebench_shm->shm_procflow_procs_cv) != 0)
    359 		exit(1);
    360 
    361 	(void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock);
    362 
    363 	/* CONSTCOND */
    364 	while (1) {
    365 		siginfo_t status;
    366 
    367 		/* wait for any child process to exit */
    368 		if (waitid(P_ALL, 0, &status, WEXITED) != 0)
    369 			pthread_exit(0);
    370 
    371 		(void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock);
    372 		/* if normal shutdown in progress, just quit */
    373 		if (filebench_shm->shm_f_abort) {
    374 			(void) ipc_mutex_unlock(
    375 			    &filebench_shm->shm_procflow_lock);
    376 			pthread_exit(0);
    377 		}
    378 
    379 		/* if nothing running, exit */
    380 		if (filebench_shm->shm_procs_running == 0) {
    381 			filebench_shm->shm_f_abort = FILEBENCH_ABORT_RSRC;
    382 			(void) ipc_mutex_unlock(
    383 			    &filebench_shm->shm_procflow_lock);
    384 			pthread_exit(0);
    385 		}
    386 		(void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock);
    387 
    388 		if (status.si_code == CLD_EXITED) {
    389 			/* A process called exit(); check returned status */
    390 			if (status.si_status != 0) {
    391 				filebench_log(LOG_ERROR,
    392 				    "Unexpected Process termination; exiting",
    393 				    status.si_status);
    394 				filebench_shutdown(1);
    395 			}
    396 		} else {
    397 			/* A process quit because of some fatal error */
    398 			filebench_log(LOG_ERROR,
    399 			    "Unexpected Process termination Code %d, Errno %d",
    400 			    status.si_code, status.si_errno);
    401 			filebench_shutdown(1);
    402 		}
    403 
    404 	}
    405 	/* NOTREACHED */
    406 	return (NULL);
    407 }
    408 
    409 /*
    410  * Cancel all threads within a processes, as well as the process itself.
    411  * Called by ^c or by sig_kill
    412  */
    413 /* ARGSUSED */
    414 static void
    415 procflow_cancel(int arg1)
    416 {
    417 	filebench_log(LOG_DEBUG_IMPL, "Process signal handler on pid %",
    418 	    my_procflow->pf_pid);
    419 
    420 	procflow_sleep(my_procflow, SHUTDOWN_WAIT_SECONDS);
    421 
    422 	threadflow_delete_all(&my_procflow->pf_threads);
    423 
    424 	/* quit the main procflow thread and hence the process */
    425 	exit(0);
    426 }
    427 
    428 #endif	/* USE_PROCESS_MODEL */
    429 
    430 /*
    431  * Iterates through proclist, the master list of procflows,
    432  * creating the number of instances of each procflow specified
    433  * by its pf_instance attribute. Returns 0 on success, or -1
    434  * times the number of procflow instances that were not
    435  * successfully created.
    436  */
    437 int
    438 procflow_init(void)
    439 {
    440 	procflow_t *procflow = filebench_shm->shm_proclist;
    441 	pthread_t tid;
    442 	int ret = 0;
    443 
    444 	if (procflow == NULL) {
    445 		filebench_log(LOG_ERROR, "Workload has no processes");
    446 		return (FILEBENCH_ERROR);
    447 	}
    448 
    449 	filebench_log(LOG_DEBUG_IMPL,
    450 	    "procflow_init %s, %llu",
    451 	    procflow->pf_name,
    452 	    (u_longlong_t)avd_get_int(procflow->pf_instances));
    453 
    454 #ifdef USE_PROCESS_MODEL
    455 	if ((pthread_create(&tid, NULL, procflow_createnwait, NULL)) != 0)
    456 		return (ret);
    457 
    458 	(void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock);
    459 
    460 	(void) signal(SIGUSR1, procflow_cancel);
    461 
    462 	if ((ret = pthread_cond_wait(&filebench_shm->shm_procflow_procs_cv,
    463 	    &filebench_shm->shm_procflow_lock)) != 0)
    464 		return (ret);
    465 
    466 	if (cnw_wait == CNW_ERROR)
    467 		ret = -1;
    468 
    469 #else /* USE_PROCESS_MODEL */
    470 	(void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock);
    471 
    472 	ret = procflow_create_all_procs();
    473 #endif /* USE_PROCESS_MODEL */
    474 
    475 	(void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock);
    476 
    477 	return (ret);
    478 }
    479 
    480 #ifdef USE_PROCESS_MODEL
    481 /*
    482  * Waits for child processes to finish and returns their exit
    483  * status. Used by procflow_delete() when the process model is
    484  * enabled to wait for a deleted process to exit.
    485  */
    486 static void
    487 procflow_wait(pid_t pid)
    488 {
    489 	pid_t wpid;
    490 	int stat;
    491 
    492 	(void) waitpid(pid, &stat, 0);
    493 	while ((wpid = waitpid(getpid() * -1, &stat, WNOHANG)) > 0)
    494 		filebench_log(LOG_DEBUG_IMPL, "Waited for pid %d", (int)wpid);
    495 }
    496 #endif
    497 
    498 /*
    499  * Common routine to sleep for wait_cnt seconds or for pf_running to
    500  * go false. Checks once a second to see if pf_running has gone false.
    501  */
    502 static void
    503 procflow_sleep(procflow_t *procflow, int wait_cnt)
    504 {
    505 	while (procflow->pf_running & wait_cnt) {
    506 		(void) sleep(1);
    507 		wait_cnt--;
    508 	}
    509 }
    510 
    511 /*
    512  * Deletes the designated procflow. Finally it frees the
    513  * procflow entity. filebench_shm->shm_procflow_lock must be held on entry.
    514  *
    515  * If the designated procflow is not found on the list it returns -1 and
    516  * the procflow is not deleted. Otherwise it returns 0.
    517  */
    518 static int
    519 procflow_cleanup(procflow_t *procflow)
    520 {
    521 	procflow_t *entry;
    522 
    523 	filebench_log(LOG_DEBUG_SCRIPT,
    524 	    "Deleted proc: (%s-%d) pid %d",
    525 	    procflow->pf_name,
    526 	    procflow->pf_instance,
    527 	    procflow->pf_pid);
    528 
    529 	procflow->pf_running = 0;
    530 
    531 	/* remove entry from proclist */
    532 	entry = filebench_shm->shm_proclist;
    533 
    534 	/* unlink procflow entity from proclist */
    535 	if (entry == procflow) {
    536 		/* at head of list */
    537 		filebench_shm->shm_proclist = procflow->pf_next;
    538 	} else {
    539 		/* search list for procflow */
    540 		while (entry && entry->pf_next != procflow)
    541 			entry = entry->pf_next;
    542 
    543 		/* if entity found, unlink it */
    544 		if (entry == NULL)
    545 			return (-1);
    546 		else
    547 			entry->pf_next = procflow->pf_next;
    548 	}
    549 
    550 	/* free up the procflow entity */
    551 	ipc_free(FILEBENCH_PROCFLOW, (char *)procflow);
    552 	return (0);
    553 }
    554 
    555 
    556 /*
    557  * Waits till all threadflows are started, or a timeout occurs.
    558  * Checks through the list of procflows, waiting up to 30
    559  * seconds for each one to set its pf_running flag to 1. If not
    560  * set after 30 seconds, continues on to the next procflow
    561  * anyway after logging the fact. Once pf_running is set
    562  * to 1 for a given procflow or the timeout is reached,
    563  * threadflow_allstarted() is called to start the threads.
    564  * Returns 0 (OK), unless filebench_shm->shm_f_abort is signaled,
    565  * in which case it returns -1.
    566  */
    567 int
    568 procflow_allstarted()
    569 {
    570 	procflow_t *procflow = filebench_shm->shm_proclist;
    571 	int running_procs = 0;
    572 	int ret = 0;
    573 
    574 	(void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock);
    575 
    576 	(void) sleep(1);
    577 
    578 	while (procflow) {
    579 		int waits;
    580 
    581 		if (procflow->pf_instance &&
    582 		    (procflow->pf_instance == FLOW_MASTER)) {
    583 			procflow = procflow->pf_next;
    584 			continue;
    585 		}
    586 
    587 		waits = 10;
    588 		while (waits && procflow->pf_running == 0) {
    589 			(void) ipc_mutex_unlock(
    590 			    &filebench_shm->shm_procflow_lock);
    591 			if (filebench_shm->shm_f_abort == 1)
    592 				return (-1);
    593 
    594 			if (waits < 3)
    595 				filebench_log(LOG_INFO,
    596 				    "Waiting for process %s-%d %d",
    597 				    procflow->pf_name,
    598 				    procflow->pf_instance,
    599 				    procflow->pf_pid);
    600 
    601 			(void) sleep(3);
    602 			waits--;
    603 			(void) ipc_mutex_lock(
    604 			    &filebench_shm->shm_procflow_lock);
    605 		}
    606 
    607 		if (waits == 0)
    608 			filebench_log(LOG_INFO,
    609 			    "Failed to start process %s-%d",
    610 			    procflow->pf_name,
    611 			    procflow->pf_instance);
    612 
    613 		running_procs++;
    614 		threadflow_allstarted(procflow->pf_pid, procflow->pf_threads);
    615 
    616 		procflow = procflow->pf_next;
    617 	}
    618 	(void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock);
    619 	filebench_shm->shm_procs_running = running_procs;
    620 	(void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock);
    621 
    622 	(void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock);
    623 
    624 
    625 	return (ret);
    626 }
    627 
    628 
    629 /*
    630  * Sets the f_abort flag and clears the running count to stop
    631  * all the flowop execution threads from running. Iterates
    632  * through the procflow list and deletes all procflows except
    633  * for the FLOW_MASTER procflow. Resets the f_abort flag when
    634  * finished.
    635  *
    636  */
    637 void
    638 procflow_shutdown(void)
    639 {
    640 	procflow_t *procflow, *next_procflow;
    641 	int wait_cnt = SHUTDOWN_WAIT_SECONDS;
    642 
    643 	(void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock);
    644 	if (filebench_shm->shm_procs_running <= 0) {
    645 		/* No processes running, so no need to do anything */
    646 		(void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock);
    647 		return;
    648 	}
    649 	(void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock);
    650 
    651 	(void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock);
    652 	if (filebench_shm->shm_f_abort == FILEBENCH_ABORT_FINI) {
    653 		(void) ipc_mutex_unlock(
    654 		    &filebench_shm->shm_procflow_lock);
    655 		return;
    656 	}
    657 
    658 	procflow = filebench_shm->shm_proclist;
    659 	if (filebench_shm->shm_f_abort == FILEBENCH_OK)
    660 		filebench_shm->shm_f_abort = FILEBENCH_ABORT_DONE;
    661 
    662 	while (procflow) {
    663 		if (procflow->pf_instance &&
    664 		    (procflow->pf_instance == FLOW_MASTER)) {
    665 			procflow = procflow->pf_next;
    666 			continue;
    667 		}
    668 		filebench_log(LOG_DEBUG_IMPL, "Deleting process %s-%d %d",
    669 		    procflow->pf_name,
    670 		    procflow->pf_instance,
    671 		    procflow->pf_pid);
    672 
    673 		next_procflow = procflow->pf_next;
    674 
    675 		/*
    676 		 * Signalling the process with SIGUSR1 will result in it
    677 		 * gracefully shutting down and exiting
    678 		 */
    679 		procflow_sleep(procflow, wait_cnt);
    680 		if (procflow->pf_running) {
    681 #ifdef USE_PROCESS_MODEL
    682 			pid_t pid;
    683 
    684 			pid = procflow->pf_pid;
    685 #ifdef HAVE_SIGSEND
    686 			(void) sigsend(P_PID, pid, SIGUSR1);
    687 #else
    688 			(void) kill(pid, SIGUSR1);
    689 #endif
    690 			procflow_wait(pid);
    691 
    692 #else /* USE_PROCESS_MODEL */
    693 			threadflow_delete_all(&procflow->pf_threads);
    694 #endif /* USE_PROCESS_MODEL */
    695 		}
    696 		(void) procflow_cleanup(procflow);
    697 		procflow = next_procflow;
    698 		if (wait_cnt > 0)
    699 			wait_cnt--;
    700 	}
    701 
    702 	filebench_shm->shm_f_abort = FILEBENCH_ABORT_FINI;
    703 	(void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock);
    704 
    705 	/* indicate all processes are stopped, even if some are "stuck" */
    706 	(void) ipc_mutex_lock(&filebench_shm->shm_procs_running_lock);
    707 	filebench_shm->shm_procs_running = 0;
    708 	(void) ipc_mutex_unlock(&filebench_shm->shm_procs_running_lock);
    709 }
    710 
    711 
    712 /*
    713  * Create an in-memory process object. Allocates a procflow
    714  * entity, initialized from the "inherit" procflow if supplied.
    715  * The name and instance number are set from the supplied name
    716  * and instance number and the procflow is added to the head of
    717  * the master procflow list. Returns pointer to the allocated
    718  * procflow, or NULL if a name isn't supplied or the procflow
    719  * entity cannot be allocated.
    720  *
    721  * The calling routine must hold the filebench_shm->shm_procflow_lock.
    722  */
    723 static procflow_t *
    724 procflow_define_common(procflow_t **list, char *name,
    725     procflow_t *inherit, int instance)
    726 {
    727 	procflow_t *procflow;
    728 
    729 	if (name == NULL)
    730 		return (NULL);
    731 
    732 	procflow = (procflow_t *)ipc_malloc(FILEBENCH_PROCFLOW);
    733 
    734 	if (procflow == NULL)
    735 		return (NULL);
    736 
    737 	if (inherit)
    738 		(void) memcpy(procflow, inherit, sizeof (procflow_t));
    739 	else
    740 		(void) memset(procflow, 0, sizeof (procflow_t));
    741 
    742 	procflow->pf_instance = instance;
    743 	(void) strcpy(procflow->pf_name, name);
    744 
    745 	filebench_log(LOG_DEBUG_IMPL, "defining process %s-%d", name, instance);
    746 
    747 	/* Add procflow to list, lock is being held already */
    748 	if (*list == NULL) {
    749 		*list = procflow;
    750 		procflow->pf_next = NULL;
    751 	} else {
    752 		procflow->pf_next = *list;
    753 		*list = procflow;
    754 	}
    755 	filebench_log(LOG_DEBUG_IMPL, "process %s-%d proclist %zx",
    756 	    name, instance, filebench_shm->shm_proclist);
    757 
    758 	return (procflow);
    759 }
    760 
    761 /*
    762  * Create an in-memory process object as described by the syntax.
    763  * Acquires the filebench_shm->shm_procflow_lock and calls
    764  * procflow_define_common() to create and initialize a
    765  * FLOW_MASTER procflow entity from the optional "inherit"
    766  * procflow with the given name and configured for "instances"
    767  * number of worker procflows. Currently only called from
    768  * parser_proc_define().
    769  */
    770 procflow_t *
    771 procflow_define(char *name, procflow_t *inherit, avd_t instances)
    772 {
    773 	procflow_t *procflow;
    774 
    775 	(void) ipc_mutex_lock(&filebench_shm->shm_procflow_lock);
    776 
    777 	procflow = procflow_define_common(&filebench_shm->shm_proclist,
    778 	    name, inherit, FLOW_MASTER);
    779 	procflow->pf_instances = instances;
    780 
    781 	(void) ipc_mutex_unlock(&filebench_shm->shm_procflow_lock);
    782 
    783 	return (procflow);
    784 }
    785