Пример #1
0
void rktio_process_forget(rktio_t *rktio, rktio_process_t *sp)
{
#ifdef RKTIO_SYSTEM_UNIX
# if defined(CENTRALIZED_SIGCHILD)
  if (!sp->done) {
    centralized_done_with_process_id(sp->pid, sp->in_group);
    centralized_ended_child();
  }
# else
  if (!((System_Child *)sp->handle)->done) {
    void **unused_pid;
    unused_pid = malloc(sizeof(void *) * 2);
    unused_pid[0] = (void *)(intptr_t)sp->pid;
    unused_pid[1] = unused_pids;
    rktio->need_to_check_children = 1;
  }
  free(sp->handle);
# endif
#endif

#ifdef RKTIO_SYSTEM_WINDOWS
  CloseHandle(sp->handle);
#endif

  free(sp);
}
Пример #2
0
rktio_status_t *rktio_process_status(rktio_t *rktio, rktio_process_t *sp)
{
  int going = 0, status = 0;
  rktio_status_t *result;

#if defined(RKTIO_SYSTEM_UNIX)
# if defined(CENTRALIZED_SIGCHILD)
  if (sp->done) {
    status = sp->status;
  } else {
    if (!centralized_get_child_status(sp->pid, sp->in_group, 1, &status)) {
      going = 1;
    } else {
      sp->done = 1;
      sp->status = status;
      centralized_ended_child();
    }
  }
# else
  System_Child *sc = (System_Child *)sp->handle;
  check_child_done(rktio, sp->pid);

  if (sc->done) {
    status = sc->status;
  } else
   going = 1;
# endif
#else
# ifdef RKTIO_SYSTEM_WINDOWS
  DWORD w;
  if (sp->handle) {
    if (GetExitCodeProcess((HANDLE)sp->handle, &w)) {
      collect_process_time(rktio, w, sp);
      if (w == STILL_ACTIVE)
        going = 1;
      else
        status = w;
    } else {
      get_windows_error();
      return NULL;
    }
  } else
    status = -1;
# endif
#endif

  result = malloc(sizeof(rktio_status_t));
  result->running = going;
  result->result = (going ? 0 : status);
  return result;
}
Пример #3
0
int rktio_poll_process_done(rktio_t *rktio, rktio_process_t *sp)
{
#if defined(RKTIO_SYSTEM_UNIX)
# if defined(CENTRALIZED_SIGCHILD)
  {
    int status;
    if (!sp->done) {
      if (centralized_get_child_status(sp->pid, sp->in_group, 1, &status)) {
        sp->done = 1;
        sp->status = status;
        centralized_ended_child();
        return 1;
      }
      return 0;
    }
    else
      return RKTIO_PROCESS_DONE;
  }
# else
  {
    System_Child *sc;
    sc = (System_Child *)sp->handle;
    /* Check specific pid, in case the child has its own group
       (either given by us or given to itself): */
    check_child_done(rktio, sp->pid);
    return sc->done;
  }
# endif
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
  {
    HANDLE sci = (HANDLE)sp->handle;
    DWORD w;
    if (sci) {
      if (GetExitCodeProcess(sci, &w)) {
        collect_process_time(rktio, w, sp);
        return (w != STILL_ACTIVE);
      } else
        return RKTIO_PROCESS_DONE;
    } else
      return RKTIO_PROCESS_DONE;

    get_windows_error();

    return RKTIO_PROCESS_ERROR;
  }
#endif
}
Пример #4
0
static int do_subprocess_kill(rktio_t *rktio, rktio_process_t *sp, int as_kill)
{
#if defined(RKTIO_SYSTEM_UNIX)
# if defined(CENTRALIZED_SIGCHILD)
  {
    int status;

    if (sp->done)
      return 1;

    centralized_wait_suspend();

    /* Don't allow group checking, because we don't want to wait
       on a group if we haven't already: */
    if (centralized_get_child_status(sp->pid, 0, 0, &status)) {
      sp->status = status;
      sp->done = 1;
      centralized_wait_resume();
      centralized_ended_child();
      return 1;
    }
  }
# else
  {
    System_Child *sc = (System_Child *)sp->handle;

    /* Don't pass sp->pid, because we don't want to wait
       on a group if we haven't already: */
    check_child_done(rktio, 0);
    if (sc->done)
      return 1;
  }
# define centralized_wait_resume() /* empty */
# endif

  while (1) {

    if (sp->is_group) {
      if (!killpg(sp->pid, as_kill ? SIGKILL : SIGINT)) {
        centralized_wait_resume();
        return 1;
      }
    } else {
      if (!kill(sp->pid, as_kill ? SIGKILL : SIGINT)) {
        centralized_wait_resume();
        return 1;
      }
    }
    
    if (errno != EINTR)
      break;
    /* Otherwise we were interrupted. Try `kill' again. */
  }

  get_posix_error();

  centralized_wait_resume();

  return 0;
#endif
#if defined(RKTIO_SYSTEM_WINDOWS)  
  if (as_kill || sp->is_group) {
    DWORD w;

    if (!sp->handle)
      return 1;

    if (!as_kill) {
      /* must be for a group; we don't care whether the
         original process is still running */
      if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, sp->pid))
        return 1;
    } else if (GetExitCodeProcess((HANDLE)sp->handle, &w)) {
      collect_process_time(rktio, w, sp);
      if (w != STILL_ACTIVE)
        return 1;
      if (TerminateProcess((HANDLE)sp->handle, 1))
        return 1;
    }
    get_windows_error();

    return 0;
  } else
    return 1;
#endif
}
Пример #5
0
rktio_process_result_t *rktio_process(rktio_t *rktio,
                                      const char *command, int argc, rktio_const_string_t *argv,
                                      rktio_fd_t *stdout_fd, rktio_fd_t *stdin_fd, rktio_fd_t *stderr_fd,
                                      rktio_process_t *group_proc,
                                      const char *current_directory, rktio_envvars_t *envvars,
                                      int flags)
{
  rktio_process_result_t *result;
  intptr_t to_subprocess[2], from_subprocess[2], err_subprocess[2];
  int pid;
#if defined(RKTIO_SYSTEM_UNIX)
# if !defined(CENTRALIZED_SIGCHILD)
  System_Child *sc;
# endif
#else
  void *sc = 0;
#endif
  void *env;
  rktio_process_t *subproc;
#if defined(RKTIO_SYSTEM_WINDOWS)
  intptr_t spawn_status;
#endif
  int new_process_group = (flags & RKTIO_PROCESS_NEW_GROUP);
  int stderr_is_stdout = (flags & RKTIO_PROCESS_STDOUT_AS_STDERR);
#if defined(RKTIO_SYSTEM_WINDOWS)
  int windows_exact_cmdline = (flags & RKTIO_PROCESS_WINDOWS_EXACT_CMDLINE);
  int windows_chain_termination_to_child = (flags & RKTIO_PROCESS_WINDOWS_CHAIN_TERMINATION);
  int i;
#endif

  /* avoid compiler warnings: */
  to_subprocess[0] = -1;
  to_subprocess[1] = -1;
  from_subprocess[0] = -1;
  from_subprocess[1] = -1;
  err_subprocess[0] = -1;
  err_subprocess[1] = -1;

  /*--------------------------------------*/
  /*          Create needed pipes         */
  /*--------------------------------------*/

  if (stdout_fd) {
    from_subprocess[1] = rktio_fd_system_fd(rktio, stdout_fd);
    RKTIO_COPY_FOR_SUBPROCESS(from_subprocess, 1);
  } else if (rktio_make_os_pipe(rktio, from_subprocess, RKTIO_NO_INHERIT_INPUT)) {
    return NULL;
  }

  if (stdin_fd) {
    to_subprocess[0] = rktio_fd_system_fd(rktio, stdin_fd);
    RKTIO_COPY_FOR_SUBPROCESS(to_subprocess, 0);
  } else if (rktio_make_os_pipe(rktio, to_subprocess, RKTIO_NO_INHERIT_OUTPUT)) {
    if (stdout_fd) { RKTIO_CLOSE_SUBPROCESS_COPY(from_subprocess, 1); }
    return NULL;
  }

  if (stderr_fd) {
    err_subprocess[1] = rktio_fd_system_fd(rktio, stderr_fd);
    RKTIO_COPY_FOR_SUBPROCESS(err_subprocess, 1);
  } else if (stderr_is_stdout) {
    err_subprocess[0] = from_subprocess[0];
    err_subprocess[1] = from_subprocess[1];
  } else if (rktio_make_os_pipe(rktio, err_subprocess, RKTIO_NO_INHERIT_INPUT)) {
    if (stdout_fd) { RKTIO_CLOSE_SUBPROCESS_COPY(from_subprocess, 1); }
    if (stdin_fd) { RKTIO_CLOSE_SUBPROCESS_COPY(to_subprocess, 0); }
    return NULL;
  }

  if (envvars)
    env = rktio_envvars_to_block(rktio, envvars);
  else
    env = NULL;

#if defined(RKTIO_SYSTEM_WINDOWS)

  /*--------------------------------------*/
  /*        Execute: Windows              */
  /*--------------------------------------*/

  /* Windows: quasi-stdin is locked, and we'll say it doesn't matter */
  fflush(stdin);
  fflush(stdout);
  fflush(stderr);

  {
    char **new_argv;

    if (!windows_exact_cmdline) {
      /* protect spaces, etc. in the arguments: */
      new_argv = malloc(sizeof(char *) * argc);
      for (i = 0; i < argc; i++) {
	new_argv[i] = cmdline_protect(argv[i]);
      }
      argv = new_argv;
    }

    pid = 0;

    spawn_status = do_spawnv(rktio,
                             command, argc, (const char * const *)argv,
			     windows_exact_cmdline,
			     to_subprocess[0],
			     from_subprocess[1],
			     err_subprocess[1],
			     &pid,
                             new_process_group,
                             windows_chain_termination_to_child,
                             env, current_directory);

    if (!windows_exact_cmdline) {
      for (i = 0; i < argc; i++) {
        free(argv[i]);
      }
      free(argv);
    }

    if (spawn_status != -1)
      sc = (void *)spawn_status;
  }

#else


  /*--------------------------------------*/
  /*            Execute: Unix             */
  /*--------------------------------------*/

  {
#if defined(CENTRALIZED_SIGCHILD)
    centralized_starting_child();
#else
    sc = malloc(sizeof(System_Child));
    sc->id = 0;
    sc->done = 0;

    block_child_signals(rktio, 1);

    /* Relies on signals blocked: */
    init_sigchld(rktio);
#endif

#if defined(__QNX__)
    pid = vfork();
#elif defined(SUBPROCESS_USE_FORK1)
    pid = fork1();
#else
    pid = fork();
#endif

    

    if (pid > 0) {
      /* This is the original process, which needs to manage the 
         newly created child process. */
      
      if (new_process_group || group_proc) {
        /* there's a race condition between this use and the exec(),
           and there's a race condition between the other setpgid() in
           the child processand sending signals from the parent
           process; so, we set in both, and at least one will
           succeed; we could perform better error checking, since
           EACCES is the only expected error */
        int pgid = pid;
        if (group_proc)
          pgid = group_proc->pid;
        setpgid(pid, pgid); /* note: silent failure */
      }

#if defined(CENTRALIZED_SIGCHILD)
      {
        rktio_signal_handle_t *signal_fd;
        int status;
        signal_fd = rktio_get_signal_handle(rktio);
        centralized_register_child(pid, new_process_group || group_proc, signal_fd, &status);

        /* printf("SUBPROCESS  %i\n", pid); */
      }
#else
      sc->next = rktio->system_children;
      rktio->system_children = sc;
      sc->id = pid;
#endif
    } else if (!pid) {
      /* This is the new child process */
      if (new_process_group || group_proc) {
        /* see also setpgid above */
        int actual_pid = getpid();
        int pgid = actual_pid;
        if (group_proc)
          pgid = group_proc->pid;
        setpgid(actual_pid, pgid); /* note: silent failure */
      }
    } else {
      get_posix_error();
    }

#if !defined(CENTRALIZED_SIGCHILD)
    block_child_signals(rktio, 0);
#else
    if (!pid)
      centralized_unblock_child_signal();
    else if (pid == -1)
      centralized_ended_child();
#endif
  }

  switch (pid)
    {
    case -1:
      /* Close all created descriptors */
      if (!stdin_fd) {
	rktio_reliably_close(to_subprocess[0]);
	rktio_reliably_close(to_subprocess[1]);
      } else {
	RKTIO_CLOSE_SUBPROCESS_COPY(to_subprocess, 0);
      }
      if (!stdout_fd) {
	rktio_reliably_close(from_subprocess[0]);
	rktio_reliably_close(from_subprocess[1]);
      } else {
	RKTIO_CLOSE_SUBPROCESS_COPY(from_subprocess, 1);
      }
      if (!stderr_fd) {
        if (!stderr_is_stdout) {
          rktio_reliably_close(err_subprocess[0]);
          rktio_reliably_close(err_subprocess[1]);
        }
      } else {
	RKTIO_CLOSE_SUBPROCESS_COPY(err_subprocess, 1);
      }
      return NULL;

    case 0: /* child */

      {
        int errid;
        
	/* Copy pipe descriptors to stdin and stdout */
	do {
	  errid = MSC_IZE(dup2)(to_subprocess[0], 0);
	} while (errid == -1 && errno == EINTR);
	do {
	  errid = MSC_IZE(dup2)(from_subprocess[1], 1);
	} while (errid == -1 && errno == EINTR);
	do {
	  errid = MSC_IZE(dup2)(err_subprocess[1], 2);
	} while (errid == -1 && errno == EINTR);

	/* Close unwanted descriptors */
	if (!stdin_fd) {
	  rktio_reliably_close(to_subprocess[0]);
	  rktio_reliably_close(to_subprocess[1]);
	}
	if (!stdout_fd) {
	  rktio_reliably_close(from_subprocess[0]);
	  rktio_reliably_close(from_subprocess[1]);
	}
	if (!stderr_fd) {
          if (!stderr_is_stdout) {
            rktio_reliably_close(err_subprocess[0]);
            rktio_reliably_close(err_subprocess[1]);
          }
	}

        rktio_close_fds_after_fork(0, 1, 2);
      }

      /* Set real CWD: */
      if (!rktio_set_current_directory(rktio, current_directory)) {
        fprintf(stderr, "racket: chdir failed to: %s\n", current_directory);
        _exit(1);
      }

      /* Exec new process */

      {
	int err, i;
        rktio_const_string_t *new_argv;

        /* add a NULL terminator */
        new_argv = malloc(sizeof(char *) * (argc + 1));
        for (i = 0; i < argc; i++) {
          new_argv[i] = argv[i];
        }
        new_argv[i] = NULL;

        if (!env)
          env = rktio_get_environ_array();
        
	err = MSC_IZE(execve)(command, (char **)new_argv, (char **)env);
        if (err)
          err = errno;

        if (envvars)
          free(env);

	/* If we get here it failed; give up */

        fprintf(stderr, "exec failed (%s%serrno=%d)\n", 
                strerror(err), "; ",
                err);

	_exit(1);
      }

    default: /* parent */

      break;
    }
#endif

  /*--------------------------------------*/
  /*      Close unneeded descriptors      */
  /*--------------------------------------*/

  free(env);

  if (!stdin_fd)
    RKTIO_CLOSE(to_subprocess[0]);
  else
    RKTIO_CLOSE_SUBPROCESS_COPY(to_subprocess, 0);
  
  if (!stdout_fd) 
    RKTIO_CLOSE(from_subprocess[1]);
  else
    RKTIO_CLOSE_SUBPROCESS_COPY(from_subprocess, 1);
  
  if (!stderr_fd) {
    if (!stderr_is_stdout)
      RKTIO_CLOSE(err_subprocess[1]);
  } else
    RKTIO_CLOSE_SUBPROCESS_COPY(err_subprocess, 1);

  /*--------------------------------------*/
  /*  Create new file-descriptor objects  */
  /*--------------------------------------*/

  result = malloc(sizeof(rktio_process_result_t));

  if (!stdout_fd)
    result->stdout_fd = rktio_system_fd(rktio, from_subprocess[0], RKTIO_OPEN_READ);
  else
    result->stdout_fd = NULL;
  if (!stdin_fd)
    result->stdin_fd = rktio_system_fd(rktio, to_subprocess[1], RKTIO_OPEN_WRITE);
  else
    result->stdin_fd = NULL;
  if (!stderr_fd && !stderr_is_stdout)
    result->stderr_fd = rktio_system_fd(rktio, err_subprocess[0], RKTIO_OPEN_READ);
  else
    result->stderr_fd = NULL;

  /*--------------------------------------*/
  /*          Return result info          */
  /*--------------------------------------*/

  subproc = malloc(sizeof(rktio_process_t));
  memset(subproc, 0, sizeof(rktio_process_t));
#if !defined(CENTRALIZED_SIGCHILD)
  subproc->handle = (void *)sc;
#endif
  subproc->pid = pid;
  subproc->is_group = new_process_group;
  subproc->in_group = (new_process_group || group_proc);

  result->process = subproc;

  return result;
}