diff --git a/deps/uv/.mailmap b/deps/uv/.mailmap index 5bbe5b26bb5c5e..8a559787b49a75 100644 --- a/deps/uv/.mailmap +++ b/deps/uv/.mailmap @@ -45,3 +45,4 @@ Yazhong Liu Yuki Okumura jBarz jBarz +ptlomholt diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index a8b50f6209d7a0..3317efeb1ac8af 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -362,3 +362,7 @@ Ashe Connor Rick Ivan Krylov Michael Meier +ptlomholt +Victor Costan +sid +Kevin Adler diff --git a/deps/uv/CMakeLists.txt b/deps/uv/CMakeLists.txt index 9f1c0587a98060..fa268a13ed6661 100644 --- a/deps/uv/CMakeLists.txt +++ b/deps/uv/CMakeLists.txt @@ -167,6 +167,7 @@ set(uv_test_sources test/test-udp-send-immediate.c test/test-udp-send-unreachable.c test/test-udp-try-send.c + test/test-uname.c test/test-walk-handles.c test/test-watcher-cross-stop.c) @@ -211,7 +212,7 @@ if(WIN32) else() list(APPEND uv_defines _FILE_OFFSET_BITS=64 _LARGEFILE_SOURCE) if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android") - # Android has pthread as part of its c library, not as a separate + # Android has pthread as part of its c library, not as a separate # libpthread.so. list(APPEND uv_libraries pthread) endif() diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index f7881e6bbc4f92..3652829ce7790b 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,3 +1,54 @@ +2019.01.19, Version 1.25.0 (Stable), 4a10a9d425863330af199e4b74bd688e62d945f1 + +Changes since version 1.24.1: + +* Revert "win,fs: retry if uv_fs_rename fails" (Ben Noordhuis) + +* aix: manually trigger fs event monitoring (Gireesh Punathil) + +* unix: rename WRITE_RETRY_ON_ERROR macro (Ben Noordhuis) + +* darwin: DRY platform-specific error check (Ben Noordhuis) + +* unix: refactor uv__write() (Ben Noordhuis) + +* unix: don't send handle twice on partial write (Ben Noordhuis) + +* tty,win: fix Alt+key under WSL (Bartosz Sosnowski) + +* build: support running tests in out-of-tree builds (Jameson Nash) + +* fsevents: really watch files with fsevents on macos 10.7+ (Jameson Nash) + +* thread,mingw64: need intrin.h header for SSE2 MemoryBarrier (Jameson Nash) + +* win: fix sizeof-pointer-div warning (cjihrig) + +* unix,win: add uv_os_uname() (cjihrig) + +* win, tty: fix CreateFileW() return value check (Bartosz Sosnowski) + +* unix: enable IPv6 tests on OpenBSD (ptlomholt) + +* test: fix test-ipc spawn_helper exit_cb (Santiago Gimeno) + +* test: fix test-ipc tests (Santiago Gimeno) + +* unix: better handling of unsupported F_FULLFSYNC (Victor Costan) + +* win,test: de-flake fs_event_watch_dir_short_path (Refael Ackermann) + +* win: fix msvc warning (sid) + +* openbsd: switch to libuv's barrier implementation (ptlomholt) + +* unix,stream: fix zero byte writes (Santiago Gimeno) + +* ibmi: return EISDIR on read from directory fd (Kevin Adler) + +* build: wrap long lines in Makefile.am (cjihrig) + + 2018.12.17, Version 1.24.1 (Stable), 274f2bd3b70847cadd9a3965577a87e666ab9ac3 Changes since version 1.24.0: diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index f9c9c9a05d14f3..d8a01574f3cf2c 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -20,7 +20,9 @@ AM_CPPFLAGS = -I$(top_srcdir)/include \ include_HEADERS=include/uv.h uvincludedir = $(includedir)/uv -uvinclude_HEADERS=include/uv/errno.h include/uv/threadpool.h include/uv/version.h +uvinclude_HEADERS = include/uv/errno.h \ + include/uv/threadpool.h \ + include/uv/version.h CLEANFILES = @@ -293,6 +295,7 @@ test_run_tests_SOURCES = test/blackhole-server.c \ test/test-udp-send-immediate.c \ test/test-udp-send-unreachable.c \ test/test-udp-try-send.c \ + test/test-uname.c \ test/test-walk-handles.c \ test/test-watcher-cross-stop.c test_run_tests_LDADD = libuv.la @@ -306,7 +309,9 @@ test_run_tests_SOURCES += test/runner-unix.c \ endif if AIX -test_run_tests_CFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 -D_LINUX_SOURCE_COMPAT +test_run_tests_CFLAGS += -D_ALL_SOURCE \ + -D_XOPEN_SOURCE=500 \ + -D_LINUX_SOURCE_COMPAT endif if LINUX diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index 35e7c1b7493acd..ab656c83d23502 100644 --- a/deps/uv/configure.ac +++ b/deps/uv/configure.ac @@ -13,7 +13,7 @@ # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. AC_PREREQ(2.57) -AC_INIT([libuv], [1.24.1], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.25.0], [https://github.com/libuv/libuv/issues]) AC_CONFIG_MACRO_DIR([m4]) m4_include([m4/libuv-extra-automake-flags.m4]) m4_include([m4/as_case.m4]) @@ -73,4 +73,6 @@ AS_CASE([$host_os], [kfreebsd*], [ ]) AC_CHECK_HEADERS([sys/ahafs_evProds.h]) AC_CONFIG_FILES([Makefile libuv.pc]) +AC_CONFIG_LINKS([test/fixtures/empty_file:test/fixtures/empty_file]) +AC_CONFIG_LINKS([test/fixtures/load_error.node:test/fixtures/load_error.node]) AC_OUTPUT diff --git a/deps/uv/docs/src/fs.rst b/deps/uv/docs/src/fs.rst index 21f9e27cb40727..af97ec3a648882 100644 --- a/deps/uv/docs/src/fs.rst +++ b/deps/uv/docs/src/fs.rst @@ -233,15 +233,6 @@ API Equivalent to :man:`rename(2)`. - .. note:: - On Windows if this function fails with ``UV_EBUSY``, ``UV_EPERM`` or - ``UV_EACCES``, it will retry to rename the file up to four times with - 250ms wait between attempts before giving up. If both `path` and - `new_path` are existing directories this function will work only if - target directory is empty. - - .. versionchanged:: 1.24.0 Added retrying and directory move support on Windows. - .. c:function:: int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) Equivalent to :man:`fsync(2)`. diff --git a/deps/uv/docs/src/misc.rst b/deps/uv/docs/src/misc.rst index cf4a7895cd147b..81c03a85303180 100644 --- a/deps/uv/docs/src/misc.rst +++ b/deps/uv/docs/src/misc.rst @@ -145,6 +145,19 @@ Data types char* homedir; } uv_passwd_t; +.. c:type:: uv_utsname_t + + Data type for operating system name and version information. + + :: + + typedef struct uv_utsname_s { + char sysname[256]; + char release[256]; + char version[256]; + char machine[256]; + } uv_utsname_t; + API --- @@ -549,3 +562,12 @@ API for others it will be silently reduced to `PRIORITY_HIGH`. .. versionadded:: 1.23.0 + +.. c:function:: int uv_os_uname(uv_utsname_t* buffer) + + Retrieves system information in `buffer`. The populated data includes the + operating system name, release, version, and machine. On non-Windows + systems, `uv_os_uname()` is a thin wrapper around :man:`uname(3)`. Returns + zero on success, and a non-zero error value otherwise. + + .. versionadded:: 1.25.0 diff --git a/deps/uv/include/uv.h b/deps/uv/include/uv.h index 86a2ecc2d74469..a46b229dfd166e 100644 --- a/deps/uv/include/uv.h +++ b/deps/uv/include/uv.h @@ -234,6 +234,7 @@ typedef struct uv_cpu_info_s uv_cpu_info_t; typedef struct uv_interface_address_s uv_interface_address_t; typedef struct uv_dirent_s uv_dirent_t; typedef struct uv_passwd_s uv_passwd_t; +typedef struct uv_utsname_s uv_utsname_t; typedef enum { UV_LOOP_BLOCK_SIGNAL @@ -968,13 +969,13 @@ enum uv_process_flags { */ UV_PROCESS_WINDOWS_HIDE = (1 << 4), /* - * Hide the subprocess console window that would normally be created. This + * Hide the subprocess console window that would normally be created. This * option is only meaningful on Windows systems. On Unix it is silently * ignored. */ UV_PROCESS_WINDOWS_HIDE_CONSOLE = (1 << 5), /* - * Hide the subprocess GUI window that would normally be created. This + * Hide the subprocess GUI window that would normally be created. This * option is only meaningful on Windows systems. On Unix it is silently * ignored. */ @@ -1054,6 +1055,16 @@ struct uv_passwd_s { char* homedir; }; +struct uv_utsname_s { + char sysname[256]; + char release[256]; + char version[256]; + char machine[256]; + /* This struct does not contain the nodename and domainname fields present in + the utsname type. domainname is a GNU extension. Both fields are referred + to as meaningless in the docs. */ +}; + typedef enum { UV_DIRENT_UNKNOWN, UV_DIRENT_FILE, @@ -1135,6 +1146,8 @@ UV_EXTERN int uv_os_unsetenv(const char* name); UV_EXTERN int uv_os_gethostname(char* buffer, size_t* size); +UV_EXTERN int uv_os_uname(uv_utsname_t* buffer); + typedef enum { UV_FS_UNKNOWN = -1, diff --git a/deps/uv/include/uv/unix.h b/deps/uv/include/uv/unix.h index 9de9efecff14c4..d887d7211f1d1e 100644 --- a/deps/uv/include/uv/unix.h +++ b/deps/uv/include/uv/unix.h @@ -136,7 +136,9 @@ typedef pthread_cond_t uv_cond_t; typedef pthread_key_t uv_key_t; /* Note: guard clauses should match uv_barrier_init's in src/unix/thread.c. */ -#if defined(_AIX) || !defined(PTHREAD_BARRIER_SERIAL_THREAD) +#if defined(_AIX) || \ + defined(__OpenBSD__) || \ + !defined(PTHREAD_BARRIER_SERIAL_THREAD) /* TODO(bnoordhuis) Merge into uv_barrier_t in v2. */ struct _uv_barrier { uv_mutex_t mutex; diff --git a/deps/uv/include/uv/version.h b/deps/uv/include/uv/version.h index 3bc023700ef002..136772128ab35a 100644 --- a/deps/uv/include/uv/version.h +++ b/deps/uv/include/uv/version.h @@ -31,8 +31,8 @@ */ #define UV_VERSION_MAJOR 1 -#define UV_VERSION_MINOR 24 -#define UV_VERSION_PATCH 1 +#define UV_VERSION_MINOR 25 +#define UV_VERSION_PATCH 0 #define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_SUFFIX "" diff --git a/deps/uv/src/unix/aix.c b/deps/uv/src/unix/aix.c index 44c9cf5b639c31..337e58e0adc02f 100644 --- a/deps/uv/src/unix/aix.c +++ b/deps/uv/src/unix/aix.c @@ -555,7 +555,7 @@ static int uv__setup_ahafs(const char* filename, int *fd) { sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1"); rc = write(*fd, mon_file_write_string, strlen(mon_file_write_string)+1); - if (rc < 0) + if (rc < 0 && errno != EBUSY) return UV__ERR(errno); return 0; @@ -728,10 +728,16 @@ int uv_fs_event_start(uv_fs_event_t* handle, char cwd[PATH_MAX]; char absolute_path[PATH_MAX]; char readlink_cwd[PATH_MAX]; + struct timeval zt; + fd_set pollfd; /* Figure out whether filename is absolute or not */ - if (filename[0] == '/') { + if (filename[0] == '\0') { + /* Missing a pathname */ + return UV_ENOENT; + } + else if (filename[0] == '/') { /* We have absolute pathname */ /* TODO(bnoordhuis) Check uv__strscpy() return value. */ uv__strscpy(absolute_path, filename, sizeof(absolute_path)); @@ -768,6 +774,15 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv__io_start(handle->loop, &handle->event_watcher, POLLIN); + /* AHAFS wants someone to poll for it to start mointoring. + * so kick-start it so that we don't miss an event in the + * eventuality of an event that occurs in the current loop. */ + do { + memset(&zt, 0, sizeof(zt)); + FD_ZERO(&pollfd); + FD_SET(fd, &pollfd); + rc = select(fd + 1, &pollfd, NULL, NULL, &zt); + } while (rc == -1 && errno == EINTR); return 0; #else return UV_ENOSYS; diff --git a/deps/uv/src/unix/bsd-ifaddrs.c b/deps/uv/src/unix/bsd-ifaddrs.c index 2f2201f9ed024a..3c2253f0c9c952 100644 --- a/deps/uv/src/unix/bsd-ifaddrs.c +++ b/deps/uv/src/unix/bsd-ifaddrs.c @@ -52,13 +52,10 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) { */ if (ent->ifa_addr->sa_family == AF_LINK) return 1; -#elif defined(__NetBSD__) +#elif defined(__NetBSD__) || defined(__OpenBSD__) if (ent->ifa_addr->sa_family != PF_INET && ent->ifa_addr->sa_family != PF_INET6) return 1; -#elif defined(__OpenBSD__) - if (ent->ifa_addr->sa_family != PF_INET) - return 1; #endif return 0; } diff --git a/deps/uv/src/unix/core.c b/deps/uv/src/unix/core.c index 0830c74a168e92..cd57ce20ba2edb 100644 --- a/deps/uv/src/unix/core.c +++ b/deps/uv/src/unix/core.c @@ -40,6 +40,7 @@ #include /* writev */ #include /* getrusage */ #include +#include #ifdef __sun # include /* MAXHOSTNAMELEN on Solaris */ @@ -1357,3 +1358,59 @@ int uv_os_setpriority(uv_pid_t pid, int priority) { return 0; } + + +int uv_os_uname(uv_utsname_t* buffer) { + struct utsname buf; + int r; + + if (buffer == NULL) + return UV_EINVAL; + + if (uname(&buf) == -1) { + r = UV__ERR(errno); + goto error; + } + + r = uv__strscpy(buffer->sysname, buf.sysname, sizeof(buffer->sysname)); + if (r == UV_E2BIG) + goto error; + +#ifdef _AIX + r = snprintf(buffer->release, + sizeof(buffer->release), + "%s.%s", + buf.version, + buf.release); + if (r >= sizeof(buffer->release)) { + r = UV_E2BIG; + goto error; + } +#else + r = uv__strscpy(buffer->release, buf.release, sizeof(buffer->release)); + if (r == UV_E2BIG) + goto error; +#endif + + r = uv__strscpy(buffer->version, buf.version, sizeof(buffer->version)); + if (r == UV_E2BIG) + goto error; + +#if defined(_AIX) || defined(__PASE__) + r = uv__strscpy(buffer->machine, "ppc64", sizeof(buffer->machine)); +#else + r = uv__strscpy(buffer->machine, buf.machine, sizeof(buffer->machine)); +#endif + + if (r == UV_E2BIG) + goto error; + + return 0; + +error: + buffer->sysname[0] = '\0'; + buffer->release[0] = '\0'; + buffer->version[0] = '\0'; + buffer->machine[0] = '\0'; + return r; +} diff --git a/deps/uv/src/unix/fs.c b/deps/uv/src/unix/fs.c index d22c70f0c293d4..91bb82f725e884 100644 --- a/deps/uv/src/unix/fs.c +++ b/deps/uv/src/unix/fs.c @@ -155,7 +155,7 @@ static ssize_t uv__fs_fsync(uv_fs_t* req) { int r; r = fcntl(req->file, F_FULLFSYNC); - if (r != 0 && errno == ENOTTY) + if (r != 0) r = fsync(req->file); return r; #else @@ -317,6 +317,18 @@ static ssize_t uv__fs_read(uv_fs_t* req) { req->bufs = NULL; req->nbufs = 0; +#ifdef __PASE__ + /* PASE returns EOPNOTSUPP when reading a directory, convert to EISDIR */ + if (result == -1 && errno == EOPNOTSUPP) { + struct stat buf; + ssize_t rc; + rc = fstat(req->file, &buf); + if (rc == 0 && S_ISDIR(buf.st_mode)) { + errno = EISDIR; + } + } +#endif + return result; } diff --git a/deps/uv/src/unix/fsevents.c b/deps/uv/src/unix/fsevents.c index ee45299b791294..c430562b37298a 100644 --- a/deps/uv/src/unix/fsevents.c +++ b/deps/uv/src/unix/fsevents.c @@ -255,42 +255,55 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef, path = paths[i]; len = strlen(path); + if (handle->realpath_len == 0) + continue; /* This should be unreachable */ + /* Filter out paths that are outside handle's request */ - if (strncmp(path, handle->realpath, handle->realpath_len) != 0) + if (len < handle->realpath_len) + continue; + + if (handle->realpath_len != len && + path[handle->realpath_len] != '/') + /* Make sure that realpath actually named a directory, + * or that we matched the whole string */ continue; - if (handle->realpath_len > 1 || *handle->realpath != '/') { + if (memcmp(path, handle->realpath, handle->realpath_len) != 0) + continue; + + if (!(handle->realpath_len == 1 && handle->realpath[0] == '/')) { + /* Remove common prefix, unless the watched folder is "/" */ path += handle->realpath_len; len -= handle->realpath_len; - /* Skip forward slash */ - if (*path != '\0') { + /* Ignore events with path equal to directory itself */ + if (len <= 1 && (flags & kFSEventStreamEventFlagItemIsDir)) + continue; + + if (len == 0) { + /* Since we're using fsevents to watch the file itself, + * realpath == path, and we now need to get the basename of the file back + * (for commonality with other codepaths and platforms). */ + while (len < handle->realpath_len && path[-1] != '/') { + path--; + len++; + } + /* Created and Removed seem to be always set, but don't make sense */ + flags &= ~kFSEventsRenamed; + } else { + /* Skip forward slash */ path++; len--; } } -#ifdef MAC_OS_X_VERSION_10_7 - /* Ignore events with path equal to directory itself */ - if (len == 0) - continue; -#else - if (len == 0 && (flags & kFSEventStreamEventFlagItemIsDir)) - continue; -#endif /* MAC_OS_X_VERSION_10_7 */ - /* Do not emit events from subdirectories (without option set) */ - if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != 0) { + if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != '\0') { pos = strchr(path + 1, '/'); if (pos != NULL) continue; } -#ifndef MAC_OS_X_VERSION_10_7 - path = ""; - len = 0; -#endif /* MAC_OS_X_VERSION_10_7 */ - event = uv__malloc(sizeof(*event) + len); if (event == NULL) break; @@ -299,22 +312,11 @@ static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef, memcpy(event->path, path, len + 1); event->events = UV_RENAME; -#ifdef MAC_OS_X_VERSION_10_7 - if (0 != (flags & kFSEventsModified) && - 0 == (flags & kFSEventsRenamed)) { - event->events = UV_CHANGE; - } -#else - if (0 != (flags & kFSEventsModified) && - 0 != (flags & kFSEventStreamEventFlagItemIsDir) && - 0 == (flags & kFSEventStreamEventFlagItemRenamed)) { - event->events = UV_CHANGE; - } - if (0 == (flags & kFSEventStreamEventFlagItemIsDir) && - 0 == (flags & kFSEventStreamEventFlagItemRenamed)) { - event->events = UV_CHANGE; + if (0 == (flags & kFSEventsRenamed)) { + if (0 != (flags & kFSEventsModified) || + 0 == (flags & kFSEventStreamEventFlagItemIsDir)) + event->events = UV_CHANGE; } -#endif /* MAC_OS_X_VERSION_10_7 */ QUEUE_INSERT_TAIL(&head, &event->member); } diff --git a/deps/uv/src/unix/internal.h b/deps/uv/src/unix/internal.h index 72d8da8a508b88..c059893a46e992 100644 --- a/deps/uv/src/unix/internal.h +++ b/deps/uv/src/unix/internal.h @@ -284,24 +284,6 @@ int uv__fsevents_init(uv_fs_event_t* handle); int uv__fsevents_close(uv_fs_event_t* handle); void uv__fsevents_loop_delete(uv_loop_t* loop); -/* OSX < 10.7 has no file events, polyfill them */ -#ifndef MAC_OS_X_VERSION_10_7 - -static const int kFSEventStreamCreateFlagFileEvents = 0x00000010; -static const int kFSEventStreamEventFlagItemCreated = 0x00000100; -static const int kFSEventStreamEventFlagItemRemoved = 0x00000200; -static const int kFSEventStreamEventFlagItemInodeMetaMod = 0x00000400; -static const int kFSEventStreamEventFlagItemRenamed = 0x00000800; -static const int kFSEventStreamEventFlagItemModified = 0x00001000; -static const int kFSEventStreamEventFlagItemFinderInfoMod = 0x00002000; -static const int kFSEventStreamEventFlagItemChangeOwner = 0x00004000; -static const int kFSEventStreamEventFlagItemXattrMod = 0x00008000; -static const int kFSEventStreamEventFlagItemIsFile = 0x00010000; -static const int kFSEventStreamEventFlagItemIsDir = 0x00020000; -static const int kFSEventStreamEventFlagItemIsSymlink = 0x00040000; - -#endif /* __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 */ - #endif /* defined(__APPLE__) */ UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) { diff --git a/deps/uv/src/unix/kqueue.c b/deps/uv/src/unix/kqueue.c index 930f2da7126a5d..c24f96e1399c69 100644 --- a/deps/uv/src/unix/kqueue.c +++ b/deps/uv/src/unix/kqueue.c @@ -452,49 +452,48 @@ int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb, const char* path, unsigned int flags) { -#if defined(__APPLE__) - struct stat statbuf; -#endif /* defined(__APPLE__) */ int fd; if (uv__is_active(handle)) return UV_EINVAL; - /* TODO open asynchronously - but how do we report back errors? */ - fd = open(path, O_RDONLY); - if (fd == -1) - return UV__ERR(errno); - - uv__handle_start(handle); - uv__io_init(&handle->event_watcher, uv__fs_event, fd); - handle->path = uv__strdup(path); - handle->cb = cb; - #if defined(__APPLE__) - if (uv__has_forked_with_cfrunloop) - goto fallback; - /* Nullify field to perform checks later */ handle->cf_cb = NULL; handle->realpath = NULL; handle->realpath_len = 0; handle->cf_flags = flags; - if (fstat(fd, &statbuf)) - goto fallback; - /* FSEvents works only with directories */ - if (!(statbuf.st_mode & S_IFDIR)) - goto fallback; - - /* The fallback fd is no longer needed */ - uv__close(fd); - handle->event_watcher.fd = -1; - - return uv__fsevents_init(handle); - -fallback: + if (!uv__has_forked_with_cfrunloop) { + int r; + /* The fallback fd is not used */ + handle->event_watcher.fd = -1; + handle->path = uv__strdup(path); + if (handle->path == NULL) + return UV_ENOMEM; + handle->cb = cb; + r = uv__fsevents_init(handle); + if (r == 0) { + uv__handle_start(handle); + } else { + uv__free(handle->path); + handle->path = NULL; + } + return r; + } #endif /* defined(__APPLE__) */ + /* TODO open asynchronously - but how do we report back errors? */ + fd = open(path, O_RDONLY); + if (fd == -1) + return UV__ERR(errno); + + handle->path = uv__strdup(path); + if (handle->path == NULL) + return UV_ENOMEM; + handle->cb = cb; + uv__handle_start(handle); + uv__io_init(&handle->event_watcher, uv__fs_event, fd); uv__io_start(handle->loop, &handle->event_watcher, POLLIN); return 0; @@ -502,29 +501,29 @@ int uv_fs_event_start(uv_fs_event_t* handle, int uv_fs_event_stop(uv_fs_event_t* handle) { + int r; + r = 0; + if (!uv__is_active(handle)) return 0; uv__handle_stop(handle); #if defined(__APPLE__) - if (uv__has_forked_with_cfrunloop || uv__fsevents_close(handle)) -#endif /* defined(__APPLE__) */ - { - uv__io_close(handle->loop, &handle->event_watcher); - } - - uv__free(handle->path); - handle->path = NULL; + if (!uv__has_forked_with_cfrunloop) + r = uv__fsevents_close(handle); +#endif if (handle->event_watcher.fd != -1) { - /* When FSEvents is used, we don't use the event_watcher's fd under certain - * confitions. (see uv_fs_event_start) */ + uv__io_close(handle->loop, &handle->event_watcher); uv__close(handle->event_watcher.fd); handle->event_watcher.fd = -1; } - return 0; + uv__free(handle->path); + handle->path = NULL; + + return r; } diff --git a/deps/uv/src/unix/stream.c b/deps/uv/src/unix/stream.c index 2e84eeeb82877e..7e4d5fc7ffd429 100644 --- a/deps/uv/src/unix/stream.c +++ b/deps/uv/src/unix/stream.c @@ -58,11 +58,19 @@ struct uv__stream_select_s { fd_set* swrite; size_t swrite_sz; }; -# define WRITE_RETRY_ON_ERROR(send_handle) \ + +/* Due to a possible kernel bug at least in OS X 10.10 "Yosemite", + * EPROTOTYPE can be returned while trying to write to a socket that is + * shutting down. If we retry the write, we should get the expected EPIPE + * instead. + */ +# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR || errno == EPROTOTYPE) +# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \ (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS || \ - (errno == EMSGSIZE && send_handle)) + (errno == EMSGSIZE && send_handle != NULL)) #else -# define WRITE_RETRY_ON_ERROR(send_handle) \ +# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR) +# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \ (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS) #endif /* defined(__APPLE__) */ @@ -700,6 +708,14 @@ static void uv__drain(uv_stream_t* stream) { } +static ssize_t uv__writev(int fd, struct iovec* vec, size_t n) { + if (n == 1) + return write(fd, vec->iov_base, vec->iov_len); + else + return writev(fd, vec, n); +} + + static size_t uv__write_req_size(uv_write_t* req) { size_t size; @@ -712,6 +728,37 @@ static size_t uv__write_req_size(uv_write_t* req) { } +/* Returns 1 if all write request data has been written, or 0 if there is still + * more data to write. + * + * Note: the return value only says something about the *current* request. + * There may still be other write requests sitting in the queue. + */ +static int uv__write_req_update(uv_stream_t* stream, + uv_write_t* req, + size_t n) { + uv_buf_t* buf; + size_t len; + + assert(n <= stream->write_queue_size); + stream->write_queue_size -= n; + + buf = req->bufs + req->write_index; + + do { + len = n < buf->len ? n : buf->len; + buf->base += len; + buf->len -= len; + buf += (buf->len == 0); /* Advance to next buffer if this one is empty. */ + n -= len; + } while (n > 0); + + req->write_index = buf - req->bufs; + + return req->write_index == req->nbufs; +} + + static void uv__write_req_finish(uv_write_t* req) { uv_stream_t* stream = req->handle; @@ -832,102 +879,32 @@ static void uv__write(uv_stream_t* stream) { *pi = fd_to_send; } - do { + do n = sendmsg(uv__stream_fd(stream), &msg, 0); - } -#if defined(__APPLE__) - /* - * Due to a possible kernel bug at least in OS X 10.10 "Yosemite", - * EPROTOTYPE can be returned while trying to write to a socket that is - * shutting down. If we retry the write, we should get the expected EPIPE - * instead. - */ - while (n == -1 && (errno == EINTR || errno == EPROTOTYPE)); -#else - while (n == -1 && errno == EINTR); -#endif - } else { - do { - if (iovcnt == 1) { - n = write(uv__stream_fd(stream), iov[0].iov_base, iov[0].iov_len); - } else { - n = writev(uv__stream_fd(stream), iov, iovcnt); - } - } -#if defined(__APPLE__) - /* - * Due to a possible kernel bug at least in OS X 10.10 "Yosemite", - * EPROTOTYPE can be returned while trying to write to a socket that is - * shutting down. If we retry the write, we should get the expected EPIPE - * instead. - */ - while (n == -1 && (errno == EINTR || errno == EPROTOTYPE)); -#else - while (n == -1 && errno == EINTR); -#endif - } + while (n == -1 && RETRY_ON_WRITE_ERROR(errno)); - if (n < 0) { - if (!WRITE_RETRY_ON_ERROR(req->send_handle)) { - err = UV__ERR(errno); - goto error; - } else if (stream->flags & UV_HANDLE_BLOCKING_WRITES) { - /* If this is a blocking stream, try again. */ - goto start; - } + /* Ensure the handle isn't sent again in case this is a partial write. */ + if (n >= 0) + req->send_handle = NULL; } else { - /* Successful write */ - - while (n >= 0) { - uv_buf_t* buf = &(req->bufs[req->write_index]); - size_t len = buf->len; - - assert(req->write_index < req->nbufs); - - if ((size_t)n < len) { - buf->base += n; - buf->len -= n; - stream->write_queue_size -= n; - n = 0; - - /* There is more to write. */ - if (stream->flags & UV_HANDLE_BLOCKING_WRITES) { - /* - * If we're blocking then we should not be enabling the write - * watcher - instead we need to try again. - */ - goto start; - } else { - /* Break loop and ensure the watcher is pending. */ - break; - } - - } else { - /* Finished writing the buf at index req->write_index. */ - req->write_index++; - - assert((size_t)n >= len); - n -= len; - - assert(stream->write_queue_size >= len); - stream->write_queue_size -= len; + do + n = uv__writev(uv__stream_fd(stream), iov, iovcnt); + while (n == -1 && RETRY_ON_WRITE_ERROR(errno)); + } - if (req->write_index == req->nbufs) { - /* Then we're done! */ - assert(n == 0); - uv__write_req_finish(req); - /* TODO: start trying to write the next request. */ - return; - } - } - } + if (n == -1 && !IS_TRANSIENT_WRITE_ERROR(errno, req->send_handle)) { + err = UV__ERR(errno); + goto error; } - /* Either we've counted n down to zero or we've got EAGAIN. */ - assert(n == 0 || n == -1); + if (n >= 0 && uv__write_req_update(stream, req, n)) { + uv__write_req_finish(req); + return; /* TODO(bnoordhuis) Start trying to write the next request. */ + } - /* Only non-blocking streams should use the write_watcher. */ - assert(!(stream->flags & UV_HANDLE_BLOCKING_WRITES)); + /* If this is a blocking stream, try again. */ + if (stream->flags & UV_HANDLE_BLOCKING_WRITES) + goto start; /* We're not done. */ uv__io_start(stream->loop, &stream->io_watcher, POLLOUT); diff --git a/deps/uv/src/unix/thread.c b/deps/uv/src/unix/thread.c index 29004707a41947..8bcb857610fa98 100644 --- a/deps/uv/src/unix/thread.c +++ b/deps/uv/src/unix/thread.c @@ -48,8 +48,10 @@ STATIC_ASSERT(sizeof(uv_barrier_t) == sizeof(pthread_barrier_t)); #endif -/* Note: guard clauses should match uv_barrier_t's in include/uv/uv-unix.h. */ -#if defined(_AIX) || !defined(PTHREAD_BARRIER_SERIAL_THREAD) +/* Note: guard clauses should match uv_barrier_t's in include/uv/unix.h. */ +#if defined(_AIX) || \ + defined(__OpenBSD__) || \ + !defined(PTHREAD_BARRIER_SERIAL_THREAD) int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { struct _uv_barrier* b; int rc; diff --git a/deps/uv/src/unix/udp.c b/deps/uv/src/unix/udp.c index e6668a012c5c27..ec337ec8b8dfc2 100644 --- a/deps/uv/src/unix/udp.c +++ b/deps/uv/src/unix/udp.c @@ -760,14 +760,16 @@ int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) { * IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case, * and use the general uv__setsockopt_maybe_char call otherwise. */ -#if defined(__sun) || defined(_AIX) || defined(__MVS__) +#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \ + defined(__MVS__) if (handle->flags & UV_HANDLE_IPV6) return uv__setsockopt(handle, IP_MULTICAST_TTL, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)); -#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */ +#endif /* defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \ + defined(__MVS__) */ return uv__setsockopt_maybe_char(handle, IP_MULTICAST_TTL, @@ -783,14 +785,16 @@ int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) { * IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case, * and use the general uv__setsockopt_maybe_char call otherwise. */ -#if defined(__sun) || defined(_AIX) || defined(__MVS__) +#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \ + defined(__MVS__) if (handle->flags & UV_HANDLE_IPV6) return uv__setsockopt(handle, IP_MULTICAST_LOOP, IPV6_MULTICAST_LOOP, &on, sizeof(on)); -#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */ +#endif /* defined(__sun) || defined(_AIX) ||defined(__OpenBSD__) || + defined(__MVS__) */ return uv__setsockopt_maybe_char(handle, IP_MULTICAST_LOOP, diff --git a/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c index 1244967a78dacb..acf8e1107e9786 100644 --- a/deps/uv/src/win/fs-event.c +++ b/deps/uv/src/win/fs-event.c @@ -230,8 +230,11 @@ int uv_fs_event_start(uv_fs_event_t* handle, */ /* Convert to short path. */ - short_path = short_path_buffer; - if (!GetShortPathNameW(pathw, short_path, ARRAY_SIZE(short_path))) { + if (GetShortPathNameW(pathw, + short_path_buffer, + ARRAY_SIZE(short_path_buffer))) { + short_path = short_path_buffer; + } else { short_path = NULL; } diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 0716ecca1221e6..65d936bf08f555 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -42,8 +42,6 @@ #define UV_FS_FREE_PTR 0x0008 #define UV_FS_CLEANEDUP 0x0010 -#define UV__RENAME_RETRIES 4 -#define UV__RENAME_WAIT 250 #define INIT(subtype) \ do { \ @@ -1360,78 +1358,12 @@ static void fs__fstat(uv_fs_t* req) { static void fs__rename(uv_fs_t* req) { - int tries; - int sys_errno; - int result; - int try_rmdir; - WCHAR* src, *dst; - DWORD src_attrib, dst_attrib; - - src = req->file.pathw; - dst = req->fs.info.new_pathw; - try_rmdir = 0; - - /* Do some checks to fail early. */ - src_attrib = GetFileAttributesW(src); - if (src_attrib == INVALID_FILE_ATTRIBUTES) { + if (!MoveFileExW(req->file.pathw, req->fs.info.new_pathw, MOVEFILE_REPLACE_EXISTING)) { SET_REQ_WIN32_ERROR(req, GetLastError()); return; } - dst_attrib = GetFileAttributesW(dst); - if (dst_attrib != INVALID_FILE_ATTRIBUTES) { - if (dst_attrib & FILE_ATTRIBUTE_READONLY) { - req->result = UV_EPERM; - return; - } - /* Renaming folder to a folder name that already exist will fail on - * Windows. We will try to delete target folder first. - */ - if (src_attrib & FILE_ATTRIBUTE_DIRECTORY && - dst_attrib & FILE_ATTRIBUTE_DIRECTORY) - try_rmdir = 1; - } - - /* Sometimes an antivirus or indexing software can lock the target or the - * source file/directory. This is annoying for users, in such cases we will - * retry couple of times with some delay before failing. - */ - for (tries = 0; tries < UV__RENAME_RETRIES; ++tries) { - if (tries > 0) - Sleep(UV__RENAME_WAIT); - - if (try_rmdir) { - result = _wrmdir(dst) == 0 ? 0 : uv_translate_sys_error(_doserrno); - switch (result) - { - case 0: - case UV_ENOENT: - /* Folder removed or did not exist at all. */ - try_rmdir = 0; - break; - case UV_ENOTEMPTY: - /* Non-empty target folder, fail instantly. */ - SET_REQ_RESULT(req, -1); - return; - default: - /* All other errors - try to move file anyway and handle the error - * there, retrying folder deletion next time around. - */ - break; - } - } - - if (MoveFileExW(src, dst, MOVEFILE_REPLACE_EXISTING) != 0) { - SET_REQ_RESULT(req, 0); - return; - } - sys_errno = GetLastError(); - result = uv_translate_sys_error(sys_errno); - if (result != UV_EBUSY && result != UV_EPERM && result != UV_EACCES) - break; - } - req->sys_errno_ = sys_errno; - req->result = result; + SET_REQ_RESULT(req, 0); } diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index e303cc8a2331e7..277f6497a25234 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -1310,7 +1310,6 @@ static int uv__pipe_write_data(uv_loop_t* loop, uv_pipe_t* handle, const uv_buf_t bufs[], size_t nbufs, - uv_stream_t* send_handle, uv_write_cb cb, int copy_always) { int err; @@ -1321,7 +1320,7 @@ static int uv__pipe_write_data(uv_loop_t* loop, UV_REQ_INIT(req, UV_WRITE); req->handle = (uv_stream_t*) handle; - req->send_handle = send_handle; + req->send_handle = NULL; req->cb = cb; /* Private fields. */ req->coalesced = 0; @@ -1558,8 +1557,7 @@ int uv__pipe_write_ipc(uv_loop_t* loop, /* Write buffers. We set the `always_copy` flag, so it is not a problem that * some of the written data lives on the stack. */ - err = uv__pipe_write_data( - loop, req, handle, bufs, buf_count, send_handle, cb, 1); + err = uv__pipe_write_data(loop, req, handle, bufs, buf_count, cb, 1); /* If we had to heap-allocate the bufs array, free it now. */ if (bufs != stack_bufs) { @@ -1583,8 +1581,7 @@ int uv__pipe_write(uv_loop_t* loop, } else { /* Non-IPC pipe write: put data on the wire directly. */ assert(send_handle == NULL); - return uv__pipe_write_data( - loop, req, handle, bufs, nbufs, NULL, cb, 0); + return uv__pipe_write_data(loop, req, handle, bufs, nbufs, cb, 0); } } diff --git a/deps/uv/src/win/thread.c b/deps/uv/src/win/thread.c index 56ca41aab0b759..fd4b7c98688f69 100644 --- a/deps/uv/src/win/thread.c +++ b/deps/uv/src/win/thread.c @@ -23,6 +23,12 @@ #include #include +#if defined(__MINGW64_VERSION_MAJOR) +/* MemoryBarrier expands to __mm_mfence in some cases (x86+sse2), which may + * require this header in some versions of mingw64. */ +#include +#endif + #include "uv.h" #include "internal.h" diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index 45bbe9689aea1d..f38e9a88636e4b 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -164,7 +164,7 @@ void uv_console_init(void) { OPEN_EXISTING, 0, 0); - if (uv__tty_console_handle != NULL) { + if (uv__tty_console_handle != INVALID_HANDLE_VALUE) { QueueUserWorkItem(uv__tty_console_resize_message_loop_thread, NULL, WT_EXECUTELONGFUNCTION); @@ -360,6 +360,8 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) { } } else { was_reading = 0; + alloc_cb = NULL; + read_cb = NULL; } uv_sem_wait(&uv_tty_output_lock); @@ -733,8 +735,9 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, /* Ignore keyup events, unless the left alt key was held and a valid * unicode character was emitted. */ - if (!KEV.bKeyDown && !(((KEV.dwControlKeyState & LEFT_ALT_PRESSED) || - KEV.wVirtualKeyCode==VK_MENU) && KEV.uChar.UnicodeChar != 0)) { + if (!KEV.bKeyDown && + KEV.wVirtualKeyCode != VK_MENU && + KEV.uChar.UnicodeChar != 0) { continue; } diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index 6e81c26165fbc0..923789129e92e0 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -1627,3 +1627,120 @@ int uv_os_setpriority(uv_pid_t pid, int priority) { CloseHandle(handle); return r; } + + +int uv_os_uname(uv_utsname_t* buffer) { + /* Implementation loosely based on + https://github.com/gagern/gnulib/blob/master/lib/uname.c */ + OSVERSIONINFOW os_info; + SYSTEM_INFO system_info; + int processor_level; + int r; + + if (buffer == NULL) + return UV_EINVAL; + + uv__once_init(); + os_info.dwOSVersionInfoSize = sizeof(os_info); + os_info.szCSDVersion[0] = L'\0'; + + /* Try calling RtlGetVersion(), and fall back to the deprecated GetVersionEx() + if RtlGetVersion() is not available. */ + if (pRtlGetVersion) { + pRtlGetVersion(&os_info); + } else { + /* Silence GetVersionEx() deprecation warning. */ + #pragma warning(suppress : 4996) + if (GetVersionExW(&os_info) == 0) { + r = uv_translate_sys_error(GetLastError()); + goto error; + } + } + + /* Populate the version field. */ + if (WideCharToMultiByte(CP_UTF8, + 0, + os_info.szCSDVersion, + -1, + buffer->version, + sizeof(buffer->version), + NULL, + NULL) == 0) { + r = uv_translate_sys_error(GetLastError()); + goto error; + } + + /* Populate the sysname field. */ +#ifdef __MINGW32__ + r = snprintf(buffer->sysname, + sizeof(buffer->sysname), + "MINGW32_NT-%u.%u", + (unsigned int) os_info.dwMajorVersion, + (unsigned int) os_info.dwMinorVersion); + assert(r < sizeof(buffer->sysname)); +#else + uv__strscpy(buffer->sysname, "Windows_NT", sizeof(buffer->sysname)); +#endif + + /* Populate the release field. */ + r = snprintf(buffer->release, + sizeof(buffer->release), + "%d.%d.%d", + (unsigned int) os_info.dwMajorVersion, + (unsigned int) os_info.dwMinorVersion, + (unsigned int) os_info.dwBuildNumber); + assert(r < sizeof(buffer->release)); + + /* Populate the machine field. */ + GetSystemInfo(&system_info); + + switch (system_info.wProcessorArchitecture) { + case PROCESSOR_ARCHITECTURE_AMD64: + uv__strscpy(buffer->machine, "x86_64", sizeof(buffer->machine)); + break; + case PROCESSOR_ARCHITECTURE_IA64: + uv__strscpy(buffer->machine, "ia64", sizeof(buffer->machine)); + break; + case PROCESSOR_ARCHITECTURE_INTEL: + uv__strscpy(buffer->machine, "i386", sizeof(buffer->machine)); + + if (system_info.wProcessorLevel > 3) { + processor_level = system_info.wProcessorLevel < 6 ? + system_info.wProcessorLevel : 6; + buffer->machine[1] = '0' + processor_level; + } + + break; + case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64: + uv__strscpy(buffer->machine, "i686", sizeof(buffer->machine)); + break; + case PROCESSOR_ARCHITECTURE_MIPS: + uv__strscpy(buffer->machine, "mips", sizeof(buffer->machine)); + break; + case PROCESSOR_ARCHITECTURE_ALPHA: + case PROCESSOR_ARCHITECTURE_ALPHA64: + uv__strscpy(buffer->machine, "alpha", sizeof(buffer->machine)); + break; + case PROCESSOR_ARCHITECTURE_PPC: + uv__strscpy(buffer->machine, "powerpc", sizeof(buffer->machine)); + break; + case PROCESSOR_ARCHITECTURE_SHX: + uv__strscpy(buffer->machine, "sh", sizeof(buffer->machine)); + break; + case PROCESSOR_ARCHITECTURE_ARM: + uv__strscpy(buffer->machine, "arm", sizeof(buffer->machine)); + break; + default: + uv__strscpy(buffer->machine, "unknown", sizeof(buffer->machine)); + break; + } + + return 0; + +error: + buffer->sysname[0] = '\0'; + buffer->release[0] = '\0'; + buffer->version[0] = '\0'; + buffer->machine[0] = '\0'; + return r; +} diff --git a/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c index 2c09b448a95c01..fbbbceed95ebcf 100644 --- a/deps/uv/src/win/winapi.c +++ b/deps/uv/src/win/winapi.c @@ -26,6 +26,7 @@ /* Ntdll function pointers */ +sRtlGetVersion pRtlGetVersion; sRtlNtStatusToDosError pRtlNtStatusToDosError; sNtDeviceIoControlFile pNtDeviceIoControlFile; sNtQueryInformationFile pNtQueryInformationFile; @@ -55,6 +56,9 @@ void uv_winapi_init(void) { uv_fatal_error(GetLastError(), "GetModuleHandleA"); } + pRtlGetVersion = (sRtlGetVersion) GetProcAddress(ntdll_module, + "RtlGetVersion"); + pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress( ntdll_module, "RtlNtStatusToDosError"); diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h index 2a8adf6b262463..82c5ed46711d2f 100644 --- a/deps/uv/src/win/winapi.h +++ b/deps/uv/src/win/winapi.h @@ -4519,6 +4519,9 @@ typedef VOID (NTAPI *PIO_APC_ROUTINE) PIO_STATUS_BLOCK IoStatusBlock, ULONG Reserved); +typedef NTSTATUS (NTAPI *sRtlGetVersion) + (PRTL_OSVERSIONINFOW lpVersionInformation); + typedef ULONG (NTAPI *sRtlNtStatusToDosError) (NTSTATUS Status); @@ -4707,6 +4710,7 @@ typedef HWINEVENTHOOK (WINAPI *sSetWinEventHook) /* Ntdll function pointers */ +extern sRtlGetVersion pRtlGetVersion; extern sRtlNtStatusToDosError pRtlNtStatusToDosError; extern sNtDeviceIoControlFile pNtDeviceIoControlFile; extern sNtQueryInformationFile pNtQueryInformationFile; diff --git a/deps/uv/test/run-tests.c b/deps/uv/test/run-tests.c index 2a699f46dcb0ff..eba28ecb9aa0a5 100644 --- a/deps/uv/test/run-tests.c +++ b/deps/uv/test/run-tests.c @@ -42,6 +42,7 @@ int ipc_helper_tcp_connection(void); int ipc_helper_closed_handle(void); int ipc_send_recv_helper(void); int ipc_helper_bind_twice(void); +int ipc_helper_send_zero(void); int stdio_over_pipes_helper(void); int spawn_stdin_stdout(void); int spawn_tcp_server_helper(void); @@ -104,6 +105,10 @@ static int maybe_run_test(int argc, char **argv) { return ipc_helper_bind_twice(); } + if (strcmp(argv[1], "ipc_helper_send_zero") == 0) { + return ipc_helper_send_zero(); + } + if (strcmp(argv[1], "stdio_over_pipes_helper") == 0) { return stdio_over_pipes_helper(); } diff --git a/deps/uv/test/test-fs-event.c b/deps/uv/test/test-fs-event.c index 5ddccffd0a98e9..ea34bd63a70625 100644 --- a/deps/uv/test/test-fs-event.c +++ b/deps/uv/test/test-fs-event.c @@ -480,6 +480,8 @@ TEST_IMPL(fs_event_watch_dir_recursive) { #ifdef _WIN32 TEST_IMPL(fs_event_watch_dir_short_path) { uv_loop_t* loop; + uv_fs_t req; + int has_shortnames; int r; /* Setup */ @@ -489,26 +491,37 @@ TEST_IMPL(fs_event_watch_dir_short_path) { create_dir("watch_dir"); create_file("watch_dir/file1"); - r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); - r = uv_fs_event_start(&fs_event, fs_event_cb_dir, "watch_~1", 0); - ASSERT(r == 0); - r = uv_timer_init(loop, &timer); - ASSERT(r == 0); - r = uv_timer_start(&timer, timer_cb_file, 100, 0); - ASSERT(r == 0); + /* Newer version of Windows ship with + HKLM\SYSTEM\CurrentControlSet\Control\FileSystem\NtfsDisable8dot3NameCreation + not equal to 0. So we verify the files we created are addressable by a 8.3 + short name */ + has_shortnames = uv_fs_stat(NULL, &req, "watch_~1", NULL) != UV_ENOENT; + if (has_shortnames) { + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + r = uv_fs_event_start(&fs_event, fs_event_cb_dir, "watch_~1", 0); + ASSERT(r == 0); + r = uv_timer_init(loop, &timer); + ASSERT(r == 0); + r = uv_timer_start(&timer, timer_cb_file, 100, 0); + ASSERT(r == 0); - uv_run(loop, UV_RUN_DEFAULT); + uv_run(loop, UV_RUN_DEFAULT); - ASSERT(fs_event_cb_called == 1); - ASSERT(timer_cb_called == 1); - ASSERT(close_cb_called == 1); + ASSERT(fs_event_cb_called == 1); + ASSERT(timer_cb_called == 1); + ASSERT(close_cb_called == 1); + } /* Cleanup */ remove("watch_dir/file1"); remove("watch_dir/"); MAKE_VALGRIND_HAPPY(); + + if (!has_shortnames) + RETURN_SKIP("Was not able to address files with 8.3 short name."); + return 0; } #endif @@ -576,6 +589,14 @@ TEST_IMPL(fs_event_watch_file_exact_path) { create_dir("watch_dir"); create_file("watch_dir/file.js"); create_file("watch_dir/file.jsx"); +#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_12) + /* Empirically, FSEvents seems to (reliably) report the preceeding + * create_file events prior to macOS 10.11.6 in the subsequent fs_watch + * creation, but that behavior hasn't been observed to occur on newer + * versions. Give a long delay here to let the system settle before running + * the test. */ + uv_sleep(1100); +#endif r = uv_fs_event_init(loop, &fs_event); ASSERT(r == 0); @@ -648,7 +669,7 @@ TEST_IMPL(fs_event_watch_file_current_dir) { r = uv_timer_init(loop, &timer); ASSERT(r == 0); - r = uv_timer_start(&timer, timer_cb_touch, 100, 0); + r = uv_timer_start(&timer, timer_cb_touch, 1100, 0); ASSERT(r == 0); ASSERT(timer_cb_touch_called == 0); @@ -936,32 +957,48 @@ TEST_IMPL(fs_event_getpath) { RETURN_SKIP(NO_FS_EVENTS); #endif uv_loop_t* loop = uv_default_loop(); + unsigned i; int r; char buf[1024]; size_t len; + const char* const watch_dir[] = { + "watch_dir", + "watch_dir/", + "watch_dir///", + "watch_dir/subfolder/..", + "watch_dir//subfolder//..//", + }; create_dir("watch_dir"); + create_dir("watch_dir/subfolder"); - r = uv_fs_event_init(loop, &fs_event); - ASSERT(r == 0); - len = sizeof buf; - r = uv_fs_event_getpath(&fs_event, buf, &len); - ASSERT(r == UV_EINVAL); - r = uv_fs_event_start(&fs_event, fail_cb, "watch_dir", 0); - ASSERT(r == 0); - len = sizeof buf; - r = uv_fs_event_getpath(&fs_event, buf, &len); - ASSERT(r == 0); - ASSERT(buf[len - 1] != 0); - ASSERT(buf[len] == '\0'); - ASSERT(memcmp(buf, "watch_dir", len) == 0); - r = uv_fs_event_stop(&fs_event); - ASSERT(r == 0); - uv_close((uv_handle_t*) &fs_event, close_cb); - uv_run(loop, UV_RUN_DEFAULT); + for (i = 0; i < ARRAY_SIZE(watch_dir); i++) { + r = uv_fs_event_init(loop, &fs_event); + ASSERT(r == 0); + len = sizeof buf; + r = uv_fs_event_getpath(&fs_event, buf, &len); + ASSERT(r == UV_EINVAL); + r = uv_fs_event_start(&fs_event, fail_cb, watch_dir[i], 0); + ASSERT(r == 0); + len = 0; + r = uv_fs_event_getpath(&fs_event, buf, &len); + ASSERT(r == UV_ENOBUFS); + ASSERT(len < sizeof buf); /* sanity check */ + ASSERT(len == strlen(watch_dir[i]) + 1); + r = uv_fs_event_getpath(&fs_event, buf, &len); + ASSERT(r == 0); + ASSERT(len == strlen(watch_dir[i])); + ASSERT(strcmp(buf, watch_dir[i]) == 0); + r = uv_fs_event_stop(&fs_event); + ASSERT(r == 0); + uv_close((uv_handle_t*) &fs_event, close_cb); - ASSERT(close_cb_called == 1); + uv_run(loop, UV_RUN_DEFAULT); + + ASSERT(close_cb_called == 1); + close_cb_called = 0; + } remove("watch_dir/"); MAKE_VALGRIND_HAPPY(); @@ -1082,6 +1119,9 @@ TEST_IMPL(fs_event_watch_invalid_path) { r = uv_fs_event_start(&fs_event, fs_event_cb_file, "<:;", 0); ASSERT(r != 0); ASSERT(uv_is_active((uv_handle_t*) &fs_event) == 0); + r = uv_fs_event_start(&fs_event, fs_event_cb_file, "", 0); + ASSERT(r != 0); + ASSERT(uv_is_active((uv_handle_t*) &fs_event) == 0); MAKE_VALGRIND_HAPPY(); return 0; } diff --git a/deps/uv/test/test-ipc-heavy-traffic-deadlock-bug.c b/deps/uv/test/test-ipc-heavy-traffic-deadlock-bug.c index 325305a6442fcf..753fb7b7c209e7 100644 --- a/deps/uv/test/test-ipc-heavy-traffic-deadlock-bug.c +++ b/deps/uv/test/test-ipc-heavy-traffic-deadlock-bug.c @@ -55,7 +55,7 @@ static void write_cb(uv_write_t* req, int status) { } static void shutdown_cb(uv_shutdown_t* req, int status) { - ASSERT(status == 0); + ASSERT(status == 0 || status == UV_ENOTCONN); uv_close((uv_handle_t*) req->handle, NULL); } diff --git a/deps/uv/test/test-ipc-send-recv.c b/deps/uv/test/test-ipc-send-recv.c index 166225c01c6b52..12d4e33221f4cf 100644 --- a/deps/uv/test/test-ipc-send-recv.c +++ b/deps/uv/test/test-ipc-send-recv.c @@ -149,7 +149,6 @@ static void connect_cb(uv_connect_t* req, int status) { &ctx.send.stream, NULL); ASSERT(r == 0); - ASSERT(ctx.write_req.send_handle == &ctx.send.stream); /* Perform two writes to the same pipe to make sure that on Windows we are * not running into issue 505: @@ -161,7 +160,6 @@ static void connect_cb(uv_connect_t* req, int status) { &ctx.send2.stream, NULL); ASSERT(r == 0); - ASSERT(ctx.write_req2.send_handle == &ctx.send2.stream); r = uv_read_start((uv_stream_t*)&ctx.channel, alloc_cb, recv_cb); ASSERT(r == 0); @@ -346,7 +344,6 @@ static void read_cb(uv_stream_t* handle, &recv->stream, write2_cb); ASSERT(r == 0); - ASSERT(write_req->send_handle == &recv->stream); } while (uv_pipe_pending_count(pipe) > 0); } diff --git a/deps/uv/test/test-ipc.c b/deps/uv/test/test-ipc.c index 829d178d47fe7a..88d04ba143cff4 100644 --- a/deps/uv/test/test-ipc.c +++ b/deps/uv/test/test-ipc.c @@ -39,12 +39,15 @@ static int local_conn_accepted; static int remote_conn_accepted; static int tcp_server_listening; static uv_write_t write_req; +static uv_write_t write_req2; static uv_write_t conn_notify_req; static int close_cb_called; static int connection_accepted; static int tcp_conn_read_cb_called; static int tcp_conn_write_cb_called; static int closed_handle_data_read; +static int closed_handle_write; +static int send_zero_write; typedef struct { uv_connect_t conn_req; @@ -54,7 +57,15 @@ typedef struct { #define CONN_COUNT 100 #define BACKLOG 128 -#define LARGE_SIZE 1000000 +#define LARGE_SIZE 100000 + +static uv_buf_t large_buf; +static char buffer[LARGE_SIZE]; +static uv_write_t write_reqs[300]; +static int write_reqs_completed; + +static unsigned int write_until_data_queued(void); +static void send_handle_and_close(void); static void close_server_conn_cb(uv_handle_t* handle) { @@ -92,6 +103,7 @@ static void exit_cb(uv_process_t* process, printf("exit_cb\n"); exit_cb_called++; ASSERT(exit_status == 0); + ASSERT(term_signal == 0); uv_close((uv_handle_t*)process, NULL); } @@ -420,6 +432,14 @@ static void on_read_closed_handle(uv_stream_t* handle, #endif +static void on_read_send_zero(uv_stream_t* handle, + ssize_t nread, + const uv_buf_t* buf) { + ASSERT(nread == 0 || nread == UV_EOF); + free(buf->base); +} + + static int run_ipc_test(const char* helper, uv_read_cb read_cb) { uv_process_t process; int r; @@ -544,6 +564,13 @@ TEST_IMPL(ipc_listen_after_bind_twice) { } #endif +TEST_IMPL(ipc_send_zero) { + int r; + r = run_ipc_test("ipc_helper_send_zero", on_read_send_zero); + ASSERT(r == 0); + return 0; +} + /* Everything here runs in a child process. */ @@ -573,14 +600,25 @@ static void tcp_connection_write_cb(uv_write_t* req, int status) { static void closed_handle_large_write_cb(uv_write_t* req, int status) { ASSERT(status == 0); ASSERT(closed_handle_data_read = LARGE_SIZE); + if (++write_reqs_completed == ARRAY_SIZE(write_reqs)) { + write_reqs_completed = 0; + if (write_until_data_queued() > 0) + send_handle_and_close(); + } } static void closed_handle_write_cb(uv_write_t* req, int status) { ASSERT(status == UV_EBADF); + closed_handle_write = 1; } +static void send_zero_write_cb(uv_write_t* req, int status) { + ASSERT(status == 0); + send_zero_write++; +} + static void on_tcp_child_process_read(uv_stream_t* tcp, ssize_t nread, const uv_buf_t* buf) { @@ -688,7 +726,6 @@ int ipc_helper(int listen_after_write) { * over which a handle will be transmitted. */ struct sockaddr_in addr; - uv_write_t write_req; int r; uv_buf_t buf; @@ -788,26 +825,28 @@ int ipc_helper_tcp_connection(void) { return 0; } - -int ipc_helper_closed_handle(void) { +static unsigned int write_until_data_queued() { + unsigned int i; int r; - struct sockaddr_in addr; - uv_write_t write_req; - uv_write_t write_req2; - uv_buf_t buf; - char buffer[LARGE_SIZE]; - r = uv_pipe_init(uv_default_loop(), &channel, 1); - ASSERT(r == 0); - - uv_pipe_open(&channel, 0); + i = 0; + do { + r = uv_write(&write_reqs[i], + (uv_stream_t*)&channel, + &large_buf, + 1, + closed_handle_large_write_cb); + ASSERT(r == 0); + i++; + } while (((uv_stream_t*)&channel)->write_queue_size == 0 && + i < ARRAY_SIZE(write_reqs)); - ASSERT(1 == uv_is_readable((uv_stream_t*) &channel)); - ASSERT(1 == uv_is_writable((uv_stream_t*) &channel)); - ASSERT(0 == uv_is_closing((uv_handle_t*) &channel)); + return ((uv_stream_t*)&channel)->write_queue_size; +} - memset(buffer, '.', LARGE_SIZE); - buf = uv_buf_init(buffer, LARGE_SIZE); +static void send_handle_and_close() { + int r; + struct sockaddr_in addr; r = uv_tcp_init(uv_default_loop(), &tcp_server); ASSERT(r == 0); @@ -817,26 +856,40 @@ int ipc_helper_closed_handle(void) { r = uv_tcp_bind(&tcp_server, (const struct sockaddr*) &addr, 0); ASSERT(r == 0); - r = uv_write(&write_req, - (uv_stream_t*)&channel, - &buf, - 1, - closed_handle_large_write_cb); - ASSERT(r == 0); - - r = uv_write2(&write_req2, + r = uv_write2(&write_req, (uv_stream_t*)&channel, - &buf, + &large_buf, 1, (uv_stream_t*)&tcp_server, closed_handle_write_cb); ASSERT(r == 0); uv_close((uv_handle_t*)&tcp_server, NULL); +} + +int ipc_helper_closed_handle(void) { + int r; + + memset(buffer, '.', LARGE_SIZE); + large_buf = uv_buf_init(buffer, LARGE_SIZE); + + r = uv_pipe_init(uv_default_loop(), &channel, 1); + ASSERT(r == 0); + + uv_pipe_open(&channel, 0); + + ASSERT(1 == uv_is_readable((uv_stream_t*) &channel)); + ASSERT(1 == uv_is_writable((uv_stream_t*) &channel)); + ASSERT(0 == uv_is_closing((uv_handle_t*) &channel)); + + if (write_until_data_queued() > 0) + send_handle_and_close(); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); ASSERT(r == 0); + ASSERT(closed_handle_write == 1); + MAKE_VALGRIND_HAPPY(); return 0; } @@ -848,8 +901,6 @@ int ipc_helper_bind_twice(void) { * over which two handles will be transmitted. */ struct sockaddr_in addr; - uv_write_t write_req; - uv_write_t write_req2; int r; uv_buf_t buf; @@ -889,3 +940,35 @@ int ipc_helper_bind_twice(void) { MAKE_VALGRIND_HAPPY(); return 0; } + +int ipc_helper_send_zero(void) { + int r; + uv_buf_t zero_buf; + + zero_buf = uv_buf_init(0, 0); + + r = uv_pipe_init(uv_default_loop(), &channel, 0); + ASSERT(r == 0); + + uv_pipe_open(&channel, 0); + + ASSERT(1 == uv_is_readable((uv_stream_t*) &channel)); + ASSERT(1 == uv_is_writable((uv_stream_t*) &channel)); + ASSERT(0 == uv_is_closing((uv_handle_t*) &channel)); + + r = uv_write(&write_req, + (uv_stream_t*)&channel, + &zero_buf, + 1, + send_zero_write_cb); + + ASSERT(r == 0); + + r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); + ASSERT(r == 0); + + ASSERT(send_zero_write == 1); + + MAKE_VALGRIND_HAPPY(); + return 0; +} \ No newline at end of file diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index cc37bc039b15ba..53372c90f769f8 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -69,6 +69,7 @@ TEST_DECLARE (ipc_send_recv_pipe_inprocess) TEST_DECLARE (ipc_send_recv_tcp) TEST_DECLARE (ipc_send_recv_tcp_inprocess) TEST_DECLARE (ipc_tcp_connection) +TEST_DECLARE (ipc_send_zero) #ifndef _WIN32 TEST_DECLARE (ipc_closed_handle) #endif @@ -436,9 +437,13 @@ TEST_DECLARE (fork_socketpair) TEST_DECLARE (fork_socketpair_started) TEST_DECLARE (fork_signal_to_child) TEST_DECLARE (fork_signal_to_child_closed) +#ifndef __APPLE__ /* This is forbidden in a fork child: The process has forked + and you cannot use this CoreFoundation functionality + safely. You MUST exec(). */ TEST_DECLARE (fork_fs_events_child) TEST_DECLARE (fork_fs_events_child_dir) TEST_DECLARE (fork_fs_events_file_parent_child) +#endif #ifndef __MVS__ TEST_DECLARE (fork_threadpool_queue_work_simple) #endif @@ -446,6 +451,7 @@ TEST_DECLARE (fork_threadpool_queue_work_simple) TEST_DECLARE (idna_toascii) TEST_DECLARE (utf8_decode1) +TEST_DECLARE (uname) TASK_LIST_START TEST_ENTRY_CUSTOM (platform_output, 0, 1, 5000) @@ -510,6 +516,7 @@ TASK_LIST_START TEST_ENTRY (ipc_send_recv_tcp) TEST_ENTRY (ipc_send_recv_tcp_inprocess) TEST_ENTRY (ipc_tcp_connection) + TEST_ENTRY (ipc_send_zero) #ifndef _WIN32 TEST_ENTRY (ipc_closed_handle) #endif @@ -945,15 +952,18 @@ TASK_LIST_START TEST_ENTRY (fork_socketpair_started) TEST_ENTRY (fork_signal_to_child) TEST_ENTRY (fork_signal_to_child_closed) +#ifndef __APPLE__ TEST_ENTRY (fork_fs_events_child) TEST_ENTRY (fork_fs_events_child_dir) TEST_ENTRY (fork_fs_events_file_parent_child) +#endif #ifndef __MVS__ TEST_ENTRY (fork_threadpool_queue_work_simple) #endif #endif TEST_ENTRY (utf8_decode1) + TEST_ENTRY (uname) /* Doesn't work on z/OS because that platform uses EBCDIC, not ASCII. */ #ifndef __MVS__ diff --git a/deps/uv/test/test-platform-output.c b/deps/uv/test/test-platform-output.c index 43ed119debfe69..e651e5c582956e 100644 --- a/deps/uv/test/test-platform-output.c +++ b/deps/uv/test/test-platform-output.c @@ -35,6 +35,7 @@ TEST_IMPL(platform_output) { uv_cpu_info_t* cpus; uv_interface_address_t* interfaces; uv_passwd_t pwd; + uv_utsname_t uname; int count; int i; int err; @@ -153,5 +154,13 @@ TEST_IMPL(platform_output) { ASSERT(ppid > 0); printf("uv_os_getppid: %d\n", (int) ppid); + err = uv_os_uname(&uname); + ASSERT(err == 0); + printf("uv_os_uname:\n"); + printf(" sysname: %s\n", uname.sysname); + printf(" release: %s\n", uname.release); + printf(" version: %s\n", uname.version); + printf(" machine: %s\n", uname.machine); + return 0; } diff --git a/deps/uv/test/test-uname.c b/deps/uv/test/test-uname.c new file mode 100644 index 00000000000000..105a17fe67771a --- /dev/null +++ b/deps/uv/test/test-uname.c @@ -0,0 +1,69 @@ +/* Copyright libuv project contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" +#include + +#ifndef _WIN32 +# include +#endif + +TEST_IMPL(uname) { +#ifndef _WIN32 + struct utsname buf; +#endif +#ifdef _AIX + char temp[256]; +#endif + uv_utsname_t buffer; + int r; + + /* Verify that NULL is handled properly. */ + r = uv_os_uname(NULL); + ASSERT(r == UV_EINVAL); + + /* Verify the happy path. */ + r = uv_os_uname(&buffer); + ASSERT(r == 0); + +#ifndef _WIN32 + ASSERT(uname(&buf) != -1); + ASSERT(strcmp(buffer.sysname, buf.sysname) == 0); + ASSERT(strcmp(buffer.version, buf.version) == 0); + +# ifdef _AIX + snprintf(temp, sizeof(temp), "%s.%s", buf.version, buf.release); + ASSERT(strcmp(buffer.release, temp) == 0); +# else + ASSERT(strcmp(buffer.release, buf.release) == 0); +# endif /* _AIX */ + +# if defined(_AIX) || defined(__PASE__) + ASSERT(strcmp(buffer.machine, "ppc64") == 0); +# else + ASSERT(strcmp(buffer.machine, buf.machine) == 0); +# endif /* defined(_AIX) || defined(__PASE__) */ + +#endif /* _WIN32 */ + + return 0; +} diff --git a/deps/uv/test/test.gyp b/deps/uv/test/test.gyp index ae7dc0d628f6e4..604925861e525a 100644 --- a/deps/uv/test/test.gyp +++ b/deps/uv/test/test.gyp @@ -154,6 +154,7 @@ 'test-udp-multicast-interface.c', 'test-udp-multicast-interface6.c', 'test-udp-try-send.c', + 'test-uname.c', ], 'conditions': [ [ 'OS=="win"', {