diff --git a/src/unix/core.c b/src/unix/core.c index 19d5b915..78b90ff5 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -686,22 +686,30 @@ void uv_freeaddrinfo(struct addrinfo* ai) { /* Open a socket in non-blocking close-on-exec mode, atomically if possible. */ int uv__socket(int domain, int type, int protocol) { -#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC) - return socket(domain, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); -#else int sockfd; - if ((sockfd = socket(domain, type, protocol)) == -1) { - return -1; - } +#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC) + sockfd = socket(domain, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol); - if (uv__nonblock(sockfd, 1) == -1 || uv__cloexec(sockfd, 1) == -1) { - uv__close(sockfd); - return -1; - } + if (sockfd != -1) + goto out; - return sockfd; + if (errno != EINVAL) + goto out; #endif + + sockfd = socket(domain, type, protocol); + + if (sockfd == -1) + goto out; + + if (uv__nonblock(sockfd, 1) || uv__cloexec(sockfd, 1)) { + uv__close(sockfd); + sockfd = -1; + } + +out: + return sockfd; } @@ -710,19 +718,34 @@ int uv__accept(int sockfd, struct sockaddr* saddr, socklen_t slen) { assert(sockfd >= 0); - do { -#if defined(HAVE_ACCEPT4) + while (1) { +#if HAVE_ACCEPT4 peerfd = accept4(sockfd, saddr, &slen, SOCK_NONBLOCK | SOCK_CLOEXEC); -#else - if ((peerfd = accept(sockfd, saddr, &slen)) != -1) { - if (uv__cloexec(peerfd, 1) == -1 || uv__nonblock(peerfd, 1) == -1) { - uv__close(peerfd); - return -1; - } - } + + if (peerfd != -1) + break; + + if (errno == EINTR) + continue; + + if (errno != ENOSYS) + break; #endif + + if ((peerfd = accept(sockfd, saddr, &slen)) == -1) { + if (errno == EINTR) + continue; + else + break; + } + + if (uv__cloexec(peerfd, 1) || uv__nonblock(peerfd, 1)) { + uv__close(peerfd); + peerfd = -1; + } + + break; } - while (peerfd == -1 && errno == EINTR); return peerfd; } diff --git a/src/unix/process.c b/src/unix/process.c index 555be5a6..c5a45929 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -63,30 +63,97 @@ static void uv__chld(EV_P_ ev_child* watcher, int revents) { } +#define UV__F_IPC (1 << 0) +#define UV__F_NONBLOCK (1 << 1) + +static int uv__make_socketpair(int fds[2], int flags) { +#ifdef SOCK_NONBLOCK + int fl; + + fl = SOCK_CLOEXEC; + + if (flags & UV__F_NONBLOCK) + fl |= SOCK_NONBLOCK; + + if (socketpair(AF_UNIX, SOCK_STREAM|fl, 0, fds) == 0) + return 0; + + if (errno != EINVAL) + return -1; + + /* errno == EINVAL so maybe the kernel headers lied about + * the availability of SOCK_NONBLOCK. This can happen if people + * build libuv against newer kernel headers than the kernel + * they actually run the software on. + */ +#endif + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) + return -1; + + uv__cloexec(fds[0], 1); + uv__cloexec(fds[1], 1); + + if (flags & UV__F_NONBLOCK) { + uv__nonblock(fds[0], 1); + uv__nonblock(fds[1], 1); + } + + return 0; +} + + +static int uv__make_pipe(int fds[2], int flags) { +#if HAVE_PIPE2 + int fl; + + fl = O_CLOEXEC; + + if (flags & UV__F_NONBLOCK) + fl |= O_NONBLOCK; + + if (pipe2(fds, fl) == 0) + return 0; + + if (errno != ENOSYS) + return -1; + + /* errno == ENOSYS so maybe the kernel headers lied about + * the availability of pipe2(). This can happen if people + * build libuv against newer kernel headers than the kernel + * they actually run the software on. + */ +#endif + + if (pipe(fds)) + return -1; + + uv__cloexec(fds[0], 1); + uv__cloexec(fds[1], 1); + + if (flags & UV__F_NONBLOCK) { + uv__nonblock(fds[0], 1); + uv__nonblock(fds[1], 1); + } + + return 0; +} + + /* * Used for initializing stdio streams like options.stdin_stream. Returns * zero on success. */ -static int uv__process_init_pipe(uv_pipe_t* handle, int fds[2]) { +static int uv__process_init_pipe(uv_pipe_t* handle, int fds[2], int flags) { if (handle->type != UV_NAMED_PIPE) { errno = EINVAL; return -1; } - if (handle->ipc) { - if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { - return -1; - } - } else { - if (pipe(fds) < 0) { - return -1; - } - } - - uv__cloexec(fds[0], 1); - uv__cloexec(fds[1], 1); - - return 0; + if (handle->ipc) + return uv__make_socketpair(fds, flags); + else + return uv__make_pipe(fds, flags); } @@ -118,17 +185,17 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, process->exit_cb = options.exit_cb; if (options.stdin_stream && - uv__process_init_pipe(options.stdin_stream, stdin_pipe)) { + uv__process_init_pipe(options.stdin_stream, stdin_pipe, 0)) { goto error; } if (options.stdout_stream && - uv__process_init_pipe(options.stdout_stream, stdout_pipe)) { + uv__process_init_pipe(options.stdout_stream, stdout_pipe, 0)) { goto error; } if (options.stderr_stream && - uv__process_init_pipe(options.stderr_stream, stderr_pipe)) { + uv__process_init_pipe(options.stderr_stream, stderr_pipe, 0)) { goto error; } @@ -153,19 +220,8 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, * the parent polls the read end until it sees POLLHUP. */ #if SPAWN_WAIT_EXEC -# ifdef HAVE_PIPE2 - if (pipe2(signal_pipe, O_CLOEXEC | O_NONBLOCK) < 0) { + if (uv__make_pipe(signal_pipe, UV__F_NONBLOCK)) goto error; - } -# else - if (socketpair(AF_UNIX, SOCK_STREAM, 0, signal_pipe) < 0) { - goto error; - } - uv__cloexec(signal_pipe[0], 1); - uv__cloexec(signal_pipe[1], 1); - uv__nonblock(signal_pipe[0], 1); - uv__nonblock(signal_pipe[1], 1); -# endif #endif pid = fork();