Ejemplo n.º 1
0
int mysystem(AppInfo* appinfo, JobInfo* jobinfo, char* envp[])
/* purpose: emulate the system() libc call, but save utilization data. 
 * paramtr: appinfo (IO): shared record of information
 *                        isPrinted (IO): reset isPrinted in child process!
 *                        input (IN): connect to stdin or share
 *                        output (IN): connect to stdout or share
 *                        error (IN): connect to stderr or share
 *          jobinfo (IO): updated record of job-specific information
 *                        argv (IN): assembled commandline
 *                        child (OUT): pid of child process
 *                        status (OUT): also returned as function result
 *                        saverr (OUT): will be set to value of errno
 *                        start (OUT): will be set to startup time
 *                        final (OUT): will be set to finish time after reap
 *                        use (OUT): rusage record from application call
 *          input (IN): connect to stdin or share
 *          output (IN): connect to stdout or share
 *          error (IN): connect to stderr or share
 *          envp (IN): vector with the parent's environment
 * returns:   -1: failure in mysystem processing, check errno
 *           126: connecting child to its new stdout failed
 *           127: execve() call failed
 *          else: status of child
 */
{
  struct sigaction ignore, saveintr, savequit;

  /* sanity checks first */
  if ( ! jobinfo->isValid ) {
    errno = ENOEXEC; /* no executable */
    return -1;
  }

  memset( &ignore, 0, sizeof(ignore) );
  ignore.sa_handler = SIG_IGN;
  sigemptyset( &ignore.sa_mask );
  ignore.sa_flags = 0;
  if ( sigaction( SIGINT, &ignore, &saveintr ) < 0 )
    return -1;
  if ( sigaction( SIGQUIT, &ignore, &savequit ) < 0 )
    return -1;

  /* start wall-clock */
  now( &(jobinfo->start) );

  if ( (jobinfo->child=fork()) < 0 ) {
    /* no more process table space */
    jobinfo->status = -1;
  } else if ( jobinfo->child == 0 ) {
    /* child */
    appinfo->isPrinted=1;

    /* connect jobs stdio */
    if ( forcefd( &appinfo->input, STDIN_FILENO ) ) _exit(126);
    if ( forcefd( &appinfo->output, STDOUT_FILENO ) ) _exit(126);
    if ( forcefd( &appinfo->error, STDERR_FILENO ) ) _exit(126);

    /* undo signal handlers */
    sigaction( SIGINT, &saveintr, NULL );
    sigaction( SIGQUIT, &savequit, NULL );

    /* If we are tracing, then hand over control to the proc module */
    if (appinfo->enableTracing) {
      if ( procChild() ) _exit(126);
    }
    
    execve( jobinfo->argv[0], (char* const*) jobinfo->argv, envp );
    perror("execve");
    _exit(127); /* executed in child process */
  } else {
    /* parent */
    if (appinfo->enableTracing) {
      procParentTrace(jobinfo->child, &jobinfo->status, &jobinfo->use, &(jobinfo->children));
    } else {
      procParentWait(jobinfo->child, &jobinfo->status, &jobinfo->use, &(jobinfo->children));
    }
    
    /* sanity check */
    if ( kill( jobinfo->child, 0 ) == 0 ) {
      debugmsg( "ERROR: job %d is still running!\n", jobinfo->child );
      if ( ! errno ) errno = EINPROGRESS;
    }
  }
  
  /* save any errors before anybody overwrites this */
  jobinfo->saverr = errno;
  
  /* stop wall-clock */
  now( &(jobinfo->finish) );
  
  /* ignore errors on these, too. */
  sigaction( SIGINT, &saveintr, NULL );
  sigaction( SIGQUIT, &savequit, NULL );
  
  /* finalize */
  return jobinfo->status;
}
Ejemplo n.º 2
0
int mysystem(AppInfo* appinfo, JobInfo* jobinfo, char* envp[]) {
    /* purpose: emulate the system() libc call, but save utilization data.
     * paramtr: appinfo (IO): shared record of information
     *                        isPrinted (IO): reset isPrinted in child process!
     *                        input (IN): connect to stdin or share
     *                        output (IN): connect to stdout or share
     *                        error (IN): connect to stderr or share
     *          jobinfo (IO): updated record of job-specific information
     *                        argv (IN): assembled commandline
     *                        child (OUT): pid of child process
     *                        status (OUT): also returned as function result
     *                        saverr (OUT): will be set to value of errno
     *                        start (OUT): will be set to startup time
     *                        final (OUT): will be set to finish time after reap
     *                        use (OUT): rusage record from application call
     *          input (IN): connect to stdin or share
     *          output (IN): connect to stdout or share
     *          error (IN): connect to stderr or share
     *          envp (IN): vector with the parent's environment
     * returns:   -1: failure in mysystem processing, check errno
     *           126: connecting child to its new stdout failed
     *           127: execve() call failed
     *          else: status of child
     */

    /* sanity checks first */
    if (!jobinfo->isValid) {
        errno = ENOEXEC; /* no executable */
        return -1;
    }

    /* Ignore SIGINT and SIGQUIT */
    struct sigaction ignore, saveintr, savequit;
    memset(&ignore, 0, sizeof(ignore));
    ignore.sa_handler = SIG_IGN;
    sigemptyset(&ignore.sa_mask);
    ignore.sa_flags = 0;
    if (sigaction(SIGINT, &ignore, &saveintr) < 0) {
        return -1;
    }
    if (sigaction(SIGQUIT, &ignore, &savequit) < 0) {
        return -1;
    }

    /* Prefix for trace files generated by this job */
    char trace_file_prefix[128];
    snprintf(trace_file_prefix, 128, "gs.trace.%d", getpid());

    /* Temp dir where trace files are stored for this job */
    const char *tempdir = getTempDir();
    if (tempdir == NULL) {
        tempdir = "/tmp";
    }

    /* start wall-clock */
    now(&(jobinfo->start));

    if ((jobinfo->child=fork()) < 0) {
        /* no more process table space */
        jobinfo->status = -1;
    } else if (jobinfo->child == 0) {
        /* child */
        appinfo->isPrinted=1;

        // If we are using library tracing, try to set the necessary
        // environment variables
        if (appinfo->enableLibTrace) {
            envp = tryGetNewEnvironment(envp, tempdir, trace_file_prefix);
        }

        /* connect jobs stdio */
        if (forcefd(&appinfo->input, STDIN_FILENO)) _exit(126);
        if (forcefd(&appinfo->output, STDOUT_FILENO)) _exit(126);
        if (forcefd(&appinfo->error, STDERR_FILENO)) _exit(126);

        /* undo signal handlers */
        sigaction(SIGINT, &saveintr, NULL);
        sigaction(SIGQUIT, &savequit, NULL);

        /* If we are tracing, then hand over control to the proc module */
        if (appinfo->enableTracing) {
            if (procChild()) _exit(126);
        }

        execve(jobinfo->argv[0], (char* const*) jobinfo->argv, envp);
        perror("execve");
        _exit(127); /* executed in child process */
    } else {
        /* Track the current child process */
        appinfo->currentChild = jobinfo->child;

        /* parent */
        if (appinfo->enableTracing) {
            /* TODO If this returns an error, then we need to untrace all the children and try the wait instead */
            procParentTrace(jobinfo->child, &jobinfo->status, &jobinfo->use, &(jobinfo->children), appinfo->enableSysTrace);
        } else {
            procParentWait(jobinfo->child, &jobinfo->status, &jobinfo->use, &(jobinfo->children));
        }

        /* sanity check */
        if (kill(jobinfo->child, 0) == 0) {
            printerr("ERROR: job %d is still running!\n", jobinfo->child);
            if (!errno) errno = EINPROGRESS;
        }

        /* Child is no longer running */
        appinfo->currentChild = 0;
    }

    /* save any errors before anybody overwrites this */
    jobinfo->saverr = errno;

    /* stop wall-clock */
    now(&(jobinfo->finish));

    /* ignore errors on these, too. */
    sigaction(SIGINT, &saveintr, NULL);
    sigaction(SIGQUIT, &savequit, NULL);

    /* Look for trace files from libinterpose and add trace data to jobinfo */
    if (appinfo->enableLibTrace) {
        jobinfo->children = processTraceFiles(tempdir, trace_file_prefix);
    }

    /* finalize */
    return jobinfo->status;
}