Example #1
0
/*
 * 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();
}
Example #2
0
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;
}