From b78a7043699093c46d5d71992184f4c40ab5c4b5 Mon Sep 17 00:00:00 2001 From: Saúl Ibarra Corretgé Date: Tue, 17 May 2016 00:25:23 +0200 Subject: deps: upgrade libuv to 1.9.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-By: James M Snell Reviewed-By: Johan Bergström Reviewed-By: Myles Borins --- deps/uv/AUTHORS | 4 + deps/uv/ChangeLog | 89 ++++++++++++++ deps/uv/Makefile.am | 13 ++- deps/uv/Makefile.mingw | 1 + deps/uv/README.md | 5 + deps/uv/android-configure | 4 +- deps/uv/appveyor.yml | 2 +- deps/uv/common.gypi | 7 -- deps/uv/configure.ac | 5 +- deps/uv/docs/src/poll.rst | 6 + deps/uv/include/pthread-barrier.h | 64 ++++++++++ deps/uv/include/uv-unix.h | 21 +--- deps/uv/include/uv-version.h | 2 +- deps/uv/include/uv-win.h | 3 +- deps/uv/src/unix/aix.c | 82 ++++++------- deps/uv/src/unix/async.c | 4 +- deps/uv/src/unix/core.c | 10 +- deps/uv/src/unix/freebsd.c | 8 +- deps/uv/src/unix/fs.c | 15 ++- deps/uv/src/unix/internal.h | 58 +++------- deps/uv/src/unix/kqueue.c | 38 ++++-- deps/uv/src/unix/linux-core.c | 69 +++++++---- deps/uv/src/unix/linux-inotify.c | 2 +- deps/uv/src/unix/linux-syscalls.h | 8 -- deps/uv/src/unix/openbsd.c | 4 +- deps/uv/src/unix/pipe.c | 4 +- deps/uv/src/unix/poll.c | 14 +-- deps/uv/src/unix/pthread-barrier.c | 120 +++++++++++++++++++ deps/uv/src/unix/pthread-fixes.c | 70 ++--------- deps/uv/src/unix/signal.c | 2 +- deps/uv/src/unix/stream.c | 70 +++++------ deps/uv/src/unix/sunos.c | 20 +++- deps/uv/src/unix/tcp.c | 4 +- deps/uv/src/unix/thread.c | 109 ++++++----------- deps/uv/src/unix/udp.c | 20 ++-- deps/uv/src/uv-common.c | 29 ++++- deps/uv/src/win/fs-event.c | 61 +++------- deps/uv/src/win/fs.c | 18 ++- deps/uv/src/win/internal.h | 3 +- deps/uv/src/win/tty.c | 174 +++++++++++++++++++++------- deps/uv/src/win/util.c | 108 +++++++---------- deps/uv/test/test-emfile.c | 7 ++ deps/uv/test/test-fs-event.c | 11 +- deps/uv/test/test-fs.c | 4 + deps/uv/test/test-get-passwd.c | 10 +- deps/uv/test/test-homedir.c | 14 ++- deps/uv/test/test-list.h | 6 + deps/uv/test/test-platform-output.c | 5 + deps/uv/test/test-poll.c | 11 +- deps/uv/test/test-tcp-create-socket-early.c | 3 + deps/uv/test/test-tcp-write-queue-order.c | 2 + deps/uv/test/test-tty.c | 69 +++++++++++ deps/uv/test/test-udp-create-socket-early.c | 3 + deps/uv/uv.gyp | 7 +- deps/uv/vcbuild.bat | 10 +- 55 files changed, 962 insertions(+), 550 deletions(-) create mode 100644 deps/uv/include/pthread-barrier.h create mode 100644 deps/uv/src/unix/pthread-barrier.c (limited to 'deps/uv') diff --git a/deps/uv/AUTHORS b/deps/uv/AUTHORS index 9a9e9c2a22..7acee7c533 100644 --- a/deps/uv/AUTHORS +++ b/deps/uv/AUTHORS @@ -253,3 +253,7 @@ Robert Chiras Kári Tristan Helgason Krishnaraj Bhat Enno Boland +Michael Fero +Robert Jefe Lindstaedt +Myles Borins +Tony Theodore diff --git a/deps/uv/ChangeLog b/deps/uv/ChangeLog index 85d40113e4..3f376de6ba 100644 --- a/deps/uv/ChangeLog +++ b/deps/uv/ChangeLog @@ -1,3 +1,92 @@ +2016.05.17, Version 1.9.1 (Stable), d989902ac658b4323a4f4020446e6f4dc449e25c + +Changes since version 1.9.0: + +* test: handle root home directories (cjihrig) + +* unix: implement uv__fs_futime for AIX 7.1 (Imran Iqbal) + +* test: skip early bind tests if no IPv6 is supported (Saúl Ibarra Corretgé) + +* win: fix var declaration to be C89 compliant (Michael Fero) + +* unix: use POLL{IN,OUT,etc} constants directly (Ben Noordhuis) + +* doc: add ability to live reload and regenerate HTML (Saúl Ibarra Corretgé) + +* Revert "win,build: remove unused build defines" (cjihrig) + +* linux: fix fd leaks in uv_cpu_info() error paths (Ben Noordhuis) + +* linux: don't abort on malformed /proc/stat (Ben Noordhuis) + +* linux: fix long lines in linux-core.c (Ben Noordhuis) + +* test: fix fs_event_watch_file_current_dir for AIX (Imran Iqbal) + +* unix,fs: code cleanup of uv_fs_event_start for AIX (Imran Iqbal) + +* unix: delay signal handling until after normal i/o (Ben Noordhuis) + +* android: pthread_sigmask() does not set errno (Oguz Bastemur) + +* win: work around sharepoint scandir bug (Ben Noordhuis) + +* unix: guard against clobbering errno in uv__free() (Ben Noordhuis) + +* unix: remove unneeded SAVE_ERRNO wrappers (Ben Noordhuis) + +* test: skip fs_event_close_in_callback on AIX (Imran Iqbal) + +* win: add maxrss, pagefaults to uv_getrusage() (Robert Jefe Lindstaedt) + +* test: set a big send buffer size for tcp_write_queue_order (Andrius Bentkus) + +* unix: error on realpath if PATH_MAX is undefined (Myles Borins) + +* unix: fix bug in barrier fallback implementation (Kári Tristan Helgason) + +* build: bump android ndk version (Kári Tristan Helgason) + +* build: always compile with -fvisibility=hidden (Ben Noordhuis) + +* test: fix -Wformat warnings in platform test (Ben Noordhuis) + +* win: clarify fsevents handling code (Saúl Ibarra Corretgé) + +* test: fix POLLHDRUP related failures for AIX (Imran Iqbal) + +* build, mingw: set LIBS in configure.ac (Tony Theodore) + +* win: improve uv__convert_utf16_to_utf8 (Saúl Ibarra Corretgé) + +* win: simplified UTF16 -> UTF8 conversions (Saúl Ibarra Corretgé) + +* win: remove unneeded condition (Saúl Ibarra Corretgé) + +* darwin: work around condition variable kernel bug (Ben Noordhuis) + +* darwin: make thread stack multiple of page size (Ben Noordhuis) + +* build,win: rename platform to msbuild_platform (João Reis) + +* gitignore: ignore VS temporary database files (João Reis) + +* test: skip emfile on AIX (Imran Iqbal) + +* unix: use system allocator for scandir() (cjihrig) + +* common: release uv_fs_scandir() array (cjihrig) + +* win: call uv__fs_scandir_cleanup() (cjihrig) + +* win,tty: fix read stop in line mode (João Reis) + +* win,tty: don't duplicate handle for line reads (João Reis) + +* win,tty: restore cursor after canceling line read (Alexis Campailla) + + 2016.04.08, Version 1.9.0 (Stable), 229b3a4cc150aebd6561e6bd43076eafa7a03756 Changes since version 1.8.0: diff --git a/deps/uv/Makefile.am b/deps/uv/Makefile.am index dfd4353a31..05ccd58ac9 100644 --- a/deps/uv/Makefile.am +++ b/deps/uv/Makefile.am @@ -43,8 +43,8 @@ if WINNT include_HEADERS += include/uv-win.h include/tree.h AM_CPPFLAGS += -I$(top_srcdir)/src/win \ + -DWIN32_LEAN_AND_MEAN \ -D_WIN32_WINNT=0x0600 -LIBS += -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv libuv_la_SOURCES += src/win/async.c \ src/win/atomicops-inl.h \ src/win/core.c \ @@ -290,20 +290,23 @@ endif if ANDROID include_HEADERS += include/android-ifaddrs.h \ - include/pthread-fixes.h + include/pthread-barrier.h libuv_la_SOURCES += src/unix/android-ifaddrs.c \ - src/unix/pthread-fixes.c + src/unix/pthread-fixes.c \ + src/unix/pthread-barrier.c endif if DARWIN -include_HEADERS += include/uv-darwin.h +include_HEADERS += include/uv-darwin.h \ + include/pthread-barrier.h libuv_la_CFLAGS += -D_DARWIN_USE_64_BIT_INODE=1 libuv_la_CFLAGS += -D_DARWIN_UNLIMITED_SELECT=1 libuv_la_SOURCES += src/unix/darwin.c \ src/unix/darwin-proctitle.c \ src/unix/fsevents.c \ src/unix/kqueue.c \ - src/unix/proctitle.c + src/unix/proctitle.c \ + src/unix/pthread-barrier.c test_run_tests_LDFLAGS += -lutil endif diff --git a/deps/uv/Makefile.mingw b/deps/uv/Makefile.mingw index 3130bac473..156f15dab1 100644 --- a/deps/uv/Makefile.mingw +++ b/deps/uv/Makefile.mingw @@ -20,6 +20,7 @@ CFLAGS += -Wall \ -Iinclude \ -Isrc \ -Isrc/win \ + -DWIN32_LEAN_AND_MEAN \ -D_WIN32_WINNT=0x0600 INCLUDES = include/stdint-msvc2008.h \ diff --git a/deps/uv/README.md b/deps/uv/README.md index 17304a7ab5..e94fcc902f 100644 --- a/deps/uv/README.md +++ b/deps/uv/README.md @@ -60,6 +60,11 @@ Build documentation as HTML: $ make html +Build documentation as HTML and live reload it when it changes (this requires +sphinx-autobuild to be installed and is only supported on Unix): + + $ make livehtml + Build documentation as man pages: $ make man diff --git a/deps/uv/android-configure b/deps/uv/android-configure index e0b250fb63..7ffc035c1b 100755 --- a/deps/uv/android-configure +++ b/deps/uv/android-configure @@ -3,7 +3,7 @@ export TOOLCHAIN=$PWD/android-toolchain mkdir -p $TOOLCHAIN $1/build/tools/make-standalone-toolchain.sh \ - --toolchain=arm-linux-androideabi-4.8 \ + --toolchain=arm-linux-androideabi-4.9 \ --arch=arm \ --install-dir=$TOOLCHAIN \ --platform=android-21 @@ -14,7 +14,7 @@ export CXX=arm-linux-androideabi-g++ export LINK=arm-linux-androideabi-g++ export PLATFORM=android -if [ $2 -a $2 == 'gyp' ] +if [[ $2 == 'gyp' ]] then ./gyp_uv.py -Dtarget_arch=arm -DOS=android -f make-android fi diff --git a/deps/uv/appveyor.yml b/deps/uv/appveyor.yml index 835730b924..c7ea736502 100644 --- a/deps/uv/appveyor.yml +++ b/deps/uv/appveyor.yml @@ -1,4 +1,4 @@ -version: v1.9.0.build{build} +version: v1.9.1.build{build} install: - cinst -y nsis diff --git a/deps/uv/common.gypi b/deps/uv/common.gypi index 7cebcde5f8..56bca2948d 100644 --- a/deps/uv/common.gypi +++ b/deps/uv/common.gypi @@ -1,6 +1,5 @@ { 'variables': { - 'visibility%': 'hidden', # V8's visibility setting 'target_arch%': 'ia32', # set v8's target architecture 'host_arch%': 'ia32', # set v8's host architecture 'uv_library%': 'static_library', # allow override to 'shared_library' for DLL/.so builds @@ -156,9 +155,6 @@ 'cflags': [ '-pthread' ], 'ldflags': [ '-pthread' ], }], - [ 'visibility=="hidden"', { - 'cflags': [ '-fvisibility=hidden' ], - }], ], }], ['OS=="mac"', { @@ -170,9 +166,6 @@ 'GCC_ENABLE_CPP_EXCEPTIONS': 'NO', # -fno-exceptions 'GCC_ENABLE_CPP_RTTI': 'NO', # -fno-rtti 'GCC_ENABLE_PASCAL_STRINGS': 'NO', # No -mpascal-strings - # GCC_INLINES_ARE_PRIVATE_EXTERN maps to -fvisibility-inlines-hidden - 'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES', - 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden 'GCC_THREADSAFE_STATICS': 'NO', # -fno-threadsafe-statics 'PREBINDING': 'NO', # No -Wl,-prebind 'USE_HEADERMAP': 'NO', diff --git a/deps/uv/configure.ac b/deps/uv/configure.ac index 2d5a3b9de5..d9251f3198 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.9.0], [https://github.com/libuv/libuv/issues]) +AC_INIT([libuv], [1.9.1], [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]) @@ -58,6 +58,9 @@ AM_CONDITIONAL([NETBSD], [AS_CASE([$host_os],[netbsd*], [true], [false]) AM_CONDITIONAL([OPENBSD], [AS_CASE([$host_os],[openbsd*], [true], [false])]) AM_CONDITIONAL([SUNOS], [AS_CASE([$host_os],[solaris*], [true], [false])]) AM_CONDITIONAL([WINNT], [AS_CASE([$host_os],[mingw*], [true], [false])]) +AS_CASE([$host_os],[mingw*], [ + LIBS="$LIBS -lws2_32 -lpsapi -liphlpapi -lshell32 -luserenv -luser32" +]) AC_CHECK_HEADERS([sys/ahafs_evProds.h]) AC_CHECK_PROG(PKG_CONFIG, pkg-config, yes) AM_CONDITIONAL([HAVE_PKG_CONFIG], [test "x$PKG_CONFIG" != "x"]) diff --git a/deps/uv/docs/src/poll.rst b/deps/uv/docs/src/poll.rst index 69d45be6d3..004ff4b92e 100644 --- a/deps/uv/docs/src/poll.rst +++ b/deps/uv/docs/src/poll.rst @@ -31,6 +31,8 @@ closed immediately after a call to :c:func:`uv_poll_stop` or :c:func:`uv_close`. On windows only sockets can be polled with poll handles. On Unix any file descriptor that would be accepted by :man:`poll(2)` can be used. +.. note:: + On AIX, watching for disconnection is not supported. Data types ---------- @@ -101,6 +103,10 @@ API Calling :c:func:`uv_poll_start` on a handle that is already active is fine. Doing so will update the events mask that is being watched for. + .. note:: + Though UV_DISCONNECT can be set, it is unsupported on AIX and as such will not be set + on the `events` field in the callback. + .. versionchanged:: 1.9.0 Added the UV_DISCONNECT event. .. c:function:: int uv_poll_stop(uv_poll_t* poll) diff --git a/deps/uv/include/pthread-barrier.h b/deps/uv/include/pthread-barrier.h new file mode 100644 index 0000000000..084e1c2d55 --- /dev/null +++ b/deps/uv/include/pthread-barrier.h @@ -0,0 +1,64 @@ +/* +Copyright (c) 2016, Kari Tristan Helgason + +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. +*/ + +#ifndef _UV_PTHREAD_BARRIER_ +#define _UV_PTHREAD_BARRIER_ +#include +#include +#include /* sem_t */ + +#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345 + +/* + * To maintain ABI compatibility with + * libuv v1.x struct is padded according + * to target platform + */ +#if defined(__ANDROID__) +# define UV_BARRIER_STRUCT_PADDING \ + sizeof(pthread_mutex_t) + \ + sizeof(pthread_cond_t) + \ + sizeof(unsigned int) - \ + sizeof(void *) +#elif defined(__APPLE__) +# define UV_BARRIER_STRUCT_PADDING \ + sizeof(pthread_mutex_t) + \ + 2 * sizeof(sem_t) + \ + 2 * sizeof(unsigned int) - \ + sizeof(void *) +#endif + +typedef struct { + pthread_mutex_t mutex; + pthread_cond_t cond; + unsigned threshold; + unsigned in; + unsigned out; +} _uv_barrier; + +typedef struct { + _uv_barrier* b; + char _pad[UV_BARRIER_STRUCT_PADDING]; +} pthread_barrier_t; + +int pthread_barrier_init(pthread_barrier_t* barrier, + const void* barrier_attr, + unsigned count); + +int pthread_barrier_wait(pthread_barrier_t* barrier); +int pthread_barrier_destroy(pthread_barrier_t *barrier); + +#endif /* _UV_PTHREAD_BARRIER_ */ diff --git a/deps/uv/include/uv-unix.h b/deps/uv/include/uv-unix.h index 82d193bdca..a852c40e49 100644 --- a/deps/uv/include/uv-unix.h +++ b/deps/uv/include/uv-unix.h @@ -38,9 +38,6 @@ #include #include -#ifdef __ANDROID__ -#include "pthread-fixes.h" -#endif #include #include "uv-threadpool.h" @@ -60,6 +57,10 @@ # include "uv-bsd.h" #endif +#ifndef PTHREAD_BARRIER_SERIAL_THREAD +# include "pthread-barrier.h" +#endif + #ifndef NI_MAXHOST # define NI_MAXHOST 1025 #endif @@ -136,22 +137,8 @@ typedef pthread_rwlock_t uv_rwlock_t; typedef UV_PLATFORM_SEM_T uv_sem_t; typedef pthread_cond_t uv_cond_t; typedef pthread_key_t uv_key_t; - -#if defined(__APPLE__) && defined(__MACH__) - -typedef struct { - unsigned int n; - unsigned int count; - uv_mutex_t mutex; - uv_sem_t turnstile1; - uv_sem_t turnstile2; -} uv_barrier_t; - -#else /* defined(__APPLE__) && defined(__MACH__) */ - typedef pthread_barrier_t uv_barrier_t; -#endif /* defined(__APPLE__) && defined(__MACH__) */ /* Platform-specific definitions for uv_spawn support. */ typedef gid_t uv_gid_t; diff --git a/deps/uv/include/uv-version.h b/deps/uv/include/uv-version.h index cb66618289..08ad0edaa7 100644 --- a/deps/uv/include/uv-version.h +++ b/deps/uv/include/uv-version.h @@ -32,7 +32,7 @@ #define UV_VERSION_MAJOR 1 #define UV_VERSION_MINOR 9 -#define UV_VERSION_PATCH 0 +#define UV_VERSION_PATCH 1 #define UV_VERSION_IS_RELEASE 1 #define UV_VERSION_SUFFIX "" diff --git a/deps/uv/include/uv-win.h b/deps/uv/include/uv-win.h index 6b537fed0d..a75dba8d1c 100644 --- a/deps/uv/include/uv-win.h +++ b/deps/uv/include/uv-win.h @@ -483,7 +483,8 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); union { \ struct { \ /* Used for readable TTY handles */ \ - HANDLE read_line_handle; \ + /* TODO: remove me in v2.x. */ \ + HANDLE unused_; \ uv_buf_t read_line_buffer; \ HANDLE read_raw_wait; \ /* Fields used for translating win keystrokes into vt100 characters */ \ 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 #include #include +#include /* PATH_MAX */ #include #include @@ -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 +# define reqevents events +# define rtnevents revents +# include +#else +# include #endif /* _AIX */ #if defined(__APPLE__) && !TARGET_OS_IPHONE # include #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 . + */ + #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 + +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 +#include + +/* 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 #include #include 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 #include /* getrlimit() */ +#include /* getpagesize() */ #include #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 #include +#include #include #include /* NULL */ +#include #include /* malloc */ #include /* 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); diff --git a/deps/uv/test/test-emfile.c b/deps/uv/test/test-emfile.c index dd35f785b4..5f4dd9efdf 100644 --- a/deps/uv/test/test-emfile.c +++ b/deps/uv/test/test-emfile.c @@ -38,6 +38,13 @@ static uv_tcp_t client_handle; TEST_IMPL(emfile) { +#ifdef _AIX + /* On AIX, if a 'accept' call fails ECONNRESET is set on the socket + * which causes uv__emfile_trick to not work as intended and this test + * to fail. + */ + RETURN_SKIP("uv__emfile_trick does not work on AIX"); +#endif struct sockaddr_in addr; struct rlimit limits; uv_connect_t connect_req; diff --git a/deps/uv/test/test-fs-event.c b/deps/uv/test/test-fs-event.c index 35583529e5..353c43b0de 100644 --- a/deps/uv/test/test-fs-event.c +++ b/deps/uv/test/test-fs-event.c @@ -511,7 +511,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, 10, 0); + r = uv_timer_start(&timer, timer_cb_touch, 100, 0); ASSERT(r == 0); ASSERT(timer_cb_touch_called == 0); @@ -698,18 +698,19 @@ TEST_IMPL(fs_event_close_with_pending_event) { return 0; } -#if defined(HAVE_KQUEUE) +#if defined(HAVE_KQUEUE) || defined(_AIX) /* kqueue doesn't register fs events if you don't have an active watcher. * The file descriptor needs to be part of the kqueue set of interest and * that's not the case until we actually enter the event loop. + * This is also observed on AIX with ahafs. */ TEST_IMPL(fs_event_close_in_callback) { - fprintf(stderr, "Skipping test, doesn't work with kqueue.\n"); + fprintf(stderr, "Skipping test, doesn't work with kqueue and AIX.\n"); return 0; } -#else /* !HAVE_KQUEUE */ +#else /* !HAVE_KQUEUE || !_AIX */ static void fs_event_cb_close(uv_fs_event_t* handle, const char* filename, int events, int status) { @@ -766,7 +767,7 @@ TEST_IMPL(fs_event_close_in_callback) { return 0; } -#endif /* HAVE_KQUEUE */ +#endif /* HAVE_KQUEUE || _AIX */ TEST_IMPL(fs_event_start_and_close) { uv_loop_t* loop; diff --git a/deps/uv/test/test-fs.c b/deps/uv/test/test-fs.c index cf37ac4909..1cc1a7c064 100644 --- a/deps/uv/test/test-fs.c +++ b/deps/uv/test/test-fs.c @@ -2033,6 +2033,9 @@ TEST_IMPL(fs_stat_root) { TEST_IMPL(fs_futime) { +#if defined(_AIX) && !defined(_AIX71) + RETURN_SKIP("futime is not implemented for AIX versions below 7.1"); +#else utime_check_t checkme; const char* path = "test_file"; double atime; @@ -2087,6 +2090,7 @@ TEST_IMPL(fs_futime) { MAKE_VALGRIND_HAPPY(); return 0; +#endif } diff --git a/deps/uv/test/test-get-passwd.c b/deps/uv/test/test-get-passwd.c index 58d9c73c69..8e16fb83c8 100644 --- a/deps/uv/test/test-get-passwd.c +++ b/deps/uv/test/test-get-passwd.c @@ -45,9 +45,15 @@ TEST_IMPL(get_passwd) { ASSERT(len > 0); #ifdef _WIN32 - ASSERT(pwd.homedir[len - 1] != '\\'); + if (len == 3 && pwd.homedir[1] == ':') + ASSERT(pwd.homedir[2] == '\\'); + else + ASSERT(pwd.homedir[len - 1] != '\\'); #else - ASSERT(pwd.homedir[len - 1] != '/'); + if (len == 1) + ASSERT(pwd.homedir[0] == '/'); + else + ASSERT(pwd.homedir[len - 1] != '/'); #endif #ifdef _WIN32 diff --git a/deps/uv/test/test-homedir.c b/deps/uv/test/test-homedir.c index 5027d44c1e..856534a40c 100644 --- a/deps/uv/test/test-homedir.c +++ b/deps/uv/test/test-homedir.c @@ -29,7 +29,6 @@ TEST_IMPL(homedir) { char homedir[PATHMAX]; size_t len; - char last; int r; /* Test the normal case */ @@ -42,14 +41,17 @@ TEST_IMPL(homedir) { ASSERT(len > 0); ASSERT(homedir[len] == '\0'); - if (len > 1) { - last = homedir[len - 1]; #ifdef _WIN32 - ASSERT(last != '\\'); + if (len == 3 && homedir[1] == ':') + ASSERT(homedir[2] == '\\'); + else + ASSERT(homedir[len - 1] != '\\'); #else - ASSERT(last != '/'); + if (len == 1) + ASSERT(homedir[0] == '/'); + else + ASSERT(homedir[len - 1] != '/'); #endif - } /* Test the case where the buffer is too small */ len = SMALLPATH; diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 8b10f1a5f6..c93f081992 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -43,6 +43,9 @@ TEST_DECLARE (semaphore_1) TEST_DECLARE (semaphore_2) TEST_DECLARE (semaphore_3) TEST_DECLARE (tty) +#ifdef _WIN32 +TEST_DECLARE (tty_raw) +#endif TEST_DECLARE (tty_file) TEST_DECLARE (tty_pty) TEST_DECLARE (stdio_over_pipes) @@ -387,6 +390,9 @@ TASK_LIST_START #endif TEST_ENTRY (pipe_set_non_blocking) TEST_ENTRY (tty) +#ifdef _WIN32 + TEST_ENTRY (tty_raw) +#endif TEST_ENTRY (tty_file) TEST_ENTRY (tty_pty) TEST_ENTRY (stdio_over_pipes) diff --git a/deps/uv/test/test-platform-output.c b/deps/uv/test/test-platform-output.c index 2c4740550a..bd61454fa7 100644 --- a/deps/uv/test/test-platform-output.c +++ b/deps/uv/test/test-platform-output.c @@ -61,6 +61,8 @@ TEST_IMPL(platform_output) { ASSERT(rusage.ru_utime.tv_usec >= 0); ASSERT(rusage.ru_stime.tv_sec >= 0); ASSERT(rusage.ru_stime.tv_usec >= 0); + ASSERT(rusage.ru_majflt >= 0); + ASSERT(rusage.ru_maxrss >= 0); printf("uv_getrusage:\n"); printf(" user: %llu sec %llu microsec\n", (unsigned long long) rusage.ru_utime.tv_sec, @@ -68,6 +70,9 @@ TEST_IMPL(platform_output) { printf(" system: %llu sec %llu microsec\n", (unsigned long long) rusage.ru_stime.tv_sec, (unsigned long long) rusage.ru_stime.tv_usec); + printf(" page faults: %llu\n", (unsigned long long) rusage.ru_majflt); + printf(" maximum resident set size: %llu\n", + (unsigned long long) rusage.ru_maxrss); err = uv_cpu_info(&cpus, &count); ASSERT(err == 0); diff --git a/deps/uv/test/test-poll.c b/deps/uv/test/test-poll.c index bfb75af133..f3cfe79777 100644 --- a/deps/uv/test/test-poll.c +++ b/deps/uv/test/test-poll.c @@ -72,8 +72,9 @@ static int closed_connections = 0; static int valid_writable_wakeups = 0; static int spurious_writable_wakeups = 0; +#ifndef _AIX static int disconnects = 0; - +#endif /* !_AIX */ static int got_eagain(void) { #ifdef _WIN32 @@ -377,7 +378,7 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { new_events &= ~UV_WRITABLE; } } - +#ifndef _AIX if (events & UV_DISCONNECT) { context->got_disconnect = 1; ++disconnects; @@ -385,6 +386,9 @@ static void connection_poll_cb(uv_poll_t* handle, int status, int events) { } if (context->got_fin && context->sent_fin && context->got_disconnect) { +#else /* _AIX */ + if (context->got_fin && context->sent_fin) { +#endif /* !_AIx */ /* Sent and received FIN. Close and destroy context. */ close_socket(context->sock); destroy_connection_context(context); @@ -552,8 +556,9 @@ static void start_poll_test(void) { spurious_writable_wakeups > 20); ASSERT(closed_connections == NUM_CLIENTS * 2); +#ifndef _AIX ASSERT(disconnects == NUM_CLIENTS * 2); - +#endif MAKE_VALGRIND_HAPPY(); } diff --git a/deps/uv/test/test-tcp-create-socket-early.c b/deps/uv/test/test-tcp-create-socket-early.c index 65650adcc2..1a508e474a 100644 --- a/deps/uv/test/test-tcp-create-socket-early.c +++ b/deps/uv/test/test-tcp-create-socket-early.c @@ -139,6 +139,9 @@ TEST_IMPL(tcp_create_early_bad_bind) { uv_os_fd_t fd; int r; + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_tcp_init_ex(uv_default_loop(), &client, AF_INET6); diff --git a/deps/uv/test/test-tcp-write-queue-order.c b/deps/uv/test/test-tcp-write-queue-order.c index aa4d2acc24..8a98ab8366 100644 --- a/deps/uv/test/test-tcp-write-queue-order.c +++ b/deps/uv/test/test-tcp-write-queue-order.c @@ -107,6 +107,7 @@ static void start_server(void) { TEST_IMPL(tcp_write_queue_order) { uv_connect_t connect_req; struct sockaddr_in addr; + int buffer_size = 16 * 1024; start_server(); @@ -117,6 +118,7 @@ TEST_IMPL(tcp_write_queue_order) { &client, (struct sockaddr*) &addr, connect_cb)); + ASSERT(0 == uv_send_buffer_size((uv_handle_t*) &client, &buffer_size)); ASSERT(0 == uv_timer_init(uv_default_loop(), &timer)); ASSERT(0 == uv_timer_start(&timer, timer_cb, 100, 0)); diff --git a/deps/uv/test/test-tty.c b/deps/uv/test/test-tty.c index 461d194135..55cc016752 100644 --- a/deps/uv/test/test-tty.c +++ b/deps/uv/test/test-tty.c @@ -146,6 +146,75 @@ TEST_IMPL(tty) { } +#ifdef _WIN32 +static void tty_raw_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + buf->base = malloc(size); + buf->len = size; +} + +static void tty_raw_read(uv_stream_t* tty_in, ssize_t nread, const uv_buf_t* buf) { + if (nread > 0) { + ASSERT(nread == 1); + ASSERT(buf->base[0] == ' '); + uv_close((uv_handle_t*) tty_in, NULL); + } else { + ASSERT(nread == 0); + } +} + +TEST_IMPL(tty_raw) { + int r; + int ttyin_fd; + uv_tty_t tty_in; + uv_loop_t* loop = uv_default_loop(); + HANDLE handle; + INPUT_RECORD record; + DWORD written; + + /* Make sure we have an FD that refers to a tty */ + handle = CreateFileA("conin$", + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + ASSERT(handle != INVALID_HANDLE_VALUE); + ttyin_fd = _open_osfhandle((intptr_t) handle, 0); + ASSERT(ttyin_fd >= 0); + ASSERT(UV_TTY == uv_guess_handle(ttyin_fd)); + + r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ + ASSERT(r == 0); + + r = uv_read_start((uv_stream_t*)&tty_in, tty_raw_alloc, tty_raw_read); + ASSERT(r == 0); + + /* Give uv_tty_line_read_thread time to block on ReadConsoleW */ + Sleep(100); + + /* Turn on raw mode. */ + r = uv_tty_set_mode(&tty_in, UV_TTY_MODE_RAW); + ASSERT(r == 0); + + /* Write ' ' that should be read in raw mode */ + record.EventType = KEY_EVENT; + record.Event.KeyEvent.bKeyDown = TRUE; + record.Event.KeyEvent.wRepeatCount = 1; + record.Event.KeyEvent.wVirtualKeyCode = VK_SPACE; + record.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW(VK_SPACE, MAPVK_VK_TO_VSC); + record.Event.KeyEvent.uChar.UnicodeChar = L' '; + record.Event.KeyEvent.dwControlKeyState = 0; + WriteConsoleInputW(handle, &record, 1, &written); + + uv_run(loop, UV_RUN_DEFAULT); + + MAKE_VALGRIND_HAPPY(); + return 0; +} +#endif + + TEST_IMPL(tty_file) { #ifndef _WIN32 uv_loop_t loop; diff --git a/deps/uv/test/test-udp-create-socket-early.c b/deps/uv/test/test-udp-create-socket-early.c index 3d0152428b..3f30274047 100644 --- a/deps/uv/test/test-udp-create-socket-early.c +++ b/deps/uv/test/test-udp-create-socket-early.c @@ -79,6 +79,9 @@ TEST_IMPL(udp_create_early_bad_bind) { uv_os_fd_t fd; int r; + if (!can_ipv6()) + RETURN_SKIP("IPv6 not supported"); + ASSERT(0 == uv_ip4_addr("127.0.0.1", TEST_PORT, &addr)); r = uv_udp_init_ex(uv_default_loop(), &client, AF_INET6); diff --git a/deps/uv/uv.gyp b/deps/uv/uv.gyp index 757540193d..2fdd59ac78 100644 --- a/deps/uv/uv.gyp +++ b/deps/uv/uv.gyp @@ -17,6 +17,7 @@ }], ], 'xcode_settings': { + 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden 'WARNING_CFLAGS': [ '-Wall', '-Wextra', '-Wno-unused-parameter' ], 'OTHER_CFLAGS': [ '-g', '--std=gnu89', '-pedantic' ], } @@ -111,12 +112,14 @@ '-liphlpapi', '-lpsapi', '-lshell32', + '-luser32', '-luserenv', '-lws2_32' ], }, }, { # Not Windows i.e. POSIX 'cflags': [ + '-fvisibility=hidden', '-g', '--std=gnu89', '-pedantic', @@ -184,6 +187,7 @@ 'src/unix/darwin.c', 'src/unix/fsevents.c', 'src/unix/darwin-proctitle.c', + 'src/unix/pthread-barrier.c' ], 'defines': [ '_DARWIN_USE_64_BIT_INODE=1', @@ -214,7 +218,8 @@ 'src/unix/linux-syscalls.c', 'src/unix/linux-syscalls.h', 'src/unix/pthread-fixes.c', - 'src/unix/android-ifaddrs.c' + 'src/unix/android-ifaddrs.c', + 'src/unix/pthread-barrier.c' ], 'link_settings': { 'libraries': [ '-ldl' ], diff --git a/deps/uv/vcbuild.bat b/deps/uv/vcbuild.bat index 9a7ed4b8c5..91f45b7219 100644 --- a/deps/uv/vcbuild.bat +++ b/deps/uv/vcbuild.bat @@ -19,7 +19,7 @@ set nobuild= set run= set target_arch=ia32 set vs_toolset=x86 -set platform=WIN32 +set msbuild_platform=WIN32 set library=static_library :next-arg @@ -31,9 +31,9 @@ if /i "%1"=="bench" set run=run-benchmarks.exe&goto arg-ok if /i "%1"=="clean" set target=Clean&goto arg-ok if /i "%1"=="noprojgen" set noprojgen=1&goto arg-ok if /i "%1"=="nobuild" set nobuild=1&goto arg-ok -if /i "%1"=="x86" set target_arch=ia32&set platform=WIN32&set vs_toolset=x86&goto arg-ok -if /i "%1"=="ia32" set target_arch=ia32&set platform=WIN32&set vs_toolset=x86&goto arg-ok -if /i "%1"=="x64" set target_arch=x64&set platform=x64&set vs_toolset=x64&goto arg-ok +if /i "%1"=="x86" set target_arch=ia32&set msbuild_platform=WIN32&set vs_toolset=x86&goto arg-ok +if /i "%1"=="ia32" set target_arch=ia32&set msbuild_platform=WIN32&set vs_toolset=x86&goto arg-ok +if /i "%1"=="x64" set target_arch=x64&set msbuild_platform=x64&set vs_toolset=x64&goto arg-ok if /i "%1"=="shared" set library=shared_library&goto arg-ok if /i "%1"=="static" set library=static_library&goto arg-ok :arg-ok @@ -132,7 +132,7 @@ goto run @rem Build the sln with msbuild. :msbuild-found -msbuild uv.sln /t:%target% /p:Configuration=%config% /p:Platform="%platform%" /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo +msbuild uv.sln /t:%target% /p:Configuration=%config% /p:Platform="%msbuild_platform%" /clp:NoSummary;NoItemAndPropertyList;Verbosity=minimal /nologo if errorlevel 1 exit /b 1 :run -- cgit v1.2.3