⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 process.c

📁 fortran并行计算包
💻 C
📖 第 1 页 / 共 2 页
字号:
/* -*- Mode: C; c-basic-offset:4 ; -*- *//*   *  (C) 2003 by Argonne National Laboratory. *      See COPYRIGHT in top-level directory. */#include "pmutilconf.h"#ifdef NEEDS_POSIX_FOR_SIGACTION#define _POSIX_SOURCE#endif#include <stdio.h>#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#include "pmutil.h"#include "ioloop.h"#include "process.h"#include "env.h"/* Use the memory defintions from mpich2/src/include */#include "mpimem.h"#ifdef HAVE_ERRNO_H#include <errno.h>#endif#include <sys/wait.h>#if defined(USE_SIGNAL) || defined(USE_SIGACTION)#include <signal.h>#else#error no signal choice#endif#ifdef NEEDS_STRSIGNAL_DECLextern char *strsignal(int);#endif/* There is only one universe */ProcessUniverse pUniv;/* This is the home of the common debug flag */int MPIE_Debug = 0;/* A unique ID for each forked process, up to 2 billion.  This is    global to this file so that MPIE_SetupSingleton and MPIE_ForkProcess   can both access it */static       int UniqId = 0; /* Local, forward references */static void MPIE_InstallSigHandler( int sig, void (*handler)(int) );/*  Fork numprocs processes, with the current PMI groupid and kvsname   This is called for the initial processes and as the result of   an PMI "spawn" command     world indicates which comm world this is, starting from zero *//*@  MPIE_ForkProcesses - Create new processes for a comm_world  Input Parameters:+ pWorld - Pointer to a 'ProcessWorld' structure, containing one or more           'ProcessApp' structures.  Each 'ProcessApp' specifies how many	   processes to create.. envp   - Environment to provide to each process. preamble - Routine executed before the fork for each created process. preambldData - Data passed to the preamble function- other - other  Output Effects:  The 'ProcessState' fields are allocated and filled in with the process id  and other information.  Callbacks:+ preamble - called before fork. postfork - called after fork, but before exec, in the forked child- postamble - called after fork in the parent (the process that executed     the fork).    A typical use of the 'preamble' function is to open a file descriptor  that is then inherited by the forked process.  The 'postfork' and  'postamble' can close any unneeded file descriptors  Returns:  The number of created processes.  @*/int MPIE_ForkProcesses( ProcessWorld *pWorld, char *envp[],			int (*preamble)(void*,ProcessState*), 			void *preambleData,			int (*postfork)(void*,void*,ProcessState*), 			void *postforkData,			int (*postamble)(void*,void*,ProcessState*), 			void *postambleData			){    pid_t         pid;    ProcessApp   *app;    ProcessState *pState=0;    int          wRank = 0;    /* Rank in this comm world of the process */    int          i, rc;    int          nProcess = 0;    app = pWorld->apps;    while (app) {	/* Allocate process state if necessary */	if (!app->pState) {	    pState = (ProcessState *)MPIU_Malloc( 		app->nProcess * sizeof(ProcessState) );	    if (!pState) {		return -1;	    }	    app->pState = pState;	}	pState = app->pState;	for (i=0; i<app->nProcess; i++) {	    pState[i].app                   = app;	    pState[i].wRank                 = wRank++;	    pState[i].id                    = UniqId++;	    pState[i].initWithEnv           = 1;  /* Default is to use env						    to initialize connection */	    pState[i].status                = PROCESS_UNINITIALIZED;	    pState[i].exitStatus.exitReason = EXIT_NOTYET;	    pState[i].pid                   = -1;	    /* Execute any preamble */	    if (preamble) {		rc = (*preamble)( preambleData, &pState[i] );	    }	    pid = fork();	    if (pid < 0) {		/* Error creating process */		return -1;	    }	    if (pid == 0) {		/* Child */		/* exec the process (this call only returns if there is an 		   error */		if (postfork) {		    rc = (*postfork)( preambleData, postforkData, &pState[i] );		}		rc = MPIE_ExecProgram( &pState[i], envp );		if (rc) {		    MPIU_Internal_error_printf( "mpiexec fork failed\n" );		    /* FIXME: kill children */		    exit(1);		}	    }	    else {		/* Parent */		nProcess++;		/* Add this to the live processes in the Universe */		pUniv.nLive++;		pState[i].pid    = pid;		pState[i].status = PROCESS_ALIVE;		if (postamble) {		    rc = (*postamble)( preambleData, postambleData, 				       &pState[i] );		    if (rc) {			MPIU_Internal_error_printf( 				      "mpiexec postamble failed\n" );			/* FIXME: kill children */			exit(1);		    }		}	    }	}		app = app->nextApp;    }    return nProcess;}/*@  MPIE_ProcessGetExitStatus - Return an integer exit status based on the  return status of all processes in the process universe; returns the  maximum value seen.  Output Parameter:. signaled - 0 if the process was `not` signaled, otherwise the signal   that terminated the process.  Return Value:  Maximum of the return status of all processes.    @*/int MPIE_ProcessGetExitStatus( int *signaled ){    ProcessWorld *world;    ProcessApp   *app;    ProcessState *pState;    int          i, rc = 0, sig = 0;    DBG_PRINTF(("Getting exit status\n"));    world = pUniv.worlds;    while (world) {	app = world->apps;	while (app) {	    pState = app->pState;	    for (i=0; i<app->nProcess; i++) {		if (pState[i].exitStatus.exitStatus > rc) {		    rc = pState[i].exitStatus.exitStatus;		}		if (pState[i].exitStatus.exitReason == EXIT_SIGNALLED) {		    sig = 1;		}	    }	    app = app->nextApp;	}	world = world->nextWorld;    }    DBG_PRINTF(("Done getting exit status\n" ));    *signaled = sig;    return rc;}/* * exec the indicated program with the indicated environment */#ifndef MAXPATHLEN#define MAXPATHLEN 1024#endif#define MAX_CLIENT_ARG 50#define MAX_CLIENT_ENV 200/* MAXNAMELEN is used for sizing the char arrays used for  * defining environment variables */#define MAXNAMELEN 1024int MPIE_ExecProgram( ProcessState *pState, char *envp[] ){    int j, rc, nj;    ProcessApp *app;    /* Provide local variables in which to hold new environment variables. */    char env_pmi_rank[MAXNAMELEN];    char env_pmi_id[MAXNAMELEN];    char env_pmi_size[MAXNAMELEN];    char env_pmi_debug[MAXNAMELEN];    char env_appnum[MAXNAMELEN];    char env_universesize[MAXNAMELEN];    char pathstring[MAXPATHLEN+10];    char *(client_env[MAX_CLIENT_ENV]);    char *(client_arg[MAX_CLIENT_ARG]);    app = pState->app;    /* build environment for client. */    j = MPIE_EnvSetup( pState, envp, client_env, MAX_CLIENT_ENV-7 );    if (j < 0) {	MPIU_Error_printf( "Failure setting up environment\n" );    }    nj = j;  /* nj is the first entry of client_env that will be set by		this routine */    DBG_PRINTF( ( "Setup env (j=%d)\n", j ) );    if (j == MAX_CLIENT_ENV-7) {	MPIU_Error_printf( "Environment is too large (max is %d)\n",			   MAX_CLIENT_ENV-7);	exit(-1);    }    DBG_PRINTF( ( "Creating pmi env\n" ) );    if (pState->initWithEnv) {	MPIU_Snprintf( env_pmi_rank, MAXNAMELEN, "PMI_RANK=%d", 		       pState->wRank );	client_env[j++] = env_pmi_rank;	MPIU_Snprintf( env_pmi_size, MAXNAMELEN, "PMI_SIZE=%d", 		       app->pWorld->nProcess );	client_env[j++] = env_pmi_size;	MPIU_Snprintf( env_pmi_debug, MAXNAMELEN, "PMI_DEBUG=%d", MPIE_Debug );	client_env[j++] = env_pmi_debug;     }    else {	/* We must also communicate the ID to the process.  	   This id is saved in the pState so that we can match it 	   when it comes back to us (it is the same as the rank 	   in the simple case) */	MPIU_Snprintf( env_pmi_id, sizeof(env_pmi_id), "PMI_ID=%d",		       pState->id );	client_env[j++] = env_pmi_id;    }    MPIU_Snprintf( env_appnum, MAXNAMELEN, "MPI_APPNUM=%d", app->myAppNum );    client_env[j++] = env_appnum;    MPIU_Snprintf( env_universesize, MAXNAMELEN, "MPI_UNIVERSE_SIZE=%d", 		   pUniv.size );    client_env[j++] = env_universesize;    client_env[j]   = 0;    for ( j = nj; client_env[j]; j++ )	if (putenv( client_env[j] )) {	    MPIU_Internal_sys_error_printf( "mpiexec", errno, 			     "Could not set environment %s", client_env[j] );	    exit( 1 );	}        DBG_PRINTF( ( "Setup env, starting with wdir\n" ) );    /* change working directory if specified, replace argv[0],        and exec client */    if (app->wdir) {	rc = chdir( app->wdir );	if (rc < 0) {	    MPIU_Error_printf( "Unable to set working directory to %s\n",			       app->wdir);	    rc = chdir( getenv( "HOME" ) );	    if (rc < 0) {		MPIU_Error_printf( "Unable to set working directory to %s\n",				   getenv( "HOME" ) );		exit( 1 );	    }	}    }    DBG_PRINTF( ( "Setup command-line args\n" ) );    /* Set up the command-line arguments */    client_arg[0] = (char *)app->exename;    for (j=0; j<app->nArgs; j++) {	client_arg[1+j] = (char *)app->args[j];    }    /* The argv array is null-terminated */    client_arg[1+j] = 0;    /* pathname argument should be used here */    if (app->path) {	/* Set up the search path */	MPIU_Snprintf( pathstring, sizeof(pathstring)-1, "PATH=%s", 		       app->path );	/* Some systems require that the path include the path to	   certain files or libraries, for example cygwin1.dll for	   Cygwin */#ifdef NEEDS_BIN_IN_PATH	MPIU_Strnapp( pathstring, ":/bin", sizeof(pathstring)-1 );#endif	putenv( pathstring );    }    DBG_PRINTF( ( "Exec the application %s\n", app->exename ) );    rc = execvp( app->exename, client_arg );    if ( rc < 0 ) {	MPIU_Internal_sys_error_printf( "mpiexec", errno, 					"mpiexec could not exec %s\n", 					app->exename );	exit( 1 );    }    return 0;}/*@  MPIE_FindProcessByPid - Given a pid, return a pointer to the process state  Notes:  This searches through all processes in the process universe.  Returns  null if no corresponding process is found.  @*/ProcessState *MPIE_FindProcessByPid( pid_t pid ){    ProcessWorld *world;    ProcessApp   *app;    ProcessState *pState;    int           i;    int           np = 100000; /* FIXME: Should initialize with the				  number of created processes */    world = pUniv.worlds;    while (world) {	app = world->apps;	while (app) {	    pState = app->pState;	    np -= app->nProcess;	    if (np < 0) {		/* This is a panic exit, used becaue we may call this		   from within the signal handler */		return 0;	    }	    /* It is possible for pState to be uninitialized if not all apps	       have been started yet via MPIE_ForkProcesses and we are called	       from handle_sigchild. */	    if (pState) {		for (i=0; i<app->nProcess; i++) {		    if (pState[i].pid == pid) return &pState[i];		}	    }	    app = app->nextApp;	}	world = world->nextWorld;    }    return 0;}/* * Given a pointer to a process state structure, and the process status * returned by a 'wait' call, set the fields in the process state to * indicate the reason for the process exit */static int nExited = 0;void MPIE_ProcessSetExitStatus( ProcessState *pState, int prog_stat ){    int rc = 0, sigval = 0;    if (WIFEXITED(prog_stat)) {	rc = WEXITSTATUS(prog_stat);	    }    if (WIFSIGNALED(prog_stat)) {	sigval = WTERMSIG(prog_stat);    }    pState->exitStatus.exitStatus = rc;    pState->exitStatus.exitSig    = sigval;    pState->exitStatus.exitOrder  = nExited++;    if (sigval) 	pState->exitStatus.exitReason = EXIT_SIGNALLED;    else {	if (pState->status >= PROCESS_ALIVE &&	    pState->status <= PROCESS_COMMUNICATING) 	    pState->exitStatus.exitReason = EXIT_NOFINALIZE;	else 	    pState->exitStatus.exitReason = EXIT_NORMAL;    }}/* ------------------------------------------------------------------------- *//* SIGNALS and CHILDREN                                                      *//* ------------------------------------------------------------------------- *//* * POSIX requires a SIGCHLD handler (SIG_IGN is invalid for SIGCHLD in * POSIX).  Thus, we have to perform the waits within the signal handler. * Because there may be a race condition with recording the pids in the  * ProcessState structure, we provide an "unexpected child" structure to * hold information about processes that are not yet registered.  A clean * up handler records the state of those processes when we're ready to  * exit. * * Because signals are not queued, this handler processes all completed * processes.   * * We must perform the wait in the handler because if we do not, we loose  * the exit status information (it is no longer available after the * signal handler exits). *//* inHandler and skipHandler are used to control the SIGCHLD handler and   to avoid (or at least narrow) race conditions */static volatile int inHandler = 0;/* skip handler is set if we are planning to wait for processes with the   "wait" system call in a separate routine.  */static volatile int skipHandler = 0;/* The "unexpected" structure is used to record any processes that   exit before we've recorded their pids.  This is unlikely, but may   happen if a process fails to exec (e.g., the fork succeeds but the    exec immediately fails).  This ensures that we can handle SIGCHLD   events without loosing information about the child processes */#define MAXUNEXPECTEDPIDS 1024static struct {    pid_t  pid;    int    stat;} unexpectedExit[MAXUNEXPECTEDPIDS];static int nUnexpected = 0;	 static void handle_sigchild( int sig ){    int prog_stat, pid;    int foundChild = 0;    ProcessState *pState;    /* Set a flag to indicate that we're in the handler, and check        to see if we should ignore the signal */    if (inHandler) return;    inHandler = 1;    if (skipHandler) {	/* Someone else wants to wait on the processes, so we	   return now. */	inHandler = 0;#ifndef SA_RESETHAND	/* If we can't clear the "reset handler bit", we must 	   re-install the handler here */	MPIE_InstallSigHandler( SIGCHLD, handle_sigchild );#endif	return;    }    DBG_PRINTF( ("Entering sigchild handler\n") );    DBG_EPRINTF((stderr, "Waiting for any child on signal\n") );    /* Since signals may be coallesced, we process all children that       have exited */    while (1) {	/* Find out about any children that have exited.  Note that	   we don't check for EINTR because we're within a 	   signal handler. */	pid = waitpid( (pid_t)(-1), &prog_stat, WNOHANG );    	if (pid <= 0) {	    /* Note that it may not be an error if no child 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -