diff options
author | Timothy J Fontaine <tjfontaine@gmail.com> | 2014-03-10 17:01:21 -0700 |
---|---|---|
committer | Timothy J Fontaine <tjfontaine@gmail.com> | 2014-03-10 17:01:21 -0700 |
commit | e92d35d80be6e193cb547e94c6fbf3654542dbaa (patch) | |
tree | bede6f090b8cca1397728634b03b31cfa7a4334c /deps/uv/src/unix | |
parent | b444392a98e66b49dfee8c7e36c59d4e7c6ea1ac (diff) | |
download | android-node-v8-e92d35d80be6e193cb547e94c6fbf3654542dbaa.tar.gz android-node-v8-e92d35d80be6e193cb547e94c6fbf3654542dbaa.tar.bz2 android-node-v8-e92d35d80be6e193cb547e94c6fbf3654542dbaa.zip |
uv: Upgrade to v0.11.22
Diffstat (limited to 'deps/uv/src/unix')
-rw-r--r-- | deps/uv/src/unix/core.c | 111 | ||||
-rw-r--r-- | deps/uv/src/unix/fs.c | 4 | ||||
-rw-r--r-- | deps/uv/src/unix/internal.h | 12 | ||||
-rw-r--r-- | deps/uv/src/unix/kqueue.c | 6 | ||||
-rw-r--r-- | deps/uv/src/unix/linux-syscalls.c | 21 | ||||
-rw-r--r-- | deps/uv/src/unix/linux-syscalls.h | 1 | ||||
-rw-r--r-- | deps/uv/src/unix/pipe.c | 28 | ||||
-rw-r--r-- | deps/uv/src/unix/process.c | 7 | ||||
-rw-r--r-- | deps/uv/src/unix/pthread-fixes.c | 23 | ||||
-rw-r--r-- | deps/uv/src/unix/stream.c | 290 | ||||
-rw-r--r-- | deps/uv/src/unix/tty.c | 65 |
11 files changed, 413 insertions, 155 deletions
diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index a84304497c..b393097fd2 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -59,6 +59,15 @@ # include <sys/filio.h> # include <sys/ioctl.h> # include <sys/wait.h> +# define UV__O_CLOEXEC O_CLOEXEC +# if __FreeBSD__ >= 10 +# define uv__accept4 accept4 +# define UV__SOCK_NONBLOCK SOCK_NONBLOCK +# define UV__SOCK_CLOEXEC SOCK_CLOEXEC +# endif +# if !defined(F_DUP2FD_CLOEXEC) && defined(_F_DUP2FD_CLOEXEC) +# define F_DUP2FD_CLOEXEC _F_DUP2FD_CLOEXEC +# endif #endif static void uv__run_pending(uv_loop_t* loop); @@ -371,7 +380,7 @@ int uv__accept(int sockfd) { assert(sockfd >= 0); while (1) { -#if defined(__linux__) +#if defined(__linux__) || __FreeBSD__ >= 10 static int no_accept4; if (no_accept4) @@ -589,16 +598,14 @@ ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) { } -int uv_cwd(char* buffer, size_t size) { - if (buffer == NULL) - return -EINVAL; - - if (size == 0) +int uv_cwd(char* buffer, size_t* size) { + if (buffer == NULL || size == NULL) return -EINVAL; - if (getcwd(buffer, size) == NULL) + if (getcwd(buffer, *size) == NULL) return -errno; + *size = strlen(buffer); return 0; } @@ -817,3 +824,93 @@ int uv_getrusage(uv_rusage_t* rusage) { return 0; } + + +int uv__open_cloexec(const char* path, int flags) { + int err; + int fd; + +#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 9) + static int no_cloexec; + + if (!no_cloexec) { + fd = open(path, flags | UV__O_CLOEXEC); + if (fd != -1) + return fd; + + if (errno != EINVAL) + return -errno; + + /* O_CLOEXEC not supported. */ + no_cloexec = 1; + } +#endif + + fd = open(path, flags); + if (fd == -1) + return -errno; + + err = uv__cloexec(fd, 1); + if (err) { + uv__close(fd); + return err; + } + + return fd; +} + + +int uv__dup2_cloexec(int oldfd, int newfd) { + int r; +#if defined(__FreeBSD__) && __FreeBSD__ >= 10 + do + r = dup3(oldfd, newfd, O_CLOEXEC); + while (r == -1 && errno == EINTR); + if (r == -1) + return -errno; + return r; +#elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC) + do + r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd); + while (r == -1 && errno == EINTR); + if (r != -1) + return r; + if (errno != EINVAL) + return -errno; + /* Fall through. */ +#elif defined(__linux__) + static int no_dup3; + if (!no_dup3) { + do + r = uv__dup3(oldfd, newfd, UV__O_CLOEXEC); + while (r == -1 && (errno == EINTR || errno == EBUSY)); + if (r != -1) + return r; + if (errno != ENOSYS) + return -errno; + /* Fall through. */ + no_dup3 = 1; + } +#endif + { + int err; + do + r = dup2(oldfd, newfd); +#if defined(__linux__) + while (r == -1 && (errno == EINTR || errno == EBUSY)); +#else + while (r == -1 && errno == EINTR); +#endif + + if (r == -1) + return -errno; + + err = uv__cloexec(newfd, 1); + if (err) { + uv__close(newfd); + return err; + } + + return r; + } +} diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index b06f992dc7..cf45669cd9 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -271,7 +271,11 @@ static ssize_t uv__fs_read(uv_fs_t* req) { } +#if defined(__OpenBSD__) || (defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8)) +static int uv__fs_readdir_filter(struct dirent* dent) { +#else static int uv__fs_readdir_filter(const struct dirent* dent) { +#endif return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0; } diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index 4a4656a562..61f5f6aa2f 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -120,6 +120,8 @@ # define O_CLOEXEC 0x00100000 #endif +typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t; + /* handle flags */ enum { UV_CLOSING = 0x01, /* uv_close() called but not finished. */ @@ -142,6 +144,13 @@ typedef enum { UV_CLOCK_FAST = 1 /* Use the fastest clock with <= 1ms granularity. */ } uv_clocktype_t; +struct uv__stream_queued_fds_s { + unsigned int size; + unsigned int offset; + int fds[1]; +}; + + /* core */ int uv__nonblock(int fd, int set); int uv__close(int fd); @@ -180,6 +189,8 @@ int uv__stream_try_select(uv_stream_t* stream, int* fd); #endif /* defined(__APPLE__) */ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); int uv__accept(int sockfd); +int uv__dup2_cloexec(int oldfd, int newfd); +int uv__open_cloexec(const char* path, int flags); /* tcp */ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb); @@ -226,6 +237,7 @@ void uv__tcp_close(uv_tcp_t* handle); void uv__timer_close(uv_timer_t* handle); void uv__udp_close(uv_udp_t* handle); void uv__udp_finish_close(uv_udp_t* handle); +uv_handle_type uv__handle_type(int fd); #if defined(__APPLE__) int uv___stream_fd(uv_stream_t* handle); diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index 5a25e117c9..77064175d6 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -383,10 +383,10 @@ int uv_fs_event_stop(uv_fs_event_t* handle) { #if defined(__APPLE__) if (uv__fsevents_close(handle)) - uv__io_stop(handle->loop, &handle->event_watcher, UV__POLLIN); -#else - uv__io_stop(handle->loop, &handle->event_watcher, UV__POLLIN); #endif /* defined(__APPLE__) */ + { + uv__io_close(handle->loop, &handle->event_watcher); + } free(handle->path); handle->path = NULL; diff --git a/deps/uv/src/unix/linux-syscalls.c b/deps/uv/src/unix/linux-syscalls.c index c9cc44d8cd..1ff8abd197 100644 --- a/deps/uv/src/unix/linux-syscalls.c +++ b/deps/uv/src/unix/linux-syscalls.c @@ -219,6 +219,16 @@ # endif #endif /* __NR_pwritev */ +#ifndef __NR_dup3 +# if defined(__x86_64__) +# define __NR_dup3 292 +# elif defined(__i386__) +# define __NR_dup3 330 +# elif defined(__arm__) +# define __NR_dup3 (UV_SYSCALL_BASE + 358) +# endif +#endif /* __NR_pwritev */ + int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) { #if defined(__i386__) @@ -407,6 +417,7 @@ int uv__utimesat(int dirfd, #endif } + ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) { #if defined(__NR_preadv) return syscall(__NR_preadv, fd, iov, iovcnt, offset); @@ -415,6 +426,7 @@ ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) { #endif } + ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) { #if defined(__NR_pwritev) return syscall(__NR_pwritev, fd, iov, iovcnt, offset); @@ -422,3 +434,12 @@ ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) { return errno = ENOSYS, -1; #endif } + + +int uv__dup3(int oldfd, int newfd, int flags) { +#if defined(__NR_dup3) + return syscall(__NR_dup3, oldfd, newfd, flags); +#else + return errno = ENOSYS, -1; +#endif +} diff --git a/deps/uv/src/unix/linux-syscalls.h b/deps/uv/src/unix/linux-syscalls.h index 6d9ec9f22c..0f0b34b1ed 100644 --- a/deps/uv/src/unix/linux-syscalls.h +++ b/deps/uv/src/unix/linux-syscalls.h @@ -149,5 +149,6 @@ int uv__utimesat(int dirfd, int flags); ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset); ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset); +int uv__dup3(int oldfd, int newfd, int flags); #endif /* UV_LINUX_SYSCALL_H_ */ diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index 34c118b773..a26c3dbc13 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -246,3 +246,31 @@ int uv_pipe_getsockname(const uv_pipe_t* handle, char* buf, size_t* len) { void uv_pipe_pending_instances(uv_pipe_t* handle, int count) { } + + +int uv_pipe_pending_count(uv_pipe_t* handle) { + uv__stream_queued_fds_t* queued_fds; + + if (!handle->ipc) + return 0; + + if (handle->accepted_fd == -1) + return 0; + + if (handle->queued_fds == NULL) + return 1; + + queued_fds = handle->queued_fds; + return queued_fds->offset + 1; +} + + +uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) { + if (!handle->ipc) + return UV_UNKNOWN_HANDLE; + + if (handle->accepted_fd == -1) + return UV_UNKNOWN_HANDLE; + else + return uv__handle_type(handle->accepted_fd); +} diff --git a/deps/uv/src/unix/process.c b/deps/uv/src/unix/process.c index 55f6ac5806..53fef8436b 100644 --- a/deps/uv/src/unix/process.c +++ b/deps/uv/src/unix/process.c @@ -302,8 +302,7 @@ static void uv__process_child_init(const uv_process_options_t* options, close_fd = use_fd; if (use_fd == -1) { - uv__write_int(error_fd, -errno); - perror("failed to open stdio"); + uv__write_int(error_fd, -errno); _exit(127); } } @@ -330,7 +329,6 @@ static void uv__process_child_init(const uv_process_options_t* options, if (options->cwd != NULL && chdir(options->cwd)) { uv__write_int(error_fd, -errno); - perror("chdir()"); _exit(127); } @@ -347,13 +345,11 @@ static void uv__process_child_init(const uv_process_options_t* options, if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) { uv__write_int(error_fd, -errno); - perror("setgid()"); _exit(127); } if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) { uv__write_int(error_fd, -errno); - perror("setuid()"); _exit(127); } @@ -363,7 +359,6 @@ static void uv__process_child_init(const uv_process_options_t* options, execvp(options->file, options->args); uv__write_int(error_fd, -errno); - perror("execvp()"); _exit(127); } diff --git a/deps/uv/src/unix/pthread-fixes.c b/deps/uv/src/unix/pthread-fixes.c index 2e4c542bc2..dc54f35d60 100644 --- a/deps/uv/src/unix/pthread-fixes.c +++ b/deps/uv/src/unix/pthread-fixes.c @@ -29,6 +29,29 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* Android versions < 4.1 have a broken pthread_sigmask. + * Note that this block of code must come before any inclusion of + * pthread-fixes.h so that the real pthread_sigmask can be referenced. + * */ +#include <errno.h> +#include <pthread.h> + +int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) { + static int workaround; + + if (workaround) { + return sigprocmask(how, set, oset); + } else if (pthread_sigmask(how, set, oset)) { + if (errno == EINVAL && sigprocmask(how, set, oset) == 0) { + workaround = 1; + return 0; + } else { + return -1; + } + } else { + return 0; + } +} /*Android doesn't provide pthread_barrier_t for now.*/ #ifndef PTHREAD_BARRIER_SERIAL_THREAD diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index ad6856b4b7..370894bfd6 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -63,36 +63,6 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); static size_t uv__write_req_size(uv_write_t* req); -/* Used by the accept() EMFILE party trick. */ -static int uv__open_cloexec(const char* path, int flags) { - int err; - int fd; - -#if defined(__linux__) - fd = open(path, flags | UV__O_CLOEXEC); - if (fd != -1) - return fd; - - if (errno != EINVAL) - return -errno; - - /* O_CLOEXEC not supported. */ -#endif - - fd = open(path, flags); - if (fd == -1) - return -errno; - - err = uv__cloexec(fd, 1); - if (err) { - uv__close(fd); - return err; - } - - return fd; -} - - static size_t uv_count_bufs(const uv_buf_t bufs[], unsigned int nbufs) { unsigned int i; size_t bytes; @@ -112,13 +82,13 @@ void uv__stream_init(uv_loop_t* loop, uv__handle_init(loop, (uv_handle_t*)stream, type); stream->read_cb = NULL; - stream->read2_cb = NULL; stream->alloc_cb = NULL; stream->close_cb = NULL; stream->connection_cb = NULL; stream->connect_req = NULL; stream->shutdown_req = NULL; stream->accepted_fd = -1; + stream->queued_fds = NULL; stream->delayed_error = 0; QUEUE_INIT(&stream->write_queue); QUEUE_INIT(&stream->write_completed_queue); @@ -570,6 +540,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { if (server->accepted_fd == -1) return -EAGAIN; + err = 0; switch (client->type) { case UV_NAMED_PIPE: case UV_TCP: @@ -579,8 +550,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { if (err) { /* TODO handle error */ uv__close(server->accepted_fd); - server->accepted_fd = -1; - return err; + goto done; } break; @@ -588,8 +558,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { err = uv_udp_open((uv_udp_t*) client, server->accepted_fd); if (err) { uv__close(server->accepted_fd); - server->accepted_fd = -1; - return err; + goto done; } break; @@ -597,9 +566,33 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { assert(0); } - uv__io_start(server->loop, &server->io_watcher, UV__POLLIN); - server->accepted_fd = -1; - return 0; +done: + /* Process queued fds */ + if (server->queued_fds != NULL) { + uv__stream_queued_fds_t* queued_fds; + + queued_fds = server->queued_fds; + + /* Read first */ + server->accepted_fd = queued_fds->fds[0]; + + /* All read, free */ + assert(queued_fds->offset > 0); + if (--queued_fds->offset == 0) { + free(queued_fds); + server->queued_fds = NULL; + } else { + /* Shift rest */ + memmove(queued_fds->fds, + queued_fds->fds + 1, + queued_fds->offset * sizeof(*queued_fds->fds)); + } + } else { + server->accepted_fd = -1; + if (err == 0) + uv__io_start(server->loop, &server->io_watcher, UV__POLLIN); + } + return err; } @@ -777,12 +770,12 @@ start: msg.msg_flags = 0; msg.msg_control = (void*) scratch; - msg.msg_controllen = CMSG_LEN(sizeof(fd_to_send)); + msg.msg_controllen = CMSG_SPACE(sizeof(fd_to_send)); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; - cmsg->cmsg_len = msg.msg_controllen; + cmsg->cmsg_len = CMSG_LEN(sizeof(fd_to_send)); /* silence aliasing warning */ { @@ -913,7 +906,7 @@ static void uv__write_callbacks(uv_stream_t* stream) { } -static uv_handle_type uv__handle_type(int fd) { +uv_handle_type uv__handle_type(int fd) { struct sockaddr_storage ss; socklen_t len; int type; @@ -947,24 +940,106 @@ static uv_handle_type uv__handle_type(int fd) { } -static void uv__stream_read_cb(uv_stream_t* stream, - int status, - const uv_buf_t* buf, - uv_handle_type type) { - if (stream->read_cb != NULL) - stream->read_cb(stream, status, buf); - else - stream->read2_cb((uv_pipe_t*) stream, status, buf, type); -} - - static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) { stream->flags |= UV_STREAM_READ_EOF; uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN); if (!uv__io_active(&stream->io_watcher, UV__POLLOUT)) uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); - uv__stream_read_cb(stream, UV_EOF, buf, UV_UNKNOWN_HANDLE); + stream->read_cb(stream, UV_EOF, buf); +} + + +static int uv__stream_queue_fd(uv_stream_t* stream, int fd) { + uv__stream_queued_fds_t* queued_fds; + unsigned int queue_size; + + queued_fds = stream->queued_fds; + if (queued_fds == NULL) { + queue_size = 8; + queued_fds = malloc((queue_size - 1) * sizeof(*queued_fds->fds) + + sizeof(*queued_fds)); + if (queued_fds == NULL) + return -ENOMEM; + queued_fds->size = queue_size; + queued_fds->offset = 0; + stream->queued_fds = queued_fds; + + /* Grow */ + } else if (queued_fds->size == queued_fds->offset) { + queue_size = queued_fds->size + 8; + queued_fds = realloc(queued_fds, + (queue_size - 1) * sizeof(*queued_fds->fds) + + sizeof(*queued_fds)); + + /* + * Allocation failure, report back. + * NOTE: if it is fatal - sockets will be closed in uv__stream_close + */ + if (queued_fds == NULL) + return -ENOMEM; + queued_fds->size = queue_size; + stream->queued_fds = queued_fds; + } + + /* Put fd in a queue */ + queued_fds->fds[queued_fds->offset++] = fd; + + return 0; +} + + +#define UV__CMSG_FD_COUNT 64 +#define UV__CMSG_FD_SIZE (UV__CMSG_FD_COUNT * sizeof(int)) + + +static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) { + struct cmsghdr* cmsg; + + for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) { + char* start; + char* end; + int err; + void* pv; + int* pi; + unsigned int i; + unsigned int count; + + if (cmsg->cmsg_type != SCM_RIGHTS) { + fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n", + cmsg->cmsg_type); + continue; + } + + /* silence aliasing warning */ + pv = CMSG_DATA(cmsg); + pi = pv; + + /* Count available fds */ + start = (char*) cmsg; + end = (char*) cmsg + cmsg->cmsg_len; + count = 0; + while (start + CMSG_LEN(count * sizeof(*pi)) < end) + count++; + assert(start + CMSG_LEN(count * sizeof(*pi)) == end); + + for (i = 0; i < count; i++) { + /* Already has accepted fd, queue now */ + if (stream->accepted_fd != -1) { + err = uv__stream_queue_fd(stream, pi[i]); + if (err != 0) { + /* Close rest */ + for (; i < count; i++) + uv__close(pi[i]); + return err; + } + } else { + stream->accepted_fd = pi[i]; + } + } + } + + return 0; } @@ -972,9 +1047,10 @@ static void uv__read(uv_stream_t* stream) { uv_buf_t buf; ssize_t nread; struct msghdr msg; - struct cmsghdr* cmsg; - char cmsg_space[64]; + char cmsg_space[CMSG_SPACE(UV__CMSG_FD_SIZE)]; int count; + int err; + int is_ipc; stream->flags &= ~UV_STREAM_READ_PARTIAL; @@ -983,10 +1059,12 @@ static void uv__read(uv_stream_t* stream) { */ count = 32; + is_ipc = stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) stream)->ipc; + /* XXX: Maybe instead of having UV_STREAM_READING we just test if * tcp->read_cb is NULL or not? */ - while ((stream->read_cb || stream->read2_cb) + while (stream->read_cb && (stream->flags & UV_STREAM_READING) && (count-- > 0)) { assert(stream->alloc_cb != NULL); @@ -994,29 +1072,28 @@ static void uv__read(uv_stream_t* stream) { stream->alloc_cb((uv_handle_t*)stream, 64 * 1024, &buf); if (buf.len == 0) { /* User indicates it can't or won't handle the read. */ - uv__stream_read_cb(stream, UV_ENOBUFS, &buf, UV_UNKNOWN_HANDLE); + stream->read_cb(stream, UV_ENOBUFS, &buf); return; } assert(buf.base != NULL); assert(uv__stream_fd(stream) >= 0); - if (stream->read_cb) { + if (!is_ipc) { do { nread = read(uv__stream_fd(stream), buf.base, buf.len); } while (nread < 0 && errno == EINTR); } else { - assert(stream->read2_cb); - /* read2_cb uses recvmsg */ + /* ipc uses recvmsg */ msg.msg_flags = 0; msg.msg_iov = (struct iovec*) &buf; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; /* Set up to receive a descriptor even if one isn't in the message */ - msg.msg_controllen = 64; - msg.msg_control = (void*) cmsg_space; + msg.msg_controllen = sizeof(cmsg_space); + msg.msg_control = cmsg_space; do { nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0); @@ -1032,10 +1109,10 @@ static void uv__read(uv_stream_t* stream) { uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN); uv__stream_osx_interrupt_select(stream); } - uv__stream_read_cb(stream, 0, &buf, UV_UNKNOWN_HANDLE); + stream->read_cb(stream, 0, &buf); } else { /* Error. User should call uv_close(). */ - uv__stream_read_cb(stream, -errno, &buf, UV_UNKNOWN_HANDLE); + stream->read_cb(stream, -errno, &buf); assert(!uv__io_active(&stream->io_watcher, UV__POLLIN) && "stream->read_cb(status=-1) did not call uv_close()"); } @@ -1047,50 +1124,14 @@ static void uv__read(uv_stream_t* stream) { /* Successful read */ ssize_t buflen = buf.len; - if (stream->read_cb) { - stream->read_cb(stream, nread, &buf); - } else { - assert(stream->read2_cb); - - /* - * XXX: Some implementations can send multiple file descriptors in a - * single message. We should be using CMSG_NXTHDR() to walk the - * chain to get at them all. This would require changing the API to - * hand these back up the caller, is a pain. - */ - - for (cmsg = CMSG_FIRSTHDR(&msg); - msg.msg_controllen > 0 && cmsg != NULL; - cmsg = CMSG_NXTHDR(&msg, cmsg)) { - - if (cmsg->cmsg_type == SCM_RIGHTS) { - if (stream->accepted_fd != -1) { - fprintf(stderr, "(libuv) ignoring extra FD received\n"); - } - - /* silence aliasing warning */ - { - void* pv = CMSG_DATA(cmsg); - int* pi = pv; - stream->accepted_fd = *pi; - } - - } else { - fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n", - cmsg->cmsg_type); - } - } - - - if (stream->accepted_fd >= 0) { - stream->read2_cb((uv_pipe_t*) stream, - nread, - &buf, - uv__handle_type(stream->accepted_fd)); - } else { - stream->read2_cb((uv_pipe_t*) stream, nread, &buf, UV_UNKNOWN_HANDLE); + if (is_ipc) { + err = uv__stream_recv_cmsg(stream, &msg); + if (err != 0) { + stream->read_cb(stream, err, NULL); + return; } } + stream->read_cb(stream, nread, &buf); /* Return if we didn't fill the buffer, there is no more data to read. */ if (nread < buflen) { @@ -1102,6 +1143,10 @@ static void uv__read(uv_stream_t* stream) { } +#undef UV__CMSG_FD_COUNT +#undef UV__CMSG_FD_SIZE + + int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE) && "uv_shutdown (unix) only supports uv_handle_t right now"); @@ -1371,10 +1416,9 @@ int uv_try_write(uv_stream_t* stream, } -static int uv__read_start_common(uv_stream_t* stream, - uv_alloc_cb alloc_cb, - uv_read_cb read_cb, - uv_read2_cb read2_cb) { +int uv_read_start(uv_stream_t* stream, + uv_alloc_cb alloc_cb, + uv_read_cb read_cb) { assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE || stream->type == UV_TTY); @@ -1394,7 +1438,6 @@ static int uv__read_start_common(uv_stream_t* stream, assert(alloc_cb); stream->read_cb = read_cb; - stream->read2_cb = read2_cb; stream->alloc_cb = alloc_cb; uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN); @@ -1405,18 +1448,6 @@ static int uv__read_start_common(uv_stream_t* stream, } -int uv_read_start(uv_stream_t* stream, uv_alloc_cb alloc_cb, - uv_read_cb read_cb) { - return uv__read_start_common(stream, alloc_cb, read_cb, NULL); -} - - -int uv_read2_start(uv_stream_t* stream, uv_alloc_cb alloc_cb, - uv_read2_cb read_cb) { - return uv__read_start_common(stream, alloc_cb, NULL, read_cb); -} - - int uv_read_stop(uv_stream_t* stream) { /* Sanity check. We're going to stop the handle unless it's primed for * writing but that means there should be some kind of write action in @@ -1435,7 +1466,6 @@ int uv_read_stop(uv_stream_t* stream) { uv__stream_osx_interrupt_select(stream); stream->read_cb = NULL; - stream->read2_cb = NULL; stream->alloc_cb = NULL; return 0; } @@ -1469,6 +1499,9 @@ int uv___stream_fd(uv_stream_t* handle) { void uv__stream_close(uv_stream_t* handle) { + unsigned int i; + uv__stream_queued_fds_t* queued_fds; + #if defined(__APPLE__) /* Terminate select loop first */ if (handle->select != NULL) { @@ -1506,6 +1539,15 @@ void uv__stream_close(uv_stream_t* handle) { handle->accepted_fd = -1; } + /* Close all queued fds */ + if (handle->queued_fds != NULL) { + queued_fds = handle->queued_fds; + for (i = 0; i < queued_fds->offset; i++) + uv__close(queued_fds->fds[i]); + free(handle->queued_fds); + handle->queued_fds = NULL; + } + assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT)); } diff --git a/deps/uv/src/unix/tty.c b/deps/uv/src/unix/tty.c index ca9459dd0d..c7ed101a75 100644 --- a/deps/uv/src/unix/tty.c +++ b/deps/uv/src/unix/tty.c @@ -35,26 +35,61 @@ static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER; int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { - uv__stream_init(loop, (uv_stream_t*)tty, UV_TTY); + int flags; + int newfd; + int r; + + newfd = -1; + + uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY); + + /* Reopen the file descriptor when it refers to a tty. This lets us put the + * tty in non-blocking mode without affecting other processes that share it + * with us. + * + * Example: `node | cat` - if we put our fd 0 in non-blocking mode, it also + * affects fd 1 of `cat` because both file descriptors refer to the same + * struct file in the kernel. When we reopen our fd 0, it points to a + * different struct file, hence changing its properties doesn't affect + * other processes. + */ + if (isatty(fd)) { + newfd = uv__open_cloexec("/dev/tty", O_RDWR); + + if (newfd == -1) + return -errno; -#if defined(__APPLE__) - { - int err = uv__stream_try_select((uv_stream_t*) tty, &fd); - if (err) - return err; + r = uv__dup2_cloexec(newfd, fd); + if (r < 0 && r != -EINVAL) { + /* EINVAL means newfd == fd which could conceivably happen if another + * thread called close(fd) between our calls to isatty() and open(). + * That's a rather unlikely event but let's handle it anyway. + */ + uv__close(newfd); + return r; + } + + fd = newfd; } -#endif /* defined(__APPLE__) */ - - if (readable) { - uv__nonblock(fd, 1); - uv__stream_open((uv_stream_t*)tty, fd, UV_STREAM_READABLE); - } else { - /* Note: writable tty we set to blocking mode. */ - uv__stream_open((uv_stream_t*)tty, fd, UV_STREAM_WRITABLE); - tty->flags |= UV_STREAM_BLOCKING; + +#if defined(__APPLE__) + r = uv__stream_try_select((uv_stream_t*) tty, &fd); + if (r) { + if (newfd != -1) + uv__close(newfd); + return r; } +#endif + if (readable) + flags = UV_STREAM_READABLE; + else + flags = UV_STREAM_WRITABLE; + + uv__nonblock(fd, 1); + uv__stream_open((uv_stream_t*) tty, fd, flags); tty->mode = 0; + return 0; } |