diff options
author | Saúl Ibarra Corretgé <saghul@gmail.com> | 2016-05-17 00:25:23 +0200 |
---|---|---|
committer | Saúl Ibarra Corretgé <saghul@gmail.com> | 2016-05-17 02:28:48 +0200 |
commit | b78a7043699093c46d5d71992184f4c40ab5c4b5 (patch) | |
tree | 7ee0fc8474ae60c4be545965ae18882ef1964027 /deps/uv/src | |
parent | f293d0b0c85b2d1b9e0d3938dd38cf1cacac6970 (diff) | |
download | android-node-v8-b78a7043699093c46d5d71992184f4c40ab5c4b5.tar.gz android-node-v8-b78a7043699093c46d5d71992184f4c40ab5c4b5.tar.bz2 android-node-v8-b78a7043699093c46d5d71992184f4c40ab5c4b5.zip |
deps: upgrade libuv to 1.9.1
Fixes: https://github.com/nodejs/node/issues/4002
Fixes: https://github.com/nodejs/node/issues/5384
Fixes: https://github.com/nodejs/node/issues/6563
Refs: https://github.com/nodejs/node/issues/2680#issuecomment-213521708
PR-URL: https://github.com/nodejs/node/pull/6796
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Johan Bergström <bugs@bergstroem.nu>
Reviewed-By: Myles Borins <myles.borins@gmail.com>
Diffstat (limited to 'deps/uv/src')
27 files changed, 631 insertions, 493 deletions
diff --git a/deps/uv/src/unix/aix.c b/deps/uv/src/unix/aix.c index bcaa5ee50b..2276985fc0 100644 --- a/deps/uv/src/unix/aix.c +++ b/deps/uv/src/unix/aix.c @@ -118,6 +118,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { uv__io_t* w; uint64_t base; uint64_t diff; + int have_signals; int nevents; int count; int nfds; @@ -225,6 +226,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { goto update_timeout; } + have_signals = 0; nevents = 0; assert(loop->watchers != NULL); @@ -255,13 +257,26 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { continue; } - w->cb(loop, w, pe->revents); + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, pe->revents); + nevents++; } + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + loop->watchers[loop->nwatchers] = NULL; loop->watchers[loop->nwatchers + 1] = NULL; + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { /* Poll for more events but don't block this time. */ @@ -782,53 +797,30 @@ int uv_fs_event_start(uv_fs_event_t* handle, const char* filename, unsigned int flags) { #ifdef HAVE_SYS_AHAFS_EVPRODS_H - int fd, rc, i = 0, res = 0; + int fd, rc, str_offset = 0; char cwd[PATH_MAX]; char absolute_path[PATH_MAX]; - char fname[PATH_MAX]; - char *p; + char readlink_cwd[PATH_MAX]; - /* Clean all the buffers*/ - for(i = 0; i < PATH_MAX; i++) { - cwd[i] = 0; - absolute_path[i] = 0; - fname[i] = 0; - } - i = 0; /* Figure out whether filename is absolute or not */ if (filename[0] == '/') { - /* We have absolute pathname, create the relative pathname*/ - sprintf(absolute_path, filename); - p = strrchr(filename, '/'); - p++; + /* We have absolute pathname */ + snprintf(absolute_path, sizeof(absolute_path), "%s", filename); } else { - if (filename[0] == '.' && filename[1] == '/') { - /* We have a relative pathname, compose the absolute pathname */ - sprintf(fname, filename); - snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid()); - res = readlink(cwd, absolute_path, sizeof(absolute_path) - 1); - if (res < 0) - return res; - p = strrchr(absolute_path, '/'); - p++; - p++; - } else { - /* We have a relative pathname, compose the absolute pathname */ - sprintf(fname, filename); - snprintf(cwd, PATH_MAX-1, "/proc/%lu/cwd", (unsigned long) getpid()); - res = readlink(cwd, absolute_path, sizeof(absolute_path) - 1); - if (res < 0) - return res; - p = strrchr(absolute_path, '/'); - p++; - } - /* Copy to filename buffer */ - while(filename[i] != NULL) { - *p = filename[i]; - i++; - p++; - } + /* We have a relative pathname, compose the absolute pathname */ + snprintf(cwd, sizeof(cwd), "/proc/%lu/cwd", (unsigned long) getpid()); + rc = readlink(cwd, readlink_cwd, sizeof(readlink_cwd) - 1); + if (rc < 0) + return rc; + /* readlink does not null terminate our string */ + readlink_cwd[rc] = '\0'; + + if (filename[0] == '.' && filename[1] == '/') + str_offset = 2; + + snprintf(absolute_path, sizeof(absolute_path), "%s%s", readlink_cwd, + filename + str_offset); } if (uv__is_ahafs_mounted() < 0) /* /aha checks failed */ @@ -845,7 +837,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, handle->path = uv__strdup(filename); handle->cb = cb; - uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN); + uv__io_start(handle->loop, &handle->event_watcher, POLLIN); return 0; #else @@ -1036,14 +1028,14 @@ int uv_interface_addresses(uv_interface_address_t** addresses, } if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) { - SAVE_ERRNO(uv__close(sockfd)); + uv__close(sockfd); return -errno; } ifc.ifc_req = (struct ifreq*)uv__malloc(size); ifc.ifc_len = size; if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) { - SAVE_ERRNO(uv__close(sockfd)); + uv__close(sockfd); return -errno; } @@ -1062,7 +1054,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name)); if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) { - SAVE_ERRNO(uv__close(sockfd)); + uv__close(sockfd); return -errno; } diff --git a/deps/uv/src/unix/async.c b/deps/uv/src/unix/async.c index 184b598126..393cdebd4e 100644 --- a/deps/uv/src/unix/async.c +++ b/deps/uv/src/unix/async.c @@ -223,7 +223,7 @@ int uv__async_start(uv_loop_t* loop, struct uv__async* wa, uv__async_cb cb) { return err; uv__io_init(&wa->io_watcher, uv__async_io, pipefd[0]); - uv__io_start(loop, &wa->io_watcher, UV__POLLIN); + uv__io_start(loop, &wa->io_watcher, POLLIN); wa->wfd = pipefd[1]; wa->cb = cb; @@ -241,7 +241,7 @@ void uv__async_stop(uv_loop_t* loop, struct uv__async* wa) { wa->wfd = -1; } - uv__io_stop(loop, &wa->io_watcher, UV__POLLIN); + uv__io_stop(loop, &wa->io_watcher, POLLIN); uv__close(wa->io_watcher.fd); wa->io_watcher.fd = -1; } diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 9aaca84187..cdcd0b504f 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -762,7 +762,7 @@ static int uv__run_pending(uv_loop_t* loop) { QUEUE_REMOVE(q); QUEUE_INIT(q); w = QUEUE_DATA(q, uv__io_t, pending_queue); - w->cb(loop, w, UV__POLLOUT); + w->cb(loop, w, POLLOUT); } return 1; @@ -833,7 +833,7 @@ void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) { void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP))); + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); assert(0 != events); assert(w->fd >= 0); assert(w->fd < INT_MAX); @@ -866,7 +866,7 @@ void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) { void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP))); + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); assert(0 != events); if (w->fd == -1) @@ -898,7 +898,7 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) { void uv__io_close(uv_loop_t* loop, uv__io_t* w) { - uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP); + uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP); QUEUE_REMOVE(&w->pending_queue); /* Remove stale events for this file descriptor */ @@ -913,7 +913,7 @@ void uv__io_feed(uv_loop_t* loop, uv__io_t* w) { int uv__io_active(const uv__io_t* w, unsigned int events) { - assert(0 == (events & ~(UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP))); + assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP))); assert(0 != events); return 0 != (w->pevents & events); } diff --git a/deps/uv/src/unix/freebsd.c b/deps/uv/src/unix/freebsd.c index b747abdf5b..adc95235ce 100644 --- a/deps/uv/src/unix/freebsd.c +++ b/deps/uv/src/unix/freebsd.c @@ -292,7 +292,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { size = sizeof(cpuspeed); if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) { - SAVE_ERRNO(uv__free(*cpu_infos)); + uv__free(*cpu_infos); return -errno; } @@ -301,7 +301,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { */ size = sizeof(maxcpus); if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) { - SAVE_ERRNO(uv__free(*cpu_infos)); + uv__free(*cpu_infos); return -errno; } @@ -314,8 +314,8 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { } if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) { - SAVE_ERRNO(uv__free(cp_times)); - SAVE_ERRNO(uv__free(*cpu_infos)); + uv__free(cp_times); + uv__free(*cpu_infos); return -errno; } diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index 8936ad9d83..085970a06d 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -33,6 +33,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <limits.h> /* PATH_MAX */ #include <sys/types.h> #include <sys/socket.h> @@ -205,6 +206,13 @@ skip: # else return futimes(req->file, tv); # endif +#elif defined(_AIX71) + struct timespec ts[2]; + ts[0].tv_sec = req->atime; + ts[0].tv_nsec = (unsigned long)(req->atime * 1000000) % 1000000 * 1000; + ts[1].tv_sec = req->mtime; + ts[1].tv_nsec = (unsigned long)(req->mtime * 1000000) % 1000000 * 1000; + return futimens(req->file, ts); #else errno = ENOSYS; return -1; @@ -362,9 +370,10 @@ out: if (dents != NULL) { int i; + /* Memory was allocated using the system allocator, so use free() here. */ for (i = 0; i < n; i++) - uv__free(dents[i]); - uv__free(dents); + free(dents[i]); + free(dents); } errno = saved_errno; @@ -383,7 +392,7 @@ static ssize_t uv__fs_pathmax_size(const char* path) { #if defined(PATH_MAX) return PATH_MAX; #else - return 4096; +#error "PATH_MAX undefined in the current platform" #endif } diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index 938e76f1d1..670b14bc2a 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -44,15 +44,25 @@ #endif /* __sun */ #if defined(_AIX) -#define reqevents events -#define rtnevents revents -#include <sys/poll.h> +# define reqevents events +# define rtnevents revents +# include <sys/poll.h> +#else +# include <poll.h> #endif /* _AIX */ #if defined(__APPLE__) && !TARGET_OS_IPHONE # include <CoreServices/CoreServices.h> #endif +#if defined(__ANDROID__) +int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset); +# ifdef pthread_sigmask +# undef pthread_sigmask +# endif +# define pthread_sigmask(how, set, oldset) uv__pthread_sigmask(how, set, oldset) +#endif + #define ACCESS_ONCE(type, var) \ (*(volatile type*) &(var)) @@ -89,43 +99,11 @@ # define UV_UNUSED(declaration) declaration #endif -#if defined(__linux__) -# define UV__POLLIN UV__EPOLLIN -# define UV__POLLOUT UV__EPOLLOUT -# define UV__POLLERR UV__EPOLLERR -# define UV__POLLHUP UV__EPOLLHUP -# define UV__POLLRDHUP UV__EPOLLRDHUP -#endif - -#if defined(__sun) || defined(_AIX) -# define UV__POLLIN POLLIN -# define UV__POLLOUT POLLOUT -# define UV__POLLERR POLLERR -# define UV__POLLHUP POLLHUP -#endif - -#ifndef UV__POLLIN -# define UV__POLLIN 1 -#endif - -#ifndef UV__POLLOUT -# define UV__POLLOUT 2 -#endif - -#ifndef UV__POLLERR -# define UV__POLLERR 4 -#endif - -#ifndef UV__POLLHUP -# define UV__POLLHUP 8 -#endif - -#ifndef UV__POLLRDHUP -# ifdef POLLRDHUP -# define UV__POLLRDHUP POLLRDHUP -# else -# define UV__POLLRDHUP 0x200 -# endif +/* Leans on the fact that, on Linux, POLLRDHUP == EPOLLRDHUP. */ +#ifdef POLLRDHUP +# define UV__POLLRDHUP POLLRDHUP +#else +# define UV__POLLRDHUP 0x2000 #endif #if !defined(O_CLOEXEC) && defined(__FreeBSD__) diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index 400b4a4b7c..fffd4626f1 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -78,6 +78,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { sigset_t set; uint64_t base; uint64_t diff; + int have_signals; int filter; int fflags; int count; @@ -103,7 +104,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { assert(w->fd >= 0); assert(w->fd < (int) loop->nwatchers); - if ((w->events & UV__POLLIN) == 0 && (w->pevents & UV__POLLIN) != 0) { + if ((w->events & POLLIN) == 0 && (w->pevents & POLLIN) != 0) { filter = EVFILT_READ; fflags = 0; op = EV_ADD; @@ -124,7 +125,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } } - if ((w->events & UV__POLLOUT) == 0 && (w->pevents & UV__POLLOUT) != 0) { + if ((w->events & POLLOUT) == 0 && (w->pevents & POLLOUT) != 0) { EV_SET(events + nevents, w->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0); if (++nevents == ARRAY_SIZE(events)) { @@ -192,6 +193,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { goto update_timeout; } + have_signals = 0; nevents = 0; assert(loop->watchers != NULL); @@ -219,8 +221,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } if (ev->filter == EVFILT_VNODE) { - assert(w->events == UV__POLLIN); - assert(w->pevents == UV__POLLIN); + assert(w->events == POLLIN); + assert(w->pevents == POLLIN); w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */ nevents++; continue; @@ -229,8 +231,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { revents = 0; if (ev->filter == EVFILT_READ) { - if (w->pevents & UV__POLLIN) { - revents |= UV__POLLIN; + if (w->pevents & POLLIN) { + revents |= POLLIN; w->rcount = ev->data; } else { /* TODO batch up */ @@ -243,8 +245,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } if (ev->filter == EVFILT_WRITE) { - if (w->pevents & UV__POLLOUT) { - revents |= UV__POLLOUT; + if (w->pevents & POLLOUT) { + revents |= POLLOUT; w->wcount = ev->data; } else { /* TODO batch up */ @@ -257,7 +259,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { } if (ev->flags & EV_ERROR) - revents |= UV__POLLERR; + revents |= POLLERR; if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP)) revents |= UV__POLLRDHUP; @@ -265,12 +267,26 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (revents == 0) continue; - w->cb(loop, w, revents); + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, revents); + nevents++; } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + loop->watchers[loop->nwatchers] = NULL; loop->watchers[loop->nwatchers + 1] = NULL; + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { /* Poll for more events but don't block this time. */ @@ -409,7 +425,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, fallback: #endif /* defined(__APPLE__) */ - uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN); + uv__io_start(handle->loop, &handle->event_watcher, POLLIN); return 0; } diff --git a/deps/uv/src/unix/linux-core.c b/deps/uv/src/unix/linux-core.c index fb8ac3f237..b48a111170 100644 --- a/deps/uv/src/unix/linux-core.c +++ b/deps/uv/src/unix/linux-core.c @@ -18,6 +18,11 @@ * IN THE SOFTWARE. */ +/* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their + * EPOLL* counterparts. We use the POLL* variants in this file because that + * is what libuv uses elsewhere and it avoids a dependency on <sys/epoll.h>. + */ + #include "uv.h" #include "internal.h" @@ -69,7 +74,9 @@ #endif static int read_models(unsigned int numcpus, uv_cpu_info_t* ci); -static int read_times(FILE* statfile_fp, unsigned int numcpus, uv_cpu_info_t* ci); +static int read_times(FILE* statfile_fp, + unsigned int numcpus, + uv_cpu_info_t* ci); static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci); static unsigned long read_cpufreq(unsigned int cpunum); @@ -102,7 +109,7 @@ int uv__platform_loop_init(uv_loop_t* loop) { void uv__platform_loop_delete(uv_loop_t* loop) { if (loop->inotify_fd == -1) return; - uv__io_stop(loop, &loop->inotify_read_watcher, UV__POLLIN); + uv__io_stop(loop, &loop->inotify_read_watcher, POLLIN); uv__close(loop->inotify_fd); loop->inotify_fd = -1; } @@ -144,7 +151,7 @@ int uv__io_check_fd(uv_loop_t* loop, int fd) { struct uv__epoll_event e; int rc; - e.events = UV__EPOLLIN; + e.events = POLLIN; e.data = -1; rc = 0; @@ -181,6 +188,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { sigset_t sigset; uint64_t sigmask; uint64_t base; + int have_signals; int nevents; int count; int nfds; @@ -308,6 +316,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { goto update_timeout; } + have_signals = 0; nevents = 0; assert(loop->watchers != NULL); @@ -341,7 +350,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * the current watcher. Also, filters out events that users has not * requested us to watch. */ - pe->events &= w->pevents | UV__POLLERR | UV__POLLHUP; + pe->events &= w->pevents | POLLERR | POLLHUP; /* Work around an epoll quirk where it sometimes reports just the * EPOLLERR or EPOLLHUP event. In order to force the event loop to @@ -358,17 +367,31 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { * needs to remember the error/hangup event. We should get that for * free when we switch over to edge-triggered I/O. */ - if (pe->events == UV__EPOLLERR || pe->events == UV__EPOLLHUP) - pe->events |= w->pevents & (UV__EPOLLIN | UV__EPOLLOUT); + if (pe->events == POLLERR || pe->events == POLLHUP) + pe->events |= w->pevents & (POLLIN | POLLOUT); if (pe->events != 0) { - w->cb(loop, w, pe->events); + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, pe->events); + nevents++; } } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + loop->watchers[loop->nwatchers] = NULL; loop->watchers[loop->nwatchers + 1] = NULL; + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { /* Poll for more events but don't block this time. */ @@ -557,7 +580,7 @@ static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) { char buf[1024]; if (!fgets(buf, sizeof(buf), statfile_fp)) - abort(); + return -EIO; num = 0; while (fgets(buf, sizeof(buf), statfile_fp)) { @@ -566,6 +589,9 @@ static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) { num++; } + if (num == 0) + return -EIO; + *numcpus = num; return 0; } @@ -586,26 +612,20 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { err = uv__cpu_num(statfile_fp, &numcpus); if (err < 0) - return err; - - assert(numcpus != (unsigned int) -1); - assert(numcpus != 0); + goto out; + err = -ENOMEM; ci = uv__calloc(numcpus, sizeof(*ci)); if (ci == NULL) - return -ENOMEM; + goto out; err = read_models(numcpus, ci); if (err == 0) err = read_times(statfile_fp, numcpus, ci); - if (fclose(statfile_fp)) - if (errno != EINTR && errno != EINPROGRESS) - abort(); - if (err) { uv_free_cpu_info(ci, numcpus); - return err; + goto out; } /* read_models() on x86 also reads the CPU speed from /proc/cpuinfo. @@ -616,8 +636,15 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { *cpu_infos = ci; *count = numcpus; + err = 0; - return 0; +out: + + if (fclose(statfile_fp)) + if (errno != EINTR && errno != EINPROGRESS) + abort(); + + return err; } @@ -727,7 +754,9 @@ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { } -static int read_times(FILE* statfile_fp, unsigned int numcpus, uv_cpu_info_t* ci) { +static int read_times(FILE* statfile_fp, + unsigned int numcpus, + uv_cpu_info_t* ci) { unsigned long clock_ticks; struct uv_cpu_times_s ts; unsigned long user; diff --git a/deps/uv/src/unix/linux-inotify.c b/deps/uv/src/unix/linux-inotify.c index 282912115d..4708c051d3 100644 --- a/deps/uv/src/unix/linux-inotify.c +++ b/deps/uv/src/unix/linux-inotify.c @@ -102,7 +102,7 @@ static int init_inotify(uv_loop_t* loop) { loop->inotify_fd = err; uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd); - uv__io_start(loop, &loop->inotify_read_watcher, UV__POLLIN); + uv__io_start(loop, &loop->inotify_read_watcher, POLLIN); return 0; } diff --git a/deps/uv/src/unix/linux-syscalls.h b/deps/uv/src/unix/linux-syscalls.h index 4260df111f..4c095e9b53 100644 --- a/deps/uv/src/unix/linux-syscalls.h +++ b/deps/uv/src/unix/linux-syscalls.h @@ -72,14 +72,6 @@ #define UV__EPOLL_CTL_DEL 2 #define UV__EPOLL_CTL_MOD 3 -#define UV__EPOLLIN 1 -#define UV__EPOLLOUT 4 -#define UV__EPOLLERR 8 -#define UV__EPOLLHUP 16 -#define UV__EPOLLRDHUP 0x2000 -#define UV__EPOLLONESHOT 0x40000000 -#define UV__EPOLLET 0x80000000 - /* inotify flags */ #define UV__IN_ACCESS 0x001 #define UV__IN_MODIFY 0x002 diff --git a/deps/uv/src/unix/openbsd.c b/deps/uv/src/unix/openbsd.c index 6a3909a666..8c40bde40f 100644 --- a/deps/uv/src/unix/openbsd.c +++ b/deps/uv/src/unix/openbsd.c @@ -247,7 +247,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { which[1] = HW_CPUSPEED; size = sizeof(cpuspeed); if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) { - SAVE_ERRNO(uv__free(*cpu_infos)); + uv__free(*cpu_infos); return -errno; } @@ -258,7 +258,7 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { which[2] = i; size = sizeof(info); if (sysctl(which, 3, &info, &size, NULL, 0)) { - SAVE_ERRNO(uv__free(*cpu_infos)); + uv__free(*cpu_infos); return -errno; } diff --git a/deps/uv/src/unix/pipe.c b/deps/uv/src/unix/pipe.c index d4fdfa9d5a..c8d163dcc7 100644 --- a/deps/uv/src/unix/pipe.c +++ b/deps/uv/src/unix/pipe.c @@ -102,7 +102,7 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { handle->connection_cb = cb; handle->io_watcher.cb = uv__server_io; - uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN); + uv__io_start(handle->loop, &handle->io_watcher, POLLIN); return 0; } @@ -185,7 +185,7 @@ void uv_pipe_connect(uv_connect_t* req, } if (err == 0) - uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN | UV__POLLOUT); + uv__io_start(handle->loop, &handle->io_watcher, POLLIN | POLLOUT); out: handle->delayed_error = err; diff --git a/deps/uv/src/unix/poll.c b/deps/uv/src/unix/poll.c index e5efb17160..0d5944b0af 100644 --- a/deps/uv/src/unix/poll.c +++ b/deps/uv/src/unix/poll.c @@ -33,17 +33,17 @@ static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { handle = container_of(w, uv_poll_t, io_watcher); - if (events & UV__POLLERR) { - uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP); + if (events & POLLERR) { + uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP); uv__handle_stop(handle); handle->poll_cb(handle, -EBADF, 0); return; } pevents = 0; - if (events & UV__POLLIN) + if (events & POLLIN) pevents |= UV_READABLE; - if (events & UV__POLLOUT) + if (events & POLLOUT) pevents |= UV_WRITABLE; if (events & UV__POLLRDHUP) pevents |= UV_DISCONNECT; @@ -79,7 +79,7 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, static void uv__poll_stop(uv_poll_t* handle) { uv__io_stop(handle->loop, &handle->io_watcher, - UV__POLLIN | UV__POLLOUT | UV__POLLRDHUP); + POLLIN | POLLOUT | UV__POLLRDHUP); uv__handle_stop(handle); } @@ -104,9 +104,9 @@ int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) { events = 0; if (pevents & UV_READABLE) - events |= UV__POLLIN; + events |= POLLIN; if (pevents & UV_WRITABLE) - events |= UV__POLLOUT; + events |= POLLOUT; if (pevents & UV_DISCONNECT) events |= UV__POLLRDHUP; diff --git a/deps/uv/src/unix/pthread-barrier.c b/deps/uv/src/unix/pthread-barrier.c new file mode 100644 index 0000000000..f57bf25080 --- /dev/null +++ b/deps/uv/src/unix/pthread-barrier.c @@ -0,0 +1,120 @@ +/* +Copyright (c) 2016, Kari Tristan Helgason <kthelgason@gmail.com> + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +#include "uv-common.h" +#include "pthread-barrier.h" + +#include <stdlib.h> +#include <assert.h> + +/* TODO: support barrier_attr */ +int pthread_barrier_init(pthread_barrier_t* barrier, + const void* barrier_attr, + unsigned count) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || count == 0) + return EINVAL; + + if (barrier_attr != NULL) + return ENOTSUP; + + b = uv__malloc(sizeof(*b)); + if (b == NULL) + return ENOMEM; + + b->in = 0; + b->out = 0; + b->threshold = count; + + if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0) + goto error2; + if ((rc = pthread_cond_init(&b->cond, NULL)) != 0) + goto error; + + barrier->b = b; + return 0; + +error: + pthread_mutex_destroy(&b->mutex); +error2: + uv__free(b); + return rc; +} + +int pthread_barrier_wait(pthread_barrier_t* barrier) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || barrier->b == NULL) + return EINVAL; + + b = barrier->b; + /* Lock the mutex*/ + if ((rc = pthread_mutex_lock(&b->mutex)) != 0) + return rc; + + /* Increment the count. If this is the first thread to reach the threshold, + wake up waiters, unlock the mutex, then return + PTHREAD_BARRIER_SERIAL_THREAD. */ + if (++b->in == b->threshold) { + b->in = 0; + b->out = b->threshold - 1; + assert(pthread_cond_signal(&b->cond) == 0); + + pthread_mutex_unlock(&b->mutex); + return PTHREAD_BARRIER_SERIAL_THREAD; + } + /* Otherwise, wait for other threads until in is set to 0, + then return 0 to indicate this is not the first thread. */ + do { + if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0) + break; + } while (b->in != 0); + + /* mark thread exit */ + b->out--; + pthread_cond_signal(&b->cond); + pthread_mutex_unlock(&b->mutex); + return rc; +} + +int pthread_barrier_destroy(pthread_barrier_t* barrier) { + int rc; + _uv_barrier* b; + + if (barrier == NULL || barrier->b == NULL) + return EINVAL; + + b = barrier->b; + + if ((rc = pthread_mutex_lock(&b->mutex)) != 0) + return rc; + + if (b->in > 0 || b->out > 0) + rc = EBUSY; + + pthread_mutex_unlock(&b->mutex); + + if (rc) + return rc; + + pthread_cond_destroy(&b->cond); + pthread_mutex_destroy(&b->mutex); + uv__free(barrier->b); + barrier->b = NULL; + return 0; +} diff --git a/deps/uv/src/unix/pthread-fixes.c b/deps/uv/src/unix/pthread-fixes.c index 3a71eb5aae..fb17995846 100644 --- a/deps/uv/src/unix/pthread-fixes.c +++ b/deps/uv/src/unix/pthread-fixes.c @@ -29,76 +29,28 @@ 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. - * */ +/* Android versions < 4.1 have a broken pthread_sigmask. */ #include <errno.h> #include <pthread.h> #include <signal.h> int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) { static int workaround; + int err; 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 - -#include "pthread-fixes.h" - -int pthread_barrier_init(pthread_barrier_t* barrier, - const void* barrier_attr, - unsigned count) { - barrier->count = count; - pthread_mutex_init(&barrier->mutex, NULL); - pthread_cond_init(&barrier->cond, NULL); - return 0; -} - -int pthread_barrier_wait(pthread_barrier_t* barrier) { - /* Lock the mutex*/ - pthread_mutex_lock(&barrier->mutex); - /* Decrement the count. If this is the first thread to reach 0, wake up - waiters, unlock the mutex, then return PTHREAD_BARRIER_SERIAL_THREAD.*/ - if (--barrier->count == 0) { - /* First thread to reach the barrier */ - pthread_cond_broadcast(&barrier->cond); - pthread_mutex_unlock(&barrier->mutex); - return PTHREAD_BARRIER_SERIAL_THREAD; + err = pthread_sigmask(how, set, oset); + if (err) { + if (err == EINVAL && sigprocmask(how, set, oset) == 0) { + workaround = 1; + return 0; + } else { + return -1; + } + } } - /* Otherwise, wait for other threads until the count reaches 0, then - return 0 to indicate this is not the first thread.*/ - do { - pthread_cond_wait(&barrier->cond, &barrier->mutex); - } while (barrier->count > 0); - - pthread_mutex_unlock(&barrier->mutex); - return 0; -} - -int pthread_barrier_destroy(pthread_barrier_t *barrier) { - barrier->count = 0; - pthread_cond_destroy(&barrier->cond); - pthread_mutex_destroy(&barrier->mutex); - return 0; -} - -#endif /* defined(PTHREAD_BARRIER_SERIAL_THREAD) */ -int pthread_yield(void) { - sched_yield(); return 0; } diff --git a/deps/uv/src/unix/signal.c b/deps/uv/src/unix/signal.c index edd9085d3f..d82b9b7cf8 100644 --- a/deps/uv/src/unix/signal.c +++ b/deps/uv/src/unix/signal.c @@ -222,7 +222,7 @@ static int uv__signal_loop_once_init(uv_loop_t* loop) { uv__io_init(&loop->signal_io_watcher, uv__signal_event, loop->signal_pipefd[0]); - uv__io_start(loop, &loop->signal_io_watcher, UV__POLLIN); + uv__io_start(loop, &loop->signal_io_watcher, POLLIN); return 0; } diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index 9043664dfc..7dbc556f74 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -159,9 +159,9 @@ static void uv__stream_osx_select(void* arg) { memset(s->sread, 0, s->sread_sz); memset(s->swrite, 0, s->swrite_sz); - if (uv__io_active(&stream->io_watcher, UV__POLLIN)) + if (uv__io_active(&stream->io_watcher, POLLIN)) FD_SET(fd, s->sread); - if (uv__io_active(&stream->io_watcher, UV__POLLOUT)) + if (uv__io_active(&stream->io_watcher, POLLOUT)) FD_SET(fd, s->swrite); FD_SET(s->int_fd, s->sread); @@ -202,9 +202,9 @@ static void uv__stream_osx_select(void* arg) { /* Handle events */ events = 0; if (FD_ISSET(fd, s->sread)) - events |= UV__POLLIN; + events |= POLLIN; if (FD_ISSET(fd, s->swrite)) - events |= UV__POLLOUT; + events |= POLLOUT; assert(events != 0 || FD_ISSET(s->int_fd, s->sread)); if (events != 0) { @@ -233,14 +233,14 @@ static void uv__stream_osx_select_cb(uv_async_t* handle) { ACCESS_ONCE(int, s->events) = 0; assert(events != 0); - assert(events == (events & (UV__POLLIN | UV__POLLOUT))); + assert(events == (events & (POLLIN | POLLOUT))); /* Invoke callback on event-loop */ - if ((events & UV__POLLIN) && uv__io_active(&stream->io_watcher, UV__POLLIN)) - uv__stream_io(stream->loop, &stream->io_watcher, UV__POLLIN); + if ((events & POLLIN) && uv__io_active(&stream->io_watcher, POLLIN)) + uv__stream_io(stream->loop, &stream->io_watcher, POLLIN); - if ((events & UV__POLLOUT) && uv__io_active(&stream->io_watcher, UV__POLLOUT)) - uv__stream_io(stream->loop, &stream->io_watcher, UV__POLLOUT); + if ((events & POLLOUT) && uv__io_active(&stream->io_watcher, POLLOUT)) + uv__stream_io(stream->loop, &stream->io_watcher, POLLOUT); if (stream->flags & UV_CLOSING) return; @@ -437,7 +437,7 @@ void uv__stream_flush_write_queue(uv_stream_t* stream, int error) { void uv__stream_destroy(uv_stream_t* stream) { - assert(!uv__io_active(&stream->io_watcher, UV__POLLIN | UV__POLLOUT)); + assert(!uv__io_active(&stream->io_watcher, POLLIN | POLLOUT)); assert(stream->flags & UV_CLOSED); if (stream->connect_req) { @@ -511,11 +511,11 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { int err; stream = container_of(w, uv_stream_t, io_watcher); - assert(events == UV__POLLIN); + assert(events == POLLIN); assert(stream->accepted_fd == -1); assert(!(stream->flags & UV_CLOSING)); - uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN); + uv__io_start(stream->loop, &stream->io_watcher, POLLIN); /* connection_cb can close the server socket while we're * in the loop so check it on each iteration. @@ -552,7 +552,7 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { if (stream->accepted_fd != -1) { /* The user hasn't yet accepted called uv_accept() */ - uv__io_stop(loop, &stream->io_watcher, UV__POLLIN); + uv__io_stop(loop, &stream->io_watcher, POLLIN); return; } @@ -626,7 +626,7 @@ done: } else { server->accepted_fd = -1; if (err == 0) - uv__io_start(server->loop, &server->io_watcher, UV__POLLIN); + uv__io_start(server->loop, &server->io_watcher, POLLIN); } return err; } @@ -660,7 +660,7 @@ static void uv__drain(uv_stream_t* stream) { int err; assert(QUEUE_EMPTY(&stream->write_queue)); - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); /* Shutdown? */ @@ -846,8 +846,8 @@ start: /* Error */ req->error = -errno; uv__write_req_finish(req); - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT); - if (!uv__io_active(&stream->io_watcher, UV__POLLIN)) + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); + if (!uv__io_active(&stream->io_watcher, POLLIN)) uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); return; @@ -910,7 +910,7 @@ start: assert(!(stream->flags & UV_STREAM_BLOCKING)); /* We're not done. */ - uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); /* Notify select() thread about state change */ uv__stream_osx_interrupt_select(stream); @@ -989,8 +989,8 @@ uv_handle_type uv__handle_type(int fd) { 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__io_stop(stream->loop, &stream->io_watcher, POLLIN); + if (!uv__io_active(&stream->io_watcher, POLLOUT)) uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); stream->read_cb(stream, UV_EOF, buf); @@ -1159,7 +1159,7 @@ static void uv__read(uv_stream_t* stream) { if (errno == EAGAIN || errno == EWOULDBLOCK) { /* Wait for the next one. */ if (stream->flags & UV_STREAM_READING) { - uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN); + uv__io_start(stream->loop, &stream->io_watcher, POLLIN); uv__stream_osx_interrupt_select(stream); } stream->read_cb(stream, 0, &buf); @@ -1168,8 +1168,8 @@ static void uv__read(uv_stream_t* stream) { stream->read_cb(stream, -errno, &buf); if (stream->flags & UV_STREAM_READING) { stream->flags &= ~UV_STREAM_READING; - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN); - if (!uv__io_active(&stream->io_watcher, UV__POLLOUT)) + uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); + if (!uv__io_active(&stream->io_watcher, POLLOUT)) uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); } @@ -1230,7 +1230,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { stream->shutdown_req = req; stream->flags |= UV_STREAM_SHUTTING; - uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); return 0; @@ -1255,7 +1255,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { assert(uv__stream_fd(stream) >= 0); /* Ignore POLLHUP here. Even it it's set, there may still be data to read. */ - if (events & (UV__POLLIN | UV__POLLERR | UV__POLLHUP)) + if (events & (POLLIN | POLLERR | POLLHUP)) uv__read(stream); if (uv__stream_fd(stream) == -1) @@ -1267,7 +1267,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { * have to do anything. If the partial read flag is not set, we can't * report the EOF yet because there is still data to read. */ - if ((events & UV__POLLHUP) && + if ((events & POLLHUP) && (stream->flags & UV_STREAM_READING) && (stream->flags & UV_STREAM_READ_PARTIAL) && !(stream->flags & UV_STREAM_READ_EOF)) { @@ -1278,7 +1278,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { if (uv__stream_fd(stream) == -1) return; /* read_cb closed stream. */ - if (events & (UV__POLLOUT | UV__POLLERR | UV__POLLHUP)) { + if (events & (POLLOUT | POLLERR | POLLHUP)) { uv__write(stream); uv__write_callbacks(stream); @@ -1327,7 +1327,7 @@ static void uv__stream_connect(uv_stream_t* stream) { uv__req_unregister(stream->loop, req); if (error < 0 || QUEUE_EMPTY(&stream->write_queue)) { - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); } if (req->cb) @@ -1422,7 +1422,7 @@ int uv_write2(uv_write_t* req, * sufficiently flushed in uv__write. */ assert(!(stream->flags & UV_STREAM_BLOCKING)); - uv__io_start(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); } @@ -1461,7 +1461,7 @@ int uv_try_write(uv_stream_t* stream, if (stream->connect_req != NULL || stream->write_queue_size != 0) return -EAGAIN; - has_pollout = uv__io_active(&stream->io_watcher, UV__POLLOUT); + has_pollout = uv__io_active(&stream->io_watcher, POLLOUT); r = uv_write(&req, stream, bufs, nbufs, uv_try_write_cb); if (r != 0) @@ -1485,7 +1485,7 @@ int uv_try_write(uv_stream_t* stream, /* Do not poll for writable, if we wasn't before calling this */ if (!has_pollout) { - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT); + uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT); uv__stream_osx_interrupt_select(stream); } @@ -1520,7 +1520,7 @@ int uv_read_start(uv_stream_t* stream, stream->read_cb = read_cb; stream->alloc_cb = alloc_cb; - uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN); + uv__io_start(stream->loop, &stream->io_watcher, POLLIN); uv__handle_start(stream); uv__stream_osx_interrupt_select(stream); @@ -1533,8 +1533,8 @@ int uv_read_stop(uv_stream_t* stream) { return 0; stream->flags &= ~UV_STREAM_READING; - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN); - if (!uv__io_active(&stream->io_watcher, UV__POLLOUT)) + uv__io_stop(stream->loop, &stream->io_watcher, POLLIN); + if (!uv__io_active(&stream->io_watcher, POLLOUT)) uv__handle_stop(stream); uv__stream_osx_interrupt_select(stream); @@ -1621,7 +1621,7 @@ void uv__stream_close(uv_stream_t* handle) { handle->queued_fds = NULL; } - assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT)); + assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT)); } diff --git a/deps/uv/src/unix/sunos.c b/deps/uv/src/unix/sunos.c index 9a6cc42b5b..e67be8fcf8 100644 --- a/deps/uv/src/unix/sunos.c +++ b/deps/uv/src/unix/sunos.c @@ -140,6 +140,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { unsigned int nfds; unsigned int i; int saved_errno; + int have_signals; int nevents; int count; int err; @@ -230,6 +231,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { return; } + have_signals = 0; nevents = 0; assert(loop->watchers != NULL); @@ -252,7 +254,14 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (w == NULL) continue; - w->cb(loop, w, pe->portev_events); + /* Run signal watchers last. This also affects child process watchers + * because those are implemented in terms of signal watchers. + */ + if (w == &loop->signal_io_watcher) + have_signals = 1; + else + w->cb(loop, w, pe->portev_events); + nevents++; if (w != loop->watchers[fd]) @@ -262,9 +271,16 @@ void uv__io_poll(uv_loop_t* loop, int timeout) { if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue); } + + if (have_signals != 0) + loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN); + loop->watchers[loop->nwatchers] = NULL; loop->watchers[loop->nwatchers + 1] = NULL; + if (have_signals != 0) + return; /* Event loop should cycle now so don't poll again. */ + if (nevents != 0) { if (nfds == ARRAY_SIZE(events) && --count != 0) { /* Poll for more events but don't block this time. */ @@ -456,7 +472,7 @@ int uv_fs_event_start(uv_fs_event_t* handle, if (first_run) { uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd); - uv__io_start(handle->loop, &handle->loop->fs_event_watcher, UV__POLLIN); + uv__io_start(handle->loop, &handle->loop->fs_event_watcher, POLLIN); } return 0; diff --git a/deps/uv/src/unix/tcp.c b/deps/uv/src/unix/tcp.c index 6d213a4977..793e4c7d60 100644 --- a/deps/uv/src/unix/tcp.c +++ b/deps/uv/src/unix/tcp.c @@ -181,7 +181,7 @@ int uv__tcp_connect(uv_connect_t* req, QUEUE_INIT(&req->queue); handle->connect_req = req; - uv__io_start(handle->loop, &handle->io_watcher, UV__POLLOUT); + uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); if (handle->delayed_error) uv__io_feed(handle->loop, &handle->io_watcher); @@ -273,7 +273,7 @@ int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) { /* Start listening for connections. */ tcp->io_watcher.cb = uv__server_io; - uv__io_start(tcp->loop, &tcp->io_watcher, UV__POLLIN); + uv__io_start(tcp->loop, &tcp->io_watcher, POLLIN); return 0; } diff --git a/deps/uv/src/unix/thread.c b/deps/uv/src/unix/thread.c index c35bc926bf..236f591393 100644 --- a/deps/uv/src/unix/thread.c +++ b/deps/uv/src/unix/thread.c @@ -28,13 +28,13 @@ #include <sys/time.h> #include <sys/resource.h> /* getrlimit() */ +#include <unistd.h> /* getpagesize() */ #include <limits.h> #undef NANOSEC #define NANOSEC ((uint64_t) 1e9) - struct thread_ctx { void (*entry)(void* arg); void* arg; @@ -82,10 +82,13 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { if (pthread_attr_init(attr)) abort(); - if (lim.rlim_cur != RLIM_INFINITY && - lim.rlim_cur >= PTHREAD_STACK_MIN) { - if (pthread_attr_setstacksize(attr, lim.rlim_cur)) - abort(); + if (lim.rlim_cur != RLIM_INFINITY) { + /* pthread_attr_setstacksize() expects page-aligned values. */ + lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize(); + + if (lim.rlim_cur >= PTHREAD_STACK_MIN) + if (pthread_attr_setstacksize(attr, lim.rlim_cur)) + abort(); } #else attr = NULL; @@ -393,6 +396,35 @@ error2: #endif /* defined(__APPLE__) && defined(__MACH__) */ void uv_cond_destroy(uv_cond_t* cond) { +#if defined(__APPLE__) && defined(__MACH__) + /* It has been reported that destroying condition variables that have been + * signalled but not waited on can sometimes result in application crashes. + * See https://codereview.chromium.org/1323293005. + */ + pthread_mutex_t mutex; + struct timespec ts; + int err; + + if (pthread_mutex_init(&mutex, NULL)) + abort(); + + if (pthread_mutex_lock(&mutex)) + abort(); + + ts.tv_sec = 0; + ts.tv_nsec = 1; + + err = pthread_cond_timedwait_relative_np(cond, &mutex, &ts); + if (err != 0 && err != ETIMEDOUT) + abort(); + + if (pthread_mutex_unlock(&mutex)) + abort(); + + if (pthread_mutex_destroy(&mutex)) + abort(); +#endif /* defined(__APPLE__) && defined(__MACH__) */ + if (pthread_cond_destroy(cond)) abort(); } @@ -448,72 +480,6 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { } -#if defined(__APPLE__) && defined(__MACH__) - -int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { - int err; - - barrier->n = count; - barrier->count = 0; - - err = uv_mutex_init(&barrier->mutex); - if (err) - return -err; - - err = uv_sem_init(&barrier->turnstile1, 0); - if (err) - goto error2; - - err = uv_sem_init(&barrier->turnstile2, 1); - if (err) - goto error; - - return 0; - -error: - uv_sem_destroy(&barrier->turnstile1); -error2: - uv_mutex_destroy(&barrier->mutex); - return -err; - -} - - -void uv_barrier_destroy(uv_barrier_t* barrier) { - uv_sem_destroy(&barrier->turnstile2); - uv_sem_destroy(&barrier->turnstile1); - uv_mutex_destroy(&barrier->mutex); -} - - -int uv_barrier_wait(uv_barrier_t* barrier) { - int serial_thread; - - uv_mutex_lock(&barrier->mutex); - if (++barrier->count == barrier->n) { - uv_sem_wait(&barrier->turnstile2); - uv_sem_post(&barrier->turnstile1); - } - uv_mutex_unlock(&barrier->mutex); - - uv_sem_wait(&barrier->turnstile1); - uv_sem_post(&barrier->turnstile1); - - uv_mutex_lock(&barrier->mutex); - serial_thread = (--barrier->count == 0); - if (serial_thread) { - uv_sem_wait(&barrier->turnstile1); - uv_sem_post(&barrier->turnstile2); - } - uv_mutex_unlock(&barrier->mutex); - - uv_sem_wait(&barrier->turnstile2); - uv_sem_post(&barrier->turnstile2); - return serial_thread; -} - -#else /* !(defined(__APPLE__) && defined(__MACH__)) */ - int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { return -pthread_barrier_init(barrier, NULL, count); } @@ -532,7 +498,6 @@ int uv_barrier_wait(uv_barrier_t* barrier) { return r == PTHREAD_BARRIER_SERIAL_THREAD; } -#endif /* defined(__APPLE__) && defined(__MACH__) */ int uv_key_create(uv_key_t* key) { return -pthread_key_create(key, NULL); diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index 39ade8de33..4527bba1f1 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -61,7 +61,7 @@ void uv__udp_finish_close(uv_udp_t* handle) { uv_udp_send_t* req; QUEUE* q; - assert(!uv__io_active(&handle->io_watcher, UV__POLLIN | UV__POLLOUT)); + assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT)); assert(handle->io_watcher.fd == -1); while (!QUEUE_EMPTY(&handle->write_queue)) { @@ -120,8 +120,8 @@ static void uv__udp_run_completed(uv_udp_t* handle) { if (QUEUE_EMPTY(&handle->write_queue)) { /* Pending queue and completion queue empty, stop watcher. */ - uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLOUT); - if (!uv__io_active(&handle->io_watcher, UV__POLLIN)) + uv__io_stop(handle->loop, &handle->io_watcher, POLLOUT); + if (!uv__io_active(&handle->io_watcher, POLLIN)) uv__handle_stop(handle); } @@ -135,10 +135,10 @@ static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) { handle = container_of(w, uv_udp_t, io_watcher); assert(handle->type == UV_UDP); - if (revents & UV__POLLIN) + if (revents & POLLIN) uv__udp_recvmsg(handle); - if (revents & UV__POLLOUT) { + if (revents & POLLOUT) { uv__udp_sendmsg(handle); uv__udp_run_completed(handle); } @@ -424,7 +424,7 @@ int uv__udp_send(uv_udp_send_t* req, if (empty_queue && !(handle->flags & UV_UDP_PROCESSING)) { uv__udp_sendmsg(handle); } else { - uv__io_start(handle->loop, &handle->io_watcher, UV__POLLOUT); + uv__io_start(handle->loop, &handle->io_watcher, POLLOUT); } return 0; @@ -843,7 +843,7 @@ int uv__udp_recv_start(uv_udp_t* handle, if (alloc_cb == NULL || recv_cb == NULL) return -EINVAL; - if (uv__io_active(&handle->io_watcher, UV__POLLIN)) + if (uv__io_active(&handle->io_watcher, POLLIN)) return -EALREADY; /* FIXME(bnoordhuis) Should be -EBUSY. */ err = uv__udp_maybe_deferred_bind(handle, AF_INET, 0); @@ -853,7 +853,7 @@ int uv__udp_recv_start(uv_udp_t* handle, handle->alloc_cb = alloc_cb; handle->recv_cb = recv_cb; - uv__io_start(handle->loop, &handle->io_watcher, UV__POLLIN); + uv__io_start(handle->loop, &handle->io_watcher, POLLIN); uv__handle_start(handle); return 0; @@ -861,9 +861,9 @@ int uv__udp_recv_start(uv_udp_t* handle, int uv__udp_recv_stop(uv_udp_t* handle) { - uv__io_stop(handle->loop, &handle->io_watcher, UV__POLLIN); + uv__io_stop(handle->loop, &handle->io_watcher, POLLIN); - if (!uv__io_active(&handle->io_watcher, UV__POLLOUT)) + if (!uv__io_active(&handle->io_watcher, POLLOUT)) uv__handle_stop(handle); handle->alloc_cb = NULL; diff --git a/deps/uv/src/uv-common.c b/deps/uv/src/uv-common.c index 6b8c584fbe..ba26446915 100644 --- a/deps/uv/src/uv-common.c +++ b/deps/uv/src/uv-common.c @@ -22,10 +22,11 @@ #include "uv.h" #include "uv-common.h" -#include <stdio.h> #include <assert.h> +#include <errno.h> #include <stdarg.h> #include <stddef.h> /* NULL */ +#include <stdio.h> #include <stdlib.h> /* malloc */ #include <string.h> /* memset */ @@ -75,7 +76,14 @@ void* uv__malloc(size_t size) { } void uv__free(void* ptr) { + int saved_errno; + + /* Libuv expects that free() does not clobber errno. The system allocator + * honors that assumption but custom allocators may not be so careful. + */ + saved_errno = errno; uv__allocator.local_free(ptr); + errno = saved_errno; } void* uv__calloc(size_t count, size_t size) { @@ -475,6 +483,16 @@ static unsigned int* uv__get_nbufs(uv_fs_t* req) { #endif } +/* uv_fs_scandir() uses the system allocator to allocate memory on non-Windows + * systems. So, the memory should be released using free(). On Windows, + * uv__malloc() is used, so use uv__free() to free memory. +*/ +#ifdef _WIN32 +# define uv__fs_scandir_free uv__free +#else +# define uv__fs_scandir_free free +#endif + void uv__fs_scandir_cleanup(uv_fs_t* req) { uv__dirent_t** dents; @@ -484,7 +502,10 @@ void uv__fs_scandir_cleanup(uv_fs_t* req) { if (*nbufs > 0 && *nbufs != (unsigned int) req->result) (*nbufs)--; for (; *nbufs < (unsigned int) req->result; (*nbufs)++) - uv__free(dents[*nbufs]); + uv__fs_scandir_free(dents[*nbufs]); + + uv__fs_scandir_free(req->ptr); + req->ptr = NULL; } @@ -498,11 +519,11 @@ int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) { /* Free previous entity */ if (*nbufs > 0) - uv__free(dents[*nbufs - 1]); + uv__fs_scandir_free(dents[*nbufs - 1]); /* End was already reached */ if (*nbufs == (unsigned int) req->result) { - uv__free(dents); + uv__fs_scandir_free(dents); req->ptr = NULL; return UV_EOF; } diff --git a/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c index 77c935a2d8..e79a48d0e9 100644 --- a/deps/uv/src/win/fs-event.c +++ b/deps/uv/src/win/fs-event.c @@ -66,11 +66,12 @@ static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop, static void uv_relative_path(const WCHAR* filename, const WCHAR* dir, WCHAR** relpath) { + size_t relpathlen; + size_t filenamelen = wcslen(filename); size_t dirlen = wcslen(dir); if (dirlen > 0 && dir[dirlen - 1] == '\\') dirlen--; - size_t filenamelen = wcslen(filename); - size_t relpathlen = filenamelen - dirlen - 1; + relpathlen = filenamelen - dirlen - 1; *relpath = uv__malloc((relpathlen + 1) * sizeof(WCHAR)); if (!*relpath) uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); @@ -348,7 +349,8 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, FILE_NOTIFY_INFORMATION* file_info; int err, sizew, size; char* filename = NULL; - WCHAR* filenamew, *long_filenamew = NULL; + WCHAR* filenamew = NULL; + WCHAR* long_filenamew = NULL; DWORD offset = 0; assert(req->type == UV_FS_EVENT_REQ); @@ -373,6 +375,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, do { file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset); assert(!filename); + assert(!filenamew); assert(!long_filenamew); /* @@ -437,14 +440,17 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, uv__free(long_filenamew); long_filenamew = filenamew; sizew = -1; + } else { + /* We couldn't get the long filename, use the one reported. */ + filenamew = file_info->FileName; + sizew = file_info->FileNameLength / sizeof(WCHAR); } - } - /* - * Removed or renamed events cannot be resolved to the long form. - * We therefore use the name given by ReadDirectoryChangesW. - * This may be the long form or the 8.3 short name in some cases. - */ - if (!long_filenamew) { + } else { + /* + * Removed or renamed events cannot be resolved to the long form. + * We therefore use the name given by ReadDirectoryChangesW. + * This may be the long form or the 8.3 short name in some cases. + */ filenamew = file_info->FileName; sizew = file_info->FileNameLength / sizeof(WCHAR); } @@ -454,38 +460,8 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, sizew = -1; } - if (filenamew) { - /* Convert the filename to utf8. */ - size = WideCharToMultiByte(CP_UTF8, - 0, - filenamew, - sizew, - NULL, - 0, - NULL, - NULL); - if (size) { - filename = (char*)uv__malloc(size + 1); - if (!filename) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - - size = WideCharToMultiByte(CP_UTF8, - 0, - filenamew, - sizew, - filename, - size, - NULL, - NULL); - if (size) { - filename[size] = '\0'; - } else { - uv__free(filename); - filename = NULL; - } - } - } + /* Convert the filename to utf8. */ + uv__convert_utf16_to_utf8(filenamew, sizew, &filename); switch (file_info->Action) { case FILE_ACTION_ADDED: @@ -504,6 +480,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, filename = NULL; uv__free(long_filenamew); long_filenamew = NULL; + filenamew = NULL; } offset = file_info->NextEntryOffset; diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 16e3ae7cf1..54dfea7240 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -901,7 +901,15 @@ void fs__scandir(uv_fs_t* req) { /* Compute the length of the filename in WCHARs. */ wchar_len = info->FileNameLength / sizeof info->FileName[0]; - /* Skip over '.' and '..' entries. */ + /* Skip over '.' and '..' entries. It has been reported that + * the SharePoint driver includes the terminating zero byte in + * the filename length. Strip those first. + */ + while (wchar_len > 0 && info->FileName[wchar_len - 1] == L'\0') + wchar_len -= 1; + + if (wchar_len == 0) + continue; if (wchar_len == 1 && info->FileName[0] == L'.') continue; if (wchar_len == 2 && info->FileName[0] == L'.' && @@ -1870,8 +1878,12 @@ void uv_fs_req_cleanup(uv_fs_t* req) { if (req->flags & UV_FS_FREE_PATHS) uv__free(req->file.pathw); - if (req->flags & UV_FS_FREE_PTR) - uv__free(req->ptr); + if (req->flags & UV_FS_FREE_PTR) { + if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL) + uv__fs_scandir_cleanup(req); + else + uv__free(req->ptr); + } req->path = NULL; req->file.pathw = NULL; diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index c724793bf0..0a7c9404fa 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -83,6 +83,7 @@ extern UV_THREAD_LOCAL int uv__crt_assert_enabled; #define UV_HANDLE_ZERO_READ 0x00080000 #define UV_HANDLE_EMULATE_IOCP 0x00100000 #define UV_HANDLE_BLOCKING_WRITES 0x00200000 +#define UV_HANDLE_CANCELLATION_PENDING 0x00400000 /* Used by uv_tcp_t and uv_udp_t handles */ #define UV_HANDLE_IPV6 0x01000000 @@ -329,7 +330,7 @@ int uv_parent_pid(); int uv_current_pid(); __declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall); int uv__getpwuid_r(uv_passwd_t* pwd); -int uv__convert_utf16_to_utf8(const WCHAR* utf16, char** utf8); +int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8); /* diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index 1b27f60a6f..9b96377844 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -57,11 +57,23 @@ static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info); static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info); +static int uv__cancel_read_console(uv_tty_t* handle); /* Null uv_buf_t */ static const uv_buf_t uv_null_buf_ = { 0, NULL }; +enum uv__read_console_status_e { + NOT_STARTED, + IN_PROGRESS, + TRAP_REQUESTED, + COMPLETED +}; + +static volatile LONG uv__read_console_status = NOT_STARTED; +static volatile LONG uv__restore_screen_state; +static CONSOLE_SCREEN_BUFFER_INFO uv__saved_screen_state; + /* * The console virtual window. @@ -173,7 +185,8 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { if (readable) { /* Initialize TTY input specific fields. */ tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE; - tty->tty.rd.read_line_handle = NULL; + /* TODO: remove me in v2.x. */ + tty->tty.rd.unused_ = NULL; tty->tty.rd.read_line_buffer = uv_null_buf_; tty->tty.rd.read_raw_wait = NULL; @@ -398,6 +411,8 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { DWORD bytes, read_bytes; WCHAR utf16[MAX_INPUT_BUFFER_LENGTH / 3]; DWORD chars, read_chars; + LONG status; + COORD pos; assert(data); @@ -419,7 +434,15 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { /* One utf-16 codeunit never takes more than 3 utf-8 codeunits to encode */ chars = bytes / 3; - if (ReadConsoleW(handle->tty.rd.read_line_handle, + status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS); + if (status == TRAP_REQUESTED) { + SET_REQ_SUCCESS(req); + req->u.io.overlapped.InternalHigh = 0; + POST_COMPLETION_FOR_REQ(loop, req); + return 0; + } + + if (ReadConsoleW(handle->handle, (void*) utf16, chars, &read_chars, @@ -438,6 +461,33 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) { SET_REQ_ERROR(req, GetLastError()); } + InterlockedExchange(&uv__read_console_status, COMPLETED); + + /* If we canceled the read by sending a VK_RETURN event, restore the screen + state to undo the visual effect of the VK_RETURN*/ + if (InterlockedOr(&uv__restore_screen_state, 0)) { + HANDLE active_screen_buffer = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (active_screen_buffer != INVALID_HANDLE_VALUE) { + pos = uv__saved_screen_state.dwCursorPosition; + + /* If the cursor was at the bottom line of the screen buffer, the + VK_RETURN would have caused the buffer contents to scroll up by + one line. The right position to reset the cursor to is therefore one + line higher */ + if (pos.Y == uv__saved_screen_state.dwSize.Y - 1) + pos.Y--; + + SetConsoleCursorPosition(active_screen_buffer, pos); + CloseHandle(active_screen_buffer); + } + } + POST_COMPLETION_FOR_REQ(loop, req); return 0; } @@ -463,25 +513,11 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { } assert(handle->tty.rd.read_line_buffer.base != NULL); - /* Duplicate the console handle, so if we want to cancel the read, we can */ - /* just close this handle duplicate. */ - if (handle->tty.rd.read_line_handle == NULL) { - HANDLE this_process = GetCurrentProcess(); - r = DuplicateHandle(this_process, - handle->handle, - this_process, - &handle->tty.rd.read_line_handle, - 0, - 0, - DUPLICATE_SAME_ACCESS); - if (!r) { - handle->tty.rd.read_line_handle = NULL; - SET_REQ_ERROR(req, GetLastError()); - uv_insert_pending_req(loop, (uv_req_t*)req); - goto out; - } - } - + /* Reset flags No locking is required since there cannot be a line read + in progress. We are also relying on the memory barrier provided by + QueueUserWorkItem*/ + uv__restore_screen_state = FALSE; + uv__read_console_status = NOT_STARTED; r = QueueUserWorkItem(uv_tty_line_read_thread, (void*) req, WT_EXECUTELONGFUNCTION); @@ -490,7 +526,6 @@ static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { uv_insert_pending_req(loop, (uv_req_t*)req); } - out: handle->flags |= UV_HANDLE_READ_PENDING; handle->reqs_pending++; } @@ -857,8 +892,7 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle, if (!REQ_SUCCESS(req)) { /* Read was not successful */ - if ((handle->flags & UV_HANDLE_READING) && - handle->tty.rd.read_line_handle != NULL) { + if (handle->flags & UV_HANDLE_READING) { /* Real error */ handle->flags &= ~UV_HANDLE_READING; DECREASE_ACTIVE_COUNT(loop, handle); @@ -871,10 +905,15 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle, } } else { - /* Read successful */ - /* TODO: read unicode, convert to utf-8 */ - DWORD bytes = req->u.io.overlapped.InternalHigh; - handle->read_cb((uv_stream_t*) handle, bytes, &buf); + if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { + /* Read successful */ + /* TODO: read unicode, convert to utf-8 */ + DWORD bytes = req->u.io.overlapped.InternalHigh; + handle->read_cb((uv_stream_t*) handle, bytes, &buf); + } else { + handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING; + handle->read_cb((uv_stream_t*) handle, 0, &buf); + } } /* Wait for more input events. */ @@ -937,30 +976,82 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, int uv_tty_read_stop(uv_tty_t* handle) { + INPUT_RECORD record; + DWORD written, err; + handle->flags &= ~UV_HANDLE_READING; DECREASE_ACTIVE_COUNT(handle->loop, handle); - /* Cancel raw read */ - if ((handle->flags & UV_HANDLE_READ_PENDING) && - (handle->flags & UV_HANDLE_TTY_RAW)) { + if (!(handle->flags & UV_HANDLE_READ_PENDING)) + return 0; + + if (handle->flags & UV_HANDLE_TTY_RAW) { + /* Cancel raw read */ /* Write some bullshit event to force the console wait to return. */ - INPUT_RECORD record; - DWORD written; memset(&record, 0, sizeof record); if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) { return GetLastError(); } + } else if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) { + /* Cancel line-buffered read if not already pending */ + err = uv__cancel_read_console(handle); + if (err) + return err; + + handle->flags |= UV_HANDLE_CANCELLATION_PENDING; + } + + return 0; +} + +static int uv__cancel_read_console(uv_tty_t* handle) { + HANDLE active_screen_buffer = INVALID_HANDLE_VALUE; + INPUT_RECORD record; + DWORD written; + DWORD err = 0; + LONG status; + + assert(!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)); + + status = InterlockedExchange(&uv__read_console_status, TRAP_REQUESTED); + if (status != IN_PROGRESS) { + /* Either we have managed to set a trap for the other thread before + ReadConsole is called, or ReadConsole has returned because the user + has pressed ENTER. In either case, there is nothing else to do. */ + return 0; } - /* Cancel line-buffered read */ - if (handle->tty.rd.read_line_handle != NULL) { - /* Closing this handle will cancel the ReadConsole operation */ - CloseHandle(handle->tty.rd.read_line_handle); - handle->tty.rd.read_line_handle = NULL; + /* Save screen state before sending the VK_RETURN event */ + active_screen_buffer = CreateFileA("conout$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + if (active_screen_buffer != INVALID_HANDLE_VALUE && + GetConsoleScreenBufferInfo(active_screen_buffer, + &uv__saved_screen_state)) { + InterlockedOr(&uv__restore_screen_state, 1); } + /* Write enter key event to force the console wait to return. */ + record.EventType = KEY_EVENT; + record.Event.KeyEvent.bKeyDown = TRUE; + record.Event.KeyEvent.wRepeatCount = 1; + record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN; + record.Event.KeyEvent.wVirtualScanCode = + MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC); + record.Event.KeyEvent.uChar.UnicodeChar = L'\r'; + record.Event.KeyEvent.dwControlKeyState = 0; + if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) + err = GetLastError(); - return 0; + if (active_screen_buffer != INVALID_HANDLE_VALUE) + CloseHandle(active_screen_buffer); + + return err; } @@ -2045,11 +2136,6 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { if (handle->flags & UV__HANDLE_CLOSING && handle->reqs_pending == 0) { - /* The console handle duplicate used for line reading should be destroyed */ - /* by uv_tty_read_stop. */ - assert(!(handle->flags & UV_HANDLE_TTY_READABLE) || - handle->tty.rd.read_line_handle == NULL); - /* The wait handle used for raw reading should be unregistered when the */ /* wait callback runs. */ assert(!(handle->flags & UV_HANDLE_TTY_READABLE) || diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index 1788b1780e..4cebad3908 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -124,7 +124,7 @@ int uv_exepath(char* buffer, size_t* size_ptr) { utf16_buffer, -1, buffer, - *size_ptr > INT_MAX ? INT_MAX : (int) *size_ptr, + (int) *size_ptr, NULL, NULL); if (utf8_len == 0) { @@ -403,36 +403,13 @@ done: static int uv__get_process_title() { WCHAR title_w[MAX_TITLE_LENGTH]; - int length; if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) { return -1; } - /* Find out what the size of the buffer is that we need */ - length = WideCharToMultiByte(CP_UTF8, 0, title_w, -1, NULL, 0, NULL, NULL); - if (!length) { - return -1; - } - - assert(!process_title); - process_title = (char*)uv__malloc(length); - if (!process_title) { - uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc"); - } - - /* Do utf16 -> utf8 conversion here */ - if (!WideCharToMultiByte(CP_UTF8, - 0, - title_w, - -1, - process_title, - length, - NULL, - NULL)) { - uv__free(process_title); + if (uv__convert_utf16_to_utf8(title_w, -1, &process_title) != 0) return -1; - } return 0; } @@ -704,43 +681,9 @@ int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) { cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000; cpu_info->cpu_times.nice = 0; - - len = WideCharToMultiByte(CP_UTF8, - 0, - cpu_brand, + uv__convert_utf16_to_utf8(cpu_brand, cpu_brand_size / sizeof(WCHAR), - NULL, - 0, - NULL, - NULL); - if (len == 0) { - err = GetLastError(); - goto error; - } - - assert(len > 0); - - /* Allocate 1 extra byte for the null terminator. */ - cpu_info->model = uv__malloc(len + 1); - if (cpu_info->model == NULL) { - err = ERROR_OUTOFMEMORY; - goto error; - } - - if (WideCharToMultiByte(CP_UTF8, - 0, - cpu_brand, - cpu_brand_size / sizeof(WCHAR), - cpu_info->model, - len, - NULL, - NULL) == 0) { - err = GetLastError(); - goto error; - } - - /* Ensure that cpu_info->model is null terminated. */ - cpu_info->model[len] = '\0'; + &(cpu_info->model)); } uv__free(sppi); @@ -1118,6 +1061,7 @@ void uv_free_interface_addresses(uv_interface_address_t* addresses, int uv_getrusage(uv_rusage_t *uv_rusage) { FILETIME createTime, exitTime, kernelTime, userTime; SYSTEMTIME kernelSystemTime, userSystemTime; + PROCESS_MEMORY_COUNTERS memCounters; int ret; ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime); @@ -1135,6 +1079,13 @@ int uv_getrusage(uv_rusage_t *uv_rusage) { return uv_translate_sys_error(GetLastError()); } + ret = GetProcessMemoryInfo(GetCurrentProcess(), + &memCounters, + sizeof(memCounters)); + if (ret == 0) { + return uv_translate_sys_error(GetLastError()); + } + memset(uv_rusage, 0, sizeof(*uv_rusage)); uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 + @@ -1147,6 +1098,9 @@ int uv_getrusage(uv_rusage_t *uv_rusage) { kernelSystemTime.wSecond; uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000; + uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount; + uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024; + return 0; } @@ -1288,20 +1242,36 @@ void uv_os_free_passwd(uv_passwd_t* pwd) { } -int uv__convert_utf16_to_utf8(const WCHAR* utf16, char** utf8) { +/* + * Converts a UTF-16 string into a UTF-8 one. The resulting string is + * null-terminated. + * + * If utf16 is null terminated, utf16len can be set to -1, otherwise it must + * be specified. + */ +int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8) { DWORD bufsize; if (utf16 == NULL) return UV_EINVAL; /* Check how much space we need */ - bufsize = WideCharToMultiByte(CP_UTF8, 0, utf16, -1, NULL, 0, NULL, NULL); + bufsize = WideCharToMultiByte(CP_UTF8, + 0, + utf16, + utf16len, + NULL, + 0, + NULL, + NULL); if (bufsize == 0) return uv_translate_sys_error(GetLastError()); - /* Allocate the destination buffer */ - *utf8 = uv__malloc(bufsize); + /* Allocate the destination buffer adding an extra byte for the terminating + * NULL. If utf16len is not -1 WideCharToMultiByte will not add it, so + * we do it ourselves always, just in case. */ + *utf8 = uv__malloc(bufsize + 1); if (*utf8 == NULL) return UV_ENOMEM; @@ -1310,7 +1280,7 @@ int uv__convert_utf16_to_utf8(const WCHAR* utf16, char** utf8) { bufsize = WideCharToMultiByte(CP_UTF8, 0, utf16, - -1, + utf16len, *utf8, bufsize, NULL, @@ -1318,9 +1288,11 @@ int uv__convert_utf16_to_utf8(const WCHAR* utf16, char** utf8) { if (bufsize == 0) { uv__free(*utf8); + *utf8 = NULL; return uv_translate_sys_error(GetLastError()); } + (*utf8)[bufsize] = '\0'; return 0; } @@ -1366,13 +1338,13 @@ int uv__getpwuid_r(uv_passwd_t* pwd) { } pwd->homedir = NULL; - r = uv__convert_utf16_to_utf8(path, &pwd->homedir); + r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir); if (r != 0) return r; pwd->username = NULL; - r = uv__convert_utf16_to_utf8(username, &pwd->username); + r = uv__convert_utf16_to_utf8(username, -1, &pwd->username); if (r != 0) { uv__free(pwd->homedir); |