procflow.c revision f2fc321be9b4df7748e8c31a5edd154b0177b139
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <signal.h>
#include <fcntl.h>
#include "procflow.h"
#include "filebench.h"
#include "flowop.h"
#include "ipc.h"
static int procflow_delete_wait_cnt = 0;
#ifdef USE_PROCESS_MODEL
static enum create_n_wait {
} cnw_wait;
static pthread_cond_t procflow_procs_created;
#endif /* USE_PROCESS_MODEL */
/*
* Procflows are filebench entities which manage processes. Each
* worker procflow spawns a separate filebench process, with attributes
* inherited from a FLOW_MASTER procflow created during f model language
* parsing. This section contains routines to define, create, control,
* and delete procflows.
*
* Each process defined in the f model creates a FLOW_MASTER
* procflow which encapsulates the defined attributes, and threads of
* the f process, including the number of instances to create. At
* runtime, a worker procflow instance with an associated filebench
* process is created, which runs until told to quite by the original
* filebench process or is specifically deleted.
*/
/*
* Prints a summary of the syntax for setting procflow parameters.
*/
void
procflow_usage(void)
{
"define process name=<name>[,instances=<count>]\n");
}
/*
* If filebench has been compiled to support multiple processes
* (USE_PROCESS_MODEL defined), this routine forks a child
* process and uses either system() or exec() to start up a new
* instance of filebench, passing it the procflow name, instance
* number and shared memory region address.
* If USE_PROCESS_MODEL is NOT defined, then the routine
* just creates a child thread which begins executing
* threadflow_init() for the specified procflow.
*/
static int
{
char instance[128];
char shmaddr[128];
char procname[128];
#ifdef USE_PROCESS_MODEL
#else
#endif
procflow->pf_running = 0;
#ifdef HAVE_FORK1
"procflow_createproc fork failed: %s",
return (-1);
}
#else
"procflow_createproc fork failed: %s",
return (-1);
}
#endif /* HAVE_FORK1 */
if (pid == 0) {
#ifdef USE_SYSTEM
char syscmd[1024];
#endif
/* Child */
#ifdef USE_SYSTEM
shmaddr);
"procflow exec proc failed: %s",
}
#else
"procflow exec proc failed: %s",
}
#endif
exit(1);
} else {
}
#else
(void *(*)(void*))threadflow_init, procflow) != 0) {
procflow->pf_running = 0;
}
#endif
pid);
return (0);
}
/*
* Find a procflow of name "name" and instance "instance" on the
* master procflow list, filebench_shm->proclist. Locks the list
* and scans through it searching for a procflow with matching
* name and instance number. If found returns a pointer to the
* procflow, otherwise returns NULL.
*/
static procflow_t *
{
while (procflow) {
return (procflow);
}
}
return (NULL);
}
static int
{
int ret = 0;
while (procflow) {
int i;
/* Create instances of procflow */
/* Create processes */
newproc =
ret = -1;
else
}
if (ret != 0)
break;
}
return (ret);
}
#ifdef USE_PROCESS_MODEL
/*
* Used to start up threads on a child process, when filebench is
* compiled to support multiple processes. Uses the name string
* and instance number passed to the child to find the previously
* created procflow entity. Then uses nice() to reduce the
* process' priority by at least 10. A call is then made to
* threadflow_init() which creates and runs the process' threads
* and flowops to completion. When threadflow_init() returns,
* a call to exit() terminates the child process.
*/
int
{
int proc_nice;
#ifdef HAVE_SETRLIMIT
#endif
"procflow_execproc %s-%d",
"procflow_exec could not find %s-%d",
return (-1);
}
#ifdef HAVE_SETRLIMIT
/* Get resource limits */
#endif
if (threadflow_init(procflow) < 0) {
"Failed to start threads for %s pid %d",
procflow->pf_running = 0;
exit(1);
}
procflow->pf_running = 0;
exit(0);
return (0);
}
/*
* A special thread from which worker (child) processes are created, and
* which then waits for worker processes to die. If they die unexpectedly,
* that is not a simple exit(0), then report an error and terminate the
* run.
*/
/* ARGSUSED */
static void *
procflow_createnwait(void *nothing)
{
if (procflow_create_all_procs() == 0)
else
if (pthread_cond_signal(&procflow_procs_created) != 0)
exit(1);
/* CONSTCOND */
while (1) {
/* wait for any child process to exit */
pthread_exit(0);
/* if normal shutdown in progress, just quit */
if (filebench_shm->f_abort)
pthread_exit(0);
/* A process called exit(); check returned status */
"Unexpected Process termination; exiting",
}
} else {
/* A process quit because of some fatal error */
"Unexpected Process termination Code %d, Errno %d",
}
if (filebench_shm->allrunning == 0)
pthread_exit(0);
}
/* NOTREACHED */
return (NULL);
}
#endif /* USE_PROCESS_MODEL */
/*
* Iterates through proclist, the master list of procflows,
* creating the number of instances of each procflow specified
* by its pf_instance attribute. Returns 0 on success, or -1
* times the number of procflow instances that were not
* successfully created.
*/
int
procflow_init(void)
{
int ret = 0;
"procflow_init %s, %lld",
#ifdef USE_PROCESS_MODEL
return (ret);
return (ret);
&filebench_shm->procflow_lock)) != 0)
return (ret);
ret = -1;
#else /* USE_PROCESS_MODEL */
#endif /* USE_PROCESS_MODEL */
return (ret);
}
#ifdef USE_PROCESS_MODEL
/*
* Waits for child processes to finish and returns their exit
* status. Used by procflow_delete() when the process model is
* enabled to wait for a deleted process to exit.
*/
static void
{
int stat;
}
#endif
/*
* Deletes the designated procflow and all its threadflows except
* for FLOW_MASTER ones. Waits 10 seconds if the procflow is still
* running, then kills the associated process. Finally it frees the
* procflow entity. filebench_shm->procflow_lock must be held on entry.
*
* If the designated procflow is not found on the list it returns -1 and
* the procflow is not deleted. Otherwise it returns 0.
*/
static int
{
"Deleted proc: (%s-%d) pid %d",
"Waiting for process %s-%d %d",
if (procflow_delete_wait_cnt < 10) {
(void) sleep(1);
continue;
}
#ifdef USE_PROCESS_MODEL
"Had to kill process %s-%d %d!",
procflow->pf_running = 0;
#endif
}
#ifdef USE_PROCESS_MODEL
#endif
/* remove entry from proclist */
/* unlink procflow entity from proclist */
/* at head of list */
} else {
/* search list for procflow */
/* if entity found, unlink it */
return (-1);
else
}
/* free up the procflow entity */
return (0);
}
/*
* Waits till all threadflows are started, or a timeout occurs.
* Checks through the list of procflows, waiting up to 30
* seconds for each one to set its pf_running flag to 1. If not
* set after 30 seconds, continues on to the next procflow
* anyway after logging the fact. Once pf_running is set
* to 1 for a given procflow or the timeout is reached,
* threadflow_allstarted() is called to start the threads.
* Returns 0 (OK), unless filebench_shm->f_abort is signaled,
* in which case it returns -1.
*/
int
{
int ret = 0;
(void) sleep(1);
while (procflow) {
int waits;
if (procflow->pf_instance &&
continue;
}
waits = 10;
return (-1);
if (waits < 3)
"Waiting for process %s-%d %d",
(void) sleep(3);
waits--;
}
if (waits == 0)
}
return (ret);
}
/*
* Sets the f_abort flag and clears the allrunning flag to stop
* all the flowop execution threads from running. Iterates
* through the procflow list and deletes all procflows except
* for the FLOW_MASTER procflow. Resets the f_abort flag when
* finished.
*/
void
procflow_shutdown(void)
{
filebench_shm->allrunning = 0;
while (procflow) {
if (procflow->pf_instance &&
continue;
}
(void) procflow_delete(procflow);
}
filebench_shm->f_abort = 0;
}
/*
* Create an in-memory process object. Allocates a procflow
* entity, initialized from the "inherit" procflow if supplied.
* The name and instance number are set from the supplied name
* and instance number and the procflow is added to the head of
* the master procflow list. Returns pointer to the allocated
* procflow, or NULL if a name isn't supplied or the procflow
* entity cannot be allocated.
*
* The calling routine must hold the filebench_shm->procflow_lock.
*/
static procflow_t *
{
return (NULL);
return (NULL);
if (inherit)
else
/* Add procflow to list, lock is being held already */
} else {
}
return (procflow);
}
/*
* Create an in-memory process object as described by the syntax.
* Acquires the filebench_shm->procflow_lock and calls
* procflow_define_common() to create and initialize a
* FLOW_MASTER procflow entity from the optional "inherit"
* procflow with the given name and configured for "instances"
* number of worker procflows. Currently only called from
* parser_proc_define().
*/
{
return (procflow);
}