Esempio n. 1
0
static void
qtcSpawnCb(void *_data)
{
    const QtcSpawnData *data = (const QtcSpawnData*)_data;
    qtcCall(data->cb, data->cb_data);
    execvp(data->file, data->argv);
}
Esempio n. 2
0
int
main()
{
    qtcCall(func_void);
    assert(qtcCall(func_int, arg_int()) == 0);
    assert(arg_int_times == 0);
    func_int = real_func_int;
    assert(qtcCall(func_int, arg_int()) == 10);
    assert(arg_int_times == 1);
    func_void = real_func_void;
    qtcCall(func_void);
    assert(real_func_void_times == 1);
#ifdef __cplusplus
    qtcCall(func_struct);
#endif
    return 0;
}
Esempio n. 3
0
QTC_EXPORT bool
qtcForkBackground(QtcCallback cb, void *data, QtcCallback fail_cb)
{
    QTC_RET_IF_FAIL(cb, false);
    // On linux, waitpid will not accept (discard) SIGCHLD therefore if there is
    // a signal handler registered for SIGCHLD and the child process exit
    // inside waitpid()/wait(), it will be run after the process state is
    // cleared and would therefore block if it call wait() (or waitpid(-1))
    // and if there are other child processes. As a workaround we only call
    // waitpid() if the main program did not set up any signal handlers for
    // SIGCHLD. See (the RATIONALE section of) wait(3P) for more detail.
    pid_t child = fork();
    if (child < 0) {
        return false;
    } else if (child == 0) {
        pid_t grandchild = fork();
        if (grandchild < 0) {
            qtcCall(fail_cb, data);
            _exit(1);
        } else if (grandchild == 0) {
            /* grandchild */
            cb(data);
            _exit(0);
        } else {
            _exit(0);
        }
        return true;
    } else {
        /* parent */
        if (qtcSignalHandlerSet(SIGCHLD)) {
            // If we create a child process, the signal handler will recieve
            // the signal anyway (and there is no way to only block SIGCHLD
            // only for our child process). Since the signal handler may
            // hang and should already take care of getting rid of
            // zombie processes, we do not call waitpid in this case....
            return true;
        }
        // If SIGCHLD is ignored, waitpid will return -1 with errno
        // set to ECHILD, treat this as success (good enough for our purpose
        // and not likely to fail anyway...)
        int status = 0;
        return ((waitpid(child, &status, 0) > 0 && status == 0) ||
                errno == ECHILD);
    }
}
Esempio n. 4
0
QTC_EXPORT bool
qtcForkBackground(QtcCallback cb, void *data, QtcCallback fail_cb)
{
    QTC_RET_IF_FAIL(cb, false);
    // On linux, waitpid will not accept (discard) SIGCHLD therefore if there is
    // a signal handler registered for SIGCHLD and the child process exit
    // inside waitpid()/wait(), it will be run after the process state is
    // cleared and would therefore block if it call wait() (or waitpid(-1))
    // and if there are other child processes. As a workaround we use vfork()
    // to block the parent until direct child exit so that waitpid() will always
    // be called after the process exit and would never hang because of signal
    // handler. See (the RATIONALE section of) wait(3P) for more detail.
    pid_t child = vfork();
    if (child < 0) {
        return false;
    } else if (child == 0) {
        pid_t grandchild = fork();
        if (grandchild < 0) {
            qtcCall(fail_cb, data);
            _exit(1);
        } else if (grandchild == 0) {
            /* grandchild */
            cb(data);
            _exit(0);
        } else {
            _exit(0);
        }
        return true;
    } else {
        /* parent */
        // If SIGCHLD is ignored, waitpid will return -1 with errno
        // set to ECHILD, treat this as success (good enough for our purpose
        // and not likely to fail anyway...)
        int status = 0;
        return ((waitpid(child, &status, 0) > 0 && status == 0) ||
                errno == ECHILD);
    }
}
Esempio n. 5
0
static void
qtcSpawnFailCb(void *_data)
{
    const QtcSpawnData *data = (const QtcSpawnData*)_data;
    qtcCall(data->fail_cb, data->cb_data);
}