/* * Function: startSignalHandlers() * * Run the handlers associated with the stacked up console events. Console * event delivery is blocked for the duration of this call. */ void startSignalHandlers(Capability *cap) { StgStablePtr handler; if (console_handler < 0) { return; } blockUserSignals(); ACQUIRE_LOCK(&sched_mutex); handler = deRefStablePtr((StgStablePtr)console_handler); while (stg_pending_events > 0) { stg_pending_events--; scheduleThread(cap, createIOThread(cap, RtsFlags.GcFlags.initialStkSize, rts_apply(cap, (StgClosure *)handler, rts_mkInt(cap, stg_pending_buf[stg_pending_events])))); } RELEASE_LOCK(&sched_mutex); unblockUserSignals(); }
ProcHandle runInteractiveProcess (char *const args[], char *workingDirectory, char **environment, int fdStdIn, int fdStdOut, int fdStdErr, int *pfdStdInput, int *pfdStdOutput, int *pfdStdError, int set_inthandler, long inthandler, int set_quithandler, long quithandler, int close_fds) { int pid; int fdStdInput[2], fdStdOutput[2], fdStdError[2]; int r; struct sigaction dfl; // Ordering matters here, see below [Note #431]. if (fdStdIn == -1) { r = pipe(fdStdInput); if (r == -1) { sysErrorBelch("runInteractiveProcess: pipe"); return -1; } } if (fdStdOut == -1) { r = pipe(fdStdOutput); if (r == -1) { sysErrorBelch("runInteractiveProcess: pipe"); return -1; } } if (fdStdErr == -1) { r = pipe(fdStdError); if (r == -1) { sysErrorBelch("runInteractiveProcess: pipe"); return -1; } } // Block signals with Haskell handlers. The danger here is that // with the threaded RTS, a signal arrives in the child process, // the RTS writes the signal information into the pipe (which is // shared between parent and child), and the parent behaves as if // the signal had been raised. blockUserSignals(); // See #4074. Sometimes fork() gets interrupted by the timer // signal and keeps restarting indefinitely. stopTimer(); switch(pid = fork()) { case -1: unblockUserSignals(); #if __GLASGOW_HASKELL__ > 612 startTimer(); #endif if (fdStdIn == -1) { close(fdStdInput[0]); close(fdStdInput[1]); } if (fdStdOut == -1) { close(fdStdOutput[0]); close(fdStdOutput[1]); } if (fdStdErr == -1) { close(fdStdError[0]); close(fdStdError[1]); } return -1; case 0: { // WARNING! we are now in the child of vfork(), so any memory // we modify below will also be seen in the parent process. unblockUserSignals(); if (workingDirectory) { if (chdir (workingDirectory) < 0) { // See #1593. The convention for the exit code when // exec() fails seems to be 127 (gleened from C's // system()), but there's no equivalent convention for // chdir(), so I'm picking 126 --SimonM. _exit(126); } } // [Note #431]: Ordering matters here. If any of the FDs // 0,1,2 were initially closed, then our pipes may have used // these FDs. So when we dup2 the pipe FDs down to 0,1,2, we // must do it in that order, otherwise we could overwrite an // FD that we need later. if (fdStdIn == -1) { if (fdStdInput[0] != STDIN_FILENO) { dup2 (fdStdInput[0], STDIN_FILENO); close(fdStdInput[0]); } close(fdStdInput[1]); } else { dup2(fdStdIn, STDIN_FILENO); } if (fdStdOut == -1) { if (fdStdOutput[1] != STDOUT_FILENO) { dup2 (fdStdOutput[1], STDOUT_FILENO); close(fdStdOutput[1]); } close(fdStdOutput[0]); } else { dup2(fdStdOut, STDOUT_FILENO); } if (fdStdErr == -1) { if (fdStdError[1] != STDERR_FILENO) { dup2 (fdStdError[1], STDERR_FILENO); close(fdStdError[1]); } close(fdStdError[0]); } else { dup2(fdStdErr, STDERR_FILENO); } if (close_fds) { int i; if (max_fd == 0) { #if HAVE_SYSCONF max_fd = sysconf(_SC_OPEN_MAX); if (max_fd == -1) { max_fd = 256; } #else max_fd = 256; #endif } for (i = 3; i < max_fd; i++) { close(i); } } /* Set the SIGINT/SIGQUIT signal handlers in the child, if requested */ (void)sigemptyset(&dfl.sa_mask); dfl.sa_flags = 0; if (set_inthandler) { dfl.sa_handler = (void *)inthandler; (void)sigaction(SIGINT, &dfl, NULL); } if (set_quithandler) { dfl.sa_handler = (void *)quithandler; (void)sigaction(SIGQUIT, &dfl, NULL); } /* the child */ if (environment) { execvpe(args[0], args, environment); } else { execvp(args[0], args); } } _exit(127); default: if (fdStdIn == -1) { close(fdStdInput[0]); fcntl(fdStdInput[1], F_SETFD, FD_CLOEXEC); *pfdStdInput = fdStdInput[1]; } if (fdStdOut == -1) { close(fdStdOutput[1]); fcntl(fdStdOutput[0], F_SETFD, FD_CLOEXEC); *pfdStdOutput = fdStdOutput[0]; } if (fdStdErr == -1) { close(fdStdError[1]); fcntl(fdStdError[0], F_SETFD, FD_CLOEXEC); *pfdStdError = fdStdError[0]; } break; } unblockUserSignals(); startTimer(); return pid; }