def create_child(args, merge_stdio=False, stderr_pipe=False, preexec_fn=None):
    """
    Create a child process whose stdin/stdout is connected to a socket.

    :param args:
        Argument vector for execv() call.
    :param bool merge_stdio:
        If :data:`True`, arrange for `stderr` to be connected to the `stdout`
        socketpair, rather than inherited from the parent process. This may be
        necessary to ensure that not TTY is connected to any stdio handle, for
        instance when using LXC.
    :param bool stderr_pipe:
        If :data:`True` and `merge_stdio` is :data:`False`, arrange for
        `stderr` to be connected to a separate pipe, to allow any ongoing debug
        logs generated by e.g. SSH to be outpu as the session progresses,
        without interfering with `stdout`.
    :returns:
        `(pid, socket_obj, :data:`None` or pipe_fd)`
    """
    parentfp, childfp = create_socketpair()
    # When running under a monkey patches-enabled gevent, the socket module
    # yields file descriptors who already have O_NONBLOCK, which is
    # persisted across fork, totally breaking Python. Therefore, drop
    # O_NONBLOCK from Python's future stdin fd.
    mitogen.core.set_block(childfp.fileno())

    stderr_r = None
    extra = {}
    if merge_stdio:
        extra = {'stderr': childfp}
    elif stderr_pipe:
        stderr_r, stderr_w = os.pipe()
        mitogen.core.set_cloexec(stderr_r)
        mitogen.core.set_cloexec(stderr_w)
        extra = {'stderr': stderr_w}

    try:
        pid = detach_popen(
            args=args,
            stdin=childfp,
            stdout=childfp,
            close_fds=True,
            preexec_fn=preexec_fn,
            **extra
        )
    except Exception:
        childfp.close()
        parentfp.close()
        if stderr_pipe:
            os.close(stderr_r)
            os.close(stderr_w)
        raise

    if stderr_pipe:
        os.close(stderr_w)
    childfp.close()
    # Decouple the socket from the lifetime of the Python socket object.
    fd = os.dup(parentfp.fileno())
    parentfp.close()

    LOG.debug('create_child() child %d fd %d, parent %d, cmd: %s',
              pid, fd, os.getpid(), Argv(args))
    return pid, fd, stderr_r
Create a child process whose stdin/stdout is connected to a socket.

    :param args:
        Argument vector for execv() call.
    :param bool merge_stdio:
        If :data:`True`, arrange for `stderr` to be connected to the `stdout`
        socketpair, rather than inherited from the parent process. This may be
        necessary to ensure that not TTY is connected to any stdio handle, for
        instance when using LXC.
    :param bool stderr_pipe:
        If :data:`True` and `merge_stdio` is :data:`False`, arrange for
        `stderr` to be connected to a separate pipe, to allow any ongoing debug
        logs generated by e.g. SSH to be outpu as the session progresses,
        without interfering with `stdout`.
    :returns:
        `(pid, socket_obj, :data:`None` or pipe_fd)`