diff --git a/src/libuv/.gitignore b/src/libuv/.gitignore index d6c65dba..3f4c5193 100644 --- a/src/libuv/.gitignore +++ b/src/libuv/.gitignore @@ -12,6 +12,9 @@ vgcore.* /libuv.so /libuv.dylib +# Generated by dtrace(1) when doing an in-tree build. +/src/unix/uv-dtrace.h + /out/ /build/gyp diff --git a/src/libuv/.mailmap b/src/libuv/.mailmap index 2d98623b..5dc4075e 100644 --- a/src/libuv/.mailmap +++ b/src/libuv/.mailmap @@ -1,13 +1,17 @@ -# update AUTHORS with: -# git log --all --reverse --format='%aN <%aE>' | perl -ne 'BEGIN{print "# Authors ordered by first contribution.\n"} print unless $h{$_}; $h{$_} = 1' > AUTHORS - - - - -San-Tai Hsu -Isaac Z. Schlueter -Saúl Ibarra Corretgé -Yuki OKUMURA +Alan Gutierrez +Bert Belder +Bert Belder +Brandon Philips +Brian White +Brian White Frank Denis +Isaac Z. Schlueter +Robert Mustacchi +Ryan Dahl Ryan Emery +San-Tai Hsu +Saúl Ibarra Corretgé +Shigeki Ohtsu +Timothy J. Fontaine Yasuhiro Matsumoto +Yuki Okumura diff --git a/src/libuv/AUTHORS b/src/libuv/AUTHORS index d28143bb..119773a5 100644 --- a/src/libuv/AUTHORS +++ b/src/libuv/AUTHORS @@ -28,7 +28,7 @@ Marek Jelen Fedor Indutny Saúl Ibarra Corretgé Felix Geisendörfer -Yuki OKUMURA +Yuki Okumura Roman Shtylman Frank Denis Carter Allen @@ -44,7 +44,6 @@ Dan VerWeire Brandon Benvie Brandon Philips Nathan Rajlich -Brandon Philips Charlie McConnell Vladimir Dronnikov Aaron Bieber @@ -54,8 +53,35 @@ Erik Dubbelboer Keno Fischer Ira Cooper Andrius Bentkus -Brian White Iñaki Baz Castillo Mark Cavage George Yohng Xidorn Quan +Roman Neuhauser +Shuhei Tanuma +Bryan Cantrill +Trond Norbye +Tim Holy +Prancesco Pertugio +Leonard Hecker +Andrew Paprocki +Luigi Grilli +Shannen Saez +Artur Adib +Hiroaki Nakamura +Ting-Yu Lin +Stephen Gallagher +Shane Holloway +Andrew Shaffer +Vlad Tudose +Ben Leslie +Tim Bradshaw +Timothy J. Fontaine +Marc Schlaich +Brian Mazza +Nils Maier +Nicholas Vavilov +Miroslav Bajtoš +Elliot Saba +Wynn Wilkes +Andrei Sedoi diff --git a/src/libuv/ChangeLog b/src/libuv/ChangeLog new file mode 100644 index 00000000..6ffffc77 --- /dev/null +++ b/src/libuv/ChangeLog @@ -0,0 +1,225 @@ +2013.07.26, Version 0.10.13 (Stable) + +Changes since version 0.10.12: + +* unix, windows: fix uv_fs_chown() function prototype (Ben Noordhuis) + + +2013.07.10, Version 0.10.12 (Stable), 58a46221bba726746887a661a9f36fe9ff204209 + +Changes since version 0.10.11: + +* linux: add support for MIPS (Andrei Sedoi) + +* windows: uv_spawn shouldn't reject reparse points (Bert Belder) + +* windows: use WSAGetLastError(), not errno (Ben Noordhuis) + +* build: darwin: disable -fstrict-aliasing warnings (Ben Noordhuis) + +* build: `all` now builds static and dynamic lib (Ben Noordhuis) + +* unix: fix build when !defined(PTHREAD_MUTEX_ERRORCHECK) (Ben Noordhuis) + + +2013.06.13, Version 0.10.11 (Stable), c3b75406a66a10222a589cb173e8f469e9665c7e + +Changes since version 0.10.10: + +* unix: unconditionally stop handle on close (Ben Noordhuis) + +* freebsd: don't enable dtrace if it's not available (Brian White) + +* build: make HAVE_DTRACE=0 should disable dtrace (Timothy J. Fontaine) + +* unix: remove overzealous assert (Ben Noordhuis) + +* unix: clear UV_STREAM_SHUTTING after shutdown() (Ben Noordhuis) + +* unix: fix busy loop, write if POLLERR or POLLHUP (Ben Noordhuis) + + +2013.06.05, Version 0.10.10 (Stable), 0d95a88bd35fce93863c57a460be613aea34d2c5 + +Changes since version 0.10.9: + +* include: document uv_update_time() and uv_now() (Ben Noordhuis) + +* linux: fix cpu model parsing on newer arm kernels (Ben Noordhuis) + +* linux: fix memory leak in uv_cpu_info() error path (Ben Noordhuis) + +* linux: don't ignore OOM errors in uv_cpu_info() (Ben Noordhuis) + +* unix, windows: move uv_now() to uv-common.c (Ben Noordhuis) + +* darwin: make uv_fs_sendfile() respect length param (Wynn Wilkes) + + +2013.05.29, Version 0.10.9 (Stable), a195f9ace23d92345baf57582678bfc3017e6632 + +Changes since version 0.10.8: + +* unix: fix stream refcounting buglet (Ben Noordhuis) + +* unix: remove erroneous asserts (Ben Noordhuis) + +* unix: add uv__is_closing() macro (Ben Noordhuis) + +* unix: stop stream POLLOUT watcher on write error (Ben Noordhuis) + + +2013.05.25, Version 0.10.8 (Stable), 0f39be12926fe2d8766a9f025797a473003e6504 + +Changes since version 0.10.7: + +* windows: make uv_spawn not fail under job control (Bert Belder) + +* darwin: assume CFRunLoopStop() isn't thread-safe (Fedor Indutny) + +* win: fix UV_EALREADY incorrectly set (Bert Belder) + +* darwin: make two uv__cf_*() functions static (Ben Noordhuis) + +* darwin: task_info() cannot fail (Ben Noordhuis) + +* unix: add mapping for ENETDOWN (Ben Noordhuis) + +* unix: implicitly signal write errors to libuv user (Ben Noordhuis) + +* unix: fix assert on signal pipe overflow (Bert Belder) + +* unix: turn off POLLOUT after stream connect (Ben Noordhuis) + + +2013.05.15, Version 0.10.7 (Stable), 028baaf0846b686a81e992cb2f2f5a9b8e841fcf + +Changes since version 0.10.6: + +* windows: kill child processes when the parent dies (Bert Belder) + + +2013.05.15, Version 0.10.6 (Stable), 11e6613e6260d95c8cf11bf89a2759c24649319a + +Changes since version 0.10.5: + +* stream: fix osx select hack (Fedor Indutny) + +* stream: fix small nit in select hack, add test (Fedor Indutny) + +* build: link with libkvm on openbsd (Ben Noordhuis) + +* stream: use harder sync restrictions for osx-hack (Fedor Indutny) + +* unix: fix EMFILE error handling (Ben Noordhuis) + +* darwin: fix unnecessary include headers (Daisuke Murase) + +* darwin: rename darwin-getproctitle.m (Ben Noordhuis) + +* build: convert predefined $PLATFORM to lower case (Elliot Saba) + +* build: set soname in shared library (Ben Noordhuis) + +* build: make `make test` link against .a again (Ben Noordhuis) + +* darwin: fix ios build, don't require ApplicationServices (Ben Noordhuis) + +* build: only set soname on shared object builds (Timothy J. Fontaine) + + +2013.04.24, Version 0.10.5 (Stable), 6595a7732c52eb4f8e57c88655f72997a8567a67 + +Changes since version 0.10.4: + +* unix: silence STATIC_ASSERT compiler warnings (Ben Noordhuis) + +* windows: make timers handle large timeouts (Miroslav Bajtoš) + +* windows: remove superfluous assert statement (Bert Belder) + +* unix: silence STATIC_ASSERT compiler warnings (Ben Noordhuis) + +* linux: don't use fopen() in uv_resident_set_memory() (Ben Noordhuis) + + +2013.04.12, Version 0.10.4 (Stable), 85827e26403ac6dfa331af8ec9916ea7e27bd833 + +Changes since version 0.10.3: + +* include: update uv_backend_fd() documentation (Ben Noordhuis) + +* unix: include uv.h in src/version.c (Ben Noordhuis) + +* unix: don't write more than IOV_MAX iovecs (Fedor Indutny) + +* mingw-w64: don't call _set_invalid_parameter_handler (Nils Maier) + +* build: gyp disable thin archives (Timothy J. Fontaine) + +* sunos: re-export entire library when static (Timothy J. Fontaine) + +* unix: dtrace probes for tick-start and tick-stop (Timothy J. Fontaine) + +* windows: fix memory leak in fs__sendfile (Shannen Saez) + +* windows: remove double initialization in uv_tty_init (Shannen Saez) + +* build: fix dtrace-enabled out of tree build (Ben Noordhuis) + +* build: squelch -Wdollar-in-identifier-extension warnings (Ben Noordhuis) + +* inet: snprintf returns int, not size_t (Brian White) + +* win: refactor uv_cpu_info (Bert Belder) + +* build: add support for Visual Studio 2012 (Nicholas Vavilov) + +* build: -Wno-dollar-in-identifier-extension is clang only (Ben Noordhuis) + + +2013.03.28, Version 0.10.3 (Stable), 31ebe23973dd98fd8a24c042b606f37a794e99d0 + +Changes since version 0.10.2: + +* include: remove extraneous const from uv_version() (Ben Noordhuis) + +* doc: update README, replace `OS` by `PLATFORM` (Ben Noordhuis) + +* build: simplify .buildstamp rule (Ben Noordhuis) + +* build: disable -Wstrict-aliasing on darwin (Ben Noordhuis) + +* darwin: don't select(&exceptfds) in fallback path (Ben Noordhuis) + +* unix: don't clear flags after closing UDP handle (Saúl Ibarra Corretgé) + + +2013.03.25, Version 0.10.2 (Stable), 0f36a00568f3e7608f97f6c6cdb081f4800a50c9 + +This is the first officially versioned release of libuv. Starting now +libuv will make releases independently of Node.js. + +Changes since Node.js v0.10.0: + +* test: add tap output for windows (Timothy J. Fontaine) + +* unix: fix uv_tcp_simultaneous_accepts() logic (Ben Noordhuis) + +* include: bump UV_VERSION_MINOR (Ben Noordhuis) + +* unix: improve uv_guess_handle() implementation (Ben Noordhuis) + +* stream: run try_select only for pipes and ttys (Fedor Indutny) + +Changes since Node.js v0.10.1: + +* build: rename OS to PLATFORM (Ben Noordhuis) + +* unix: make uv_timer_init() initialize repeat (Brian Mazza) + +* unix: make timers handle large timeouts (Ben Noordhuis) + +* build: add OBJC makefile var (Ben Noordhuis) + +* Add `uv_version()` and `uv_version_string()` APIs (Bert Belder) diff --git a/src/libuv/README.md b/src/libuv/README.md index cdddbd2a..54740ca9 100644 --- a/src/libuv/README.md +++ b/src/libuv/README.md @@ -64,7 +64,7 @@ To build via Makefile simply execute: MinGW users should run this instead: - make OS=mingw + make PLATFORM=mingw Out-of-tree builds are supported: diff --git a/src/libuv/build.mk b/src/libuv/build.mk index 91886f0e..6cba169f 100644 --- a/src/libuv/build.mk +++ b/src/libuv/build.mk @@ -18,17 +18,21 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. -OS ?= $(shell sh -c 'uname -s | tr "[A-Z]" "[a-z]"') +ifdef PLATFORM +override PLATFORM := $(shell echo $(PLATFORM) | tr "[A-Z]" "[a-z]") +else +PLATFORM = $(shell sh -c 'uname -s | tr "[A-Z]" "[a-z]"') +endif CPPFLAGS += -I$(SRCDIR)/include -I$(SRCDIR)/include/uv-private -ifeq (darwin,$(OS)) +ifeq (darwin,$(PLATFORM)) SOEXT = dylib else SOEXT = so endif -ifneq (,$(findstring mingw,$(OS))) +ifneq (,$(findstring mingw,$(PLATFORM))) include $(SRCDIR)/config-mingw.mk else include $(SRCDIR)/config-unix.mk @@ -88,6 +92,7 @@ TESTS= \ test/test-loop-stop.o \ test/test-multiple-listen.o \ test/test-mutexes.o \ + test/test-osx-select.o \ test/test-pass-always.o \ test/test-ping-pong.o \ test/test-pipe-bind-error.o \ @@ -125,6 +130,7 @@ TESTS= \ test/test-threadpool.o \ test/test-threadpool-cancel.o \ test/test-timer-again.o \ + test/test-timer-from-check.o \ test/test-timer.o \ test/test-tty.o \ test/test-udp-dgram-too-big.o \ @@ -137,20 +143,16 @@ TESTS= \ test/test-util.o \ test/test-walk-handles.o \ -all: libuv.a +.PHONY: all bench clean clean-platform distclean test -run-tests$(E): test/run-tests.o test/runner.o $(RUNNER_SRC) $(TESTS) libuv.$(SOEXT) +run-tests$(E): test/run-tests.o test/runner.o $(RUNNER_SRC) $(TESTS) libuv.a $(CC) $(CPPFLAGS) $(RUNNER_CFLAGS) -o $@ $^ $(RUNNER_LIBS) $(RUNNER_LDFLAGS) -run-benchmarks$(E): test/run-benchmarks.o test/runner.o $(RUNNER_SRC) $(BENCHMARKS) libuv.$(SOEXT) +run-benchmarks$(E): test/run-benchmarks.o test/runner.o $(RUNNER_SRC) $(BENCHMARKS) libuv.a $(CC) $(CPPFLAGS) $(RUNNER_CFLAGS) -o $@ $^ $(RUNNER_LIBS) $(RUNNER_LDFLAGS) test/echo.o: test/echo.c test/echo.h - -.PHONY: clean clean-platform distclean test bench - - test: run-tests$(E) $(CURDIR)/$< diff --git a/src/libuv/checksparse.sh b/src/libuv/checksparse.sh index f06b27d2..7412c21c 100755 --- a/src/libuv/checksparse.sh +++ b/src/libuv/checksparse.sh @@ -222,7 +222,7 @@ SunOS) ;; esac -for ARCH in __i386__ __x86_64__ __arm__; do +for ARCH in __i386__ __x86_64__ __arm__ __mips__; do $SPARSE $SPARSE_FLAGS -D$ARCH=1 $SOURCES done diff --git a/src/libuv/common.gypi b/src/libuv/common.gypi index 8c6c8875..67291fdc 100644 --- a/src/libuv/common.gypi +++ b/src/libuv/common.gypi @@ -36,6 +36,7 @@ }, 'xcode_settings': { 'GCC_OPTIMIZATION_LEVEL': '0', + 'OTHER_CFLAGS': [ '-Wno-strict-aliasing' ], }, 'conditions': [ ['OS != "win"', { @@ -132,6 +133,11 @@ [ 'OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', { 'cflags': [ '-Wall' ], 'cflags_cc': [ '-fno-rtti', '-fno-exceptions' ], + 'target_conditions': [ + ['_type=="static_library"', { + 'standalone_static_library': 1, # disable thin archive which needs binutils >= 2.19 + }], + ], 'conditions': [ [ 'host_arch != target_arch and target_arch=="ia32"', { 'cflags': [ '-m32' ], @@ -192,6 +198,11 @@ }], ], }], + ['OS=="solaris"', { + 'cflags': [ '-fno-omit-frame-pointer' ], + # pull in V8's postmortem metadata + 'ldflags': [ '-Wl,-z,allextract' ] + }], ], }, } diff --git a/src/libuv/config-mingw.mk b/src/libuv/config-mingw.mk index 400a6c46..84df27a1 100644 --- a/src/libuv/config-mingw.mk +++ b/src/libuv/config-mingw.mk @@ -35,7 +35,7 @@ RUNNER_LDFLAGS=$(LDFLAGS) RUNNER_LIBS=-lws2_32 -lpsapi -liphlpapi RUNNER_SRC=test/runner-win.c -libuv.a: $(WIN_OBJS) src/fs-poll.o src/inet.o src/uv-common.o +libuv.a: $(WIN_OBJS) src/fs-poll.o src/inet.o src/uv-common.o src/version.o $(AR) rcs $@ $^ src/%.o: src/%.c include/uv.h include/uv-private/uv-win.h diff --git a/src/libuv/config-unix.mk b/src/libuv/config-unix.mk index efe0d17e..d230bb25 100644 --- a/src/libuv/config-unix.mk +++ b/src/libuv/config-unix.mk @@ -29,7 +29,10 @@ CPPFLAGS += -D_FILE_OFFSET_BITS=64 RUNNER_SRC=test/runner-unix.c RUNNER_CFLAGS=$(CFLAGS) -I$(SRCDIR)/test -RUNNER_LDFLAGS=-L"$(CURDIR)" -luv -Xlinker -rpath -Xlinker "$(CURDIR)" +RUNNER_LDFLAGS= + +DTRACE_OBJS= +DTRACE_HEADER= OBJS += src/unix/async.o OBJS += src/unix/core.o @@ -53,27 +56,38 @@ OBJS += src/unix/udp.o OBJS += src/fs-poll.o OBJS += src/uv-common.o OBJS += src/inet.o +OBJS += src/version.o -ifeq (sunos,$(OS)) +ifeq (sunos,$(PLATFORM)) +HAVE_DTRACE ?= 1 CPPFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=500 LDFLAGS+=-lkstat -lnsl -lsendfile -lsocket # Library dependencies are not transitive. -RUNNER_LDFLAGS += $(LDFLAGS) OBJS += src/unix/sunos.o +ifeq (1, $(HAVE_DTRACE)) +OBJS += src/unix/dtrace.o +DTRACE_OBJS += src/unix/core.o +endif endif -ifeq (aix,$(OS)) +ifeq (aix,$(PLATFORM)) CPPFLAGS += -D_ALL_SOURCE -D_XOPEN_SOURCE=500 LDFLAGS+= -lperfstat OBJS += src/unix/aix.o endif -ifeq (darwin,$(OS)) +ifeq (darwin,$(PLATFORM)) +HAVE_DTRACE ?= 1 +# dtrace(1) probes contain dollar signs on OS X. Mute the warnings they +# generate but only when CC=clang, -Wno-dollar-in-identifier-extension +# is a clang extension. +ifeq (__clang__,$(shell sh -c "$(CC) -dM -E - &2 2>/dev/null; echo $$?),0) +HAVE_DTRACE ?= 1 +endif LDFLAGS+=-lkvm OBJS += src/unix/freebsd.o OBJS += src/unix/kqueue.o endif -ifeq (dragonfly,$(OS)) +ifeq (dragonfly,$(PLATFORM)) LDFLAGS+=-lkvm OBJS += src/unix/freebsd.o OBJS += src/unix/kqueue.o endif -ifeq (netbsd,$(OS)) +ifeq (netbsd,$(PLATFORM)) LDFLAGS+=-lkvm OBJS += src/unix/netbsd.o OBJS += src/unix/kqueue.o endif -ifeq (openbsd,$(OS)) +ifeq (openbsd,$(PLATFORM)) LDFLAGS+=-lkvm OBJS += src/unix/openbsd.o OBJS += src/unix/kqueue.o endif -ifneq (,$(findstring cygwin,$(OS))) +ifneq (,$(findstring cygwin,$(PLATFORM))) # We drop the --std=c89, it hides CLOCK_MONOTONIC on cygwin CSTDFLAG = -D_GNU_SOURCE LDFLAGS+= OBJS += src/unix/cygwin.o endif -ifeq (sunos,$(OS)) +ifeq (sunos,$(PLATFORM)) RUNNER_LDFLAGS += -pthreads else RUNNER_LDFLAGS += -pthread endif +ifeq ($(HAVE_DTRACE), 1) +DTRACE_HEADER = src/unix/uv-dtrace.h +CPPFLAGS += -Isrc/unix +CFLAGS += -DHAVE_DTRACE +endif + +ifneq (darwin,$(PLATFORM)) +# Must correspond with UV_VERSION_MAJOR and UV_VERSION_MINOR in src/version.c +SO_LDFLAGS = -Wl,-soname,libuv.so.0.10 +endif + +RUNNER_LDFLAGS += $(LDFLAGS) + +all: + # Force a sequential build of the static and the shared library. + # Works around a make quirk where it forgets to (re)build either + # the *.o or *.pic.o files, depending on what target comes first. + $(MAKE) -f $(SRCDIR)/Makefile libuv.a + $(MAKE) -f $(SRCDIR)/Makefile libuv.$(SOEXT) + libuv.a: $(OBJS) $(AR) rcs $@ $^ libuv.$(SOEXT): override CFLAGS += -fPIC libuv.$(SOEXT): $(OBJS:%.o=%.pic.o) - $(CC) -shared -o $@ $^ $(LDFLAGS) + $(CC) -shared -o $@ $^ $(LDFLAGS) $(SO_LDFLAGS) include/uv-private/uv-unix.h: \ include/uv-private/uv-bsd.h \ @@ -145,10 +182,10 @@ include/uv-private/uv-unix.h: \ src/unix/internal.h: src/unix/linux-syscalls.h src/.buildstamp src/unix/.buildstamp test/.buildstamp: - mkdir -p $(dir $@) + mkdir -p $(@D) touch $@ -src/unix/%.o src/unix/%.pic.o: src/unix/%.c include/uv.h include/uv-private/uv-unix.h src/unix/internal.h src/unix/.buildstamp +src/unix/%.o src/unix/%.pic.o: src/unix/%.c include/uv.h include/uv-private/uv-unix.h src/unix/internal.h src/unix/.buildstamp $(DTRACE_HEADER) $(CC) $(CSTDFLAG) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ src/%.o src/%.pic.o: src/%.c include/uv.h include/uv-private/uv-unix.h src/.buildstamp @@ -158,7 +195,13 @@ test/%.o: test/%.c include/uv.h test/.buildstamp $(CC) $(CSTDFLAG) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ clean-platform: - $(RM) test/run-{tests,benchmarks}.dSYM $(OBJS) $(OBJS:%.o=%.pic.o) + $(RM) test/run-{tests,benchmarks}.dSYM $(OBJS) $(OBJS:%.o=%.pic.o) src/unix/uv-dtrace.h + +src/unix/uv-dtrace.h: src/unix/uv-dtrace.d + dtrace -h -xnolibs -s $< -o $@ + +src/unix/dtrace.o: src/unix/uv-dtrace.d $(DTRACE_OBJS) + dtrace -G -s $^ -o $@ -%.pic.o %.o: %.m - $(CC) $(CPPFLAGS) $(CFLAGS) -c $^ -o $@ +src/unix/dtrace.pic.o: src/unix/uv-dtrace.d $(DTRACE_OBJS:%.o=%.pic.o) + dtrace -G -s $^ -o $@ diff --git a/src/libuv/gyp_uv b/src/libuv/gyp_uv index ab594515..651bd095 100755 --- a/src/libuv/gyp_uv +++ b/src/libuv/gyp_uv @@ -24,6 +24,7 @@ def host_arch(): if machine == 'i386': return 'ia32' if machine == 'x86_64': return 'x64' if machine.startswith('arm'): return 'arm' + if machine.startswith('mips'): return 'mips' return machine # Return as-is and hope for the best. diff --git a/src/libuv/include/uv-private/uv-unix.h b/src/libuv/include/uv-private/uv-unix.h index 729082e0..9e83cd88 100644 --- a/src/libuv/include/uv-private/uv-unix.h +++ b/src/libuv/include/uv-private/uv-unix.h @@ -300,8 +300,8 @@ typedef struct { void* buf; \ size_t len; \ off_t off; \ - uid_t uid; \ - gid_t gid; \ + uv_uid_t uid; \ + uv_gid_t gid; \ double atime; \ double mtime; \ struct uv__work work_req; \ diff --git a/src/libuv/include/uv.h b/src/libuv/include/uv.h index de375d4b..3978def5 100644 --- a/src/libuv/include/uv.h +++ b/src/libuv/include/uv.h @@ -47,7 +47,7 @@ extern "C" { #define UV_VERSION_MAJOR 0 -#define UV_VERSION_MINOR 9 +#define UV_VERSION_MINOR 10 #if defined(_MSC_VER) && _MSC_VER < 1600 @@ -228,6 +228,20 @@ typedef enum { } uv_run_mode; +/* + * Returns the libuv version packed into a single integer. 8 bits are used for + * each component, with the patch number stored in the 8 least significant + * bits. E.g. for libuv 1.2.3 this would return 0x010203. + */ +UV_EXTERN unsigned int uv_version(void); + +/* + * Returns the libuv version number as a string. For non-release versions + * "-pre" is appended, so the version number could be "1.2.3-pre". + */ +UV_EXTERN const char* uv_version_string(void); + + /* * This function must be called before any other functions in libuv. * @@ -273,15 +287,36 @@ UV_EXTERN void uv_stop(uv_loop_t*); UV_EXTERN void uv_ref(uv_handle_t*); UV_EXTERN void uv_unref(uv_handle_t*); +/* + * Update the event loop's concept of "now". Libuv caches the current time + * at the start of the event loop tick in order to reduce the number of + * time-related system calls. + * + * You won't normally need to call this function unless you have callbacks + * that block the event loop for longer periods of time, where "longer" is + * somewhat subjective but probably on the order of a millisecond or more. + */ UV_EXTERN void uv_update_time(uv_loop_t*); + +/* + * Return the current timestamp in milliseconds. The timestamp is cached at + * the start of the event loop tick, see |uv_update_time()| for details and + * rationale. + * + * The timestamp increases monotonically from some arbitrary point in time. + * Don't make assumptions about the starting point, you will only get + * disappointed. + * + * Use uv_hrtime() if you need sub-milliseond granularity. + */ UV_EXTERN uint64_t uv_now(uv_loop_t*); /* * Get backend file descriptor. Only kqueue, epoll and event ports are * supported. * - * This can be used in conjunction with uv_run_once() to poll in one thread and - * run the event loop's event callbacks in another. + * This can be used in conjunction with `uv_run(loop, UV_RUN_NOWAIT)` to + * poll in one thread and run the event loop's event callbacks in another. * * Useful for embedding libuv's event loop in another event loop. * See test/test-embed.c for an example. @@ -660,12 +695,12 @@ UV_EXTERN int uv_tcp_keepalive(uv_tcp_t* handle, unsigned int delay); /* - * This setting applies to Windows only. * Enable/disable simultaneous asynchronous accept requests that are * queued by the operating system when listening for new tcp connections. * This setting is used to tune a tcp server for the desired performance. * Having simultaneous accepts can significantly improve the rate of - * accepting connections (which is why it is enabled by default). + * accepting connections (which is why it is enabled by default) but + * may lead to uneven load distribution in multi-process setups. */ UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable); @@ -1607,10 +1642,10 @@ UV_EXTERN int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file file, int mode, uv_fs_cb cb); UV_EXTERN int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, - int uid, int gid, uv_fs_cb cb); + uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb); UV_EXTERN int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, - int uid, int gid, uv_fs_cb cb); + uv_uid_t uid, uv_gid_t gid, uv_fs_cb cb); enum uv_fs_event { @@ -1805,8 +1840,6 @@ UV_EXTERN extern uint64_t uv_hrtime(void); * Note that this function works on a best-effort basis: there is no guarantee * that libuv can discover all file descriptors that were inherited. In general * it does a better job on Windows than it does on unix. - * - * TODO(bb): insert snarky remark to annoy bnoordhuis and the folks at joyent. */ UV_EXTERN void uv_disable_stdio_inheritance(void); diff --git a/src/libuv/src/inet.c b/src/libuv/src/inet.c index 939a9fa5..8f9d89b0 100644 --- a/src/libuv/src/inet.c +++ b/src/libuv/src/inet.c @@ -54,14 +54,14 @@ uv_err_t uv_inet_ntop(int af, const void* src, char* dst, size_t size) { static uv_err_t inet_ntop4(const unsigned char *src, char *dst, size_t size) { static const char fmt[] = "%u.%u.%u.%u"; char tmp[sizeof "255.255.255.255"]; - size_t l; + int l; #ifndef _WIN32 l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); #else l = _snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); #endif - if (l <= 0 || l >= size) { + if (l <= 0 || (size_t) l >= size) { return uv_enospc_; } strncpy(dst, tmp, size); diff --git a/src/libuv/src/unix/aix.c b/src/libuv/src/unix/aix.c index 5ea33bbc..8ac6eca0 100644 --- a/src/libuv/src/unix/aix.c +++ b/src/libuv/src/unix/aix.c @@ -62,7 +62,6 @@ uint64_t uv__hrtime(void) { int uv_exepath(char* buffer, size_t* size) { ssize_t res; char pp[64], cwdl[PATH_MAX]; - size_t cwdl_len; struct psinfo ps; int fd; @@ -79,7 +78,6 @@ int uv_exepath(char* buffer, size_t* size) { return res; cwdl[res] = '\0'; - cwdl_len = res; (void) snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid()); fd = open(pp, O_RDONLY); diff --git a/src/libuv/src/unix/core.c b/src/libuv/src/unix/core.c index 9b471ec7..e8e5f9e6 100644 --- a/src/libuv/src/unix/core.c +++ b/src/libuv/src/unix/core.c @@ -71,10 +71,8 @@ STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->base) == sizeof(((struct iovec*) 0)->iov_base)); STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->len) == sizeof(((struct iovec*) 0)->iov_len)); -STATIC_ASSERT((uintptr_t) &((uv_buf_t*) 0)->base == - (uintptr_t) &((struct iovec*) 0)->iov_base); -STATIC_ASSERT((uintptr_t) &((uv_buf_t*) 0)->len == - (uintptr_t) &((struct iovec*) 0)->iov_len); +STATIC_ASSERT(offsetof(uv_buf_t, base) == offsetof(struct iovec, iov_base)); +STATIC_ASSERT(offsetof(uv_buf_t, len) == offsetof(struct iovec, iov_len)); uint64_t uv_hrtime(void) { @@ -164,7 +162,12 @@ void uv__make_close_pending(uv_handle_t* handle) { static void uv__finish_close(uv_handle_t* handle) { - assert(!uv__is_active(handle)); + /* Note: while the handle is in the UV_CLOSING state now, it's still possible + * for it to be active in the sense that uv__is_active() returns true. + * A good example is when the user calls uv_shutdown(), immediately followed + * by uv_close(). The handle is considered active at this point because the + * completion of the shutdown req is still pending. + */ assert(handle->flags & UV_CLOSING); assert(!(handle->flags & UV_CLOSED)); handle->flags |= UV_CLOSED; @@ -222,7 +225,7 @@ static void uv__run_closing_handles(uv_loop_t* loop) { int uv_is_closing(const uv_handle_t* handle) { - return handle->flags & (UV_CLOSING | UV_CLOSED); + return uv__is_closing(handle); } @@ -299,6 +302,8 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) { r = uv__loop_alive(loop); while (r != 0 && loop->stop_flag == 0) { + UV_TICK_START(loop, mode); + uv__update_time(loop); uv__run_timers(loop); uv__run_idle(loop); @@ -314,6 +319,8 @@ int uv_run(uv_loop_t* loop, uv_run_mode mode) { uv__run_closing_handles(loop); r = uv__loop_alive(loop); + UV_TICK_STOP(loop, mode); + if (mode & (UV_RUN_ONCE | UV_RUN_NOWAIT)) break; } @@ -333,11 +340,6 @@ void uv_update_time(uv_loop_t* loop) { } -uint64_t uv_now(uv_loop_t* loop) { - return loop->time; -} - - int uv_is_active(const uv_handle_t* handle) { return uv__is_active(handle); } diff --git a/src/libuv/src/unix/cygwin.c b/src/libuv/src/unix/cygwin.c index 97464541..dcd9d6dd 100644 --- a/src/libuv/src/unix/cygwin.c +++ b/src/libuv/src/unix/cygwin.c @@ -55,11 +55,6 @@ void uv_loadavg(double avg[3]) { int uv_exepath(char* buffer, size_t* size) { - uint32_t usize; - int result; - char* path; - char* fullpath; - if (!buffer || !size) { return -1; } diff --git a/src/libuv/src/unix/darwin-proctitle.m b/src/libuv/src/unix/darwin-proctitle.c similarity index 89% rename from src/libuv/src/unix/darwin-proctitle.m rename to src/libuv/src/unix/darwin-proctitle.c index d0ee95b4..c3171a61 100644 --- a/src/libuv/src/unix/darwin-proctitle.m +++ b/src/libuv/src/unix/darwin-proctitle.c @@ -18,10 +18,18 @@ * IN THE SOFTWARE. */ -#include +#include + +#if !TARGET_OS_IPHONE +# include +# include +#endif int uv__set_process_title(const char* title) { +#if TARGET_OS_IPHONE + return -1; +#else typedef CFTypeRef (*LSGetCurrentApplicationASNType)(void); typedef OSStatus (*LSSetApplicationInformationItemType)(int, CFTypeRef, @@ -43,14 +51,14 @@ typedef OSStatus (*LSSetApplicationInformationItemType)(int, if (launch_services_bundle == NULL) return -1; - ls_get_current_application_asn = + ls_get_current_application_asn = (LSGetCurrentApplicationASNType) CFBundleGetFunctionPointerForName(launch_services_bundle, CFSTR("_LSGetCurrentApplicationASN")); if (ls_get_current_application_asn == NULL) return -1; - ls_set_application_information_item = + ls_set_application_information_item = (LSSetApplicationInformationItemType) CFBundleGetFunctionPointerForName(launch_services_bundle, CFSTR("_LSSetApplicationInformationItem")); @@ -75,4 +83,5 @@ typedef OSStatus (*LSSetApplicationInformationItemType)(int, NULL); return (err == noErr) ? 0 : -1; +#endif /* !TARGET_OS_IPHONE */ } diff --git a/src/libuv/src/unix/darwin.c b/src/libuv/src/unix/darwin.c index cfbfed23..77e662f4 100644 --- a/src/libuv/src/unix/darwin.c +++ b/src/libuv/src/unix/darwin.c @@ -38,8 +38,8 @@ #include /* sysconf */ /* Forward declarations */ -void uv__cf_loop_runner(void* arg); -void uv__cf_loop_cb(void* arg); +static void uv__cf_loop_runner(void* arg); +static void uv__cf_loop_cb(void* arg); typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t; struct uv__cf_loop_signal_s { @@ -84,9 +84,8 @@ void uv__platform_loop_delete(uv_loop_t* loop) { uv__cf_loop_signal_t* s; assert(loop->cf_loop != NULL); - CFRunLoopStop(loop->cf_loop); + uv__cf_loop_signal(loop, NULL, NULL); uv_thread_join(&loop->cf_thread); - loop->cf_loop = NULL; uv_sem_destroy(&loop->cf_sem); uv_mutex_destroy(&loop->cf_mutex); @@ -103,7 +102,7 @@ void uv__platform_loop_delete(uv_loop_t* loop) { } -void uv__cf_loop_runner(void* arg) { +static void uv__cf_loop_runner(void* arg) { uv_loop_t* loop; loop = arg; @@ -125,7 +124,7 @@ void uv__cf_loop_runner(void* arg) { } -void uv__cf_loop_cb(void* arg) { +static void uv__cf_loop_cb(void* arg) { uv_loop_t* loop; ngx_queue_t* item; ngx_queue_t split_head; @@ -145,7 +144,12 @@ void uv__cf_loop_cb(void* arg) { item = ngx_queue_head(&split_head); s = ngx_queue_data(item, uv__cf_loop_signal_t, member); - s->cb(s->arg); + + /* This was a termination signal */ + if (s->cb == NULL) + CFRunLoopStop(loop->cf_loop); + else + s->cb(s->arg); ngx_queue_remove(item); free(s); @@ -253,19 +257,21 @@ void uv_loadavg(double avg[3]) { uv_err_t uv_resident_set_memory(size_t* rss) { - struct task_basic_info t_info; - mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; - - int r = task_info(mach_task_self(), - TASK_BASIC_INFO, - (task_info_t)&t_info, - &t_info_count); - - if (r != KERN_SUCCESS) { - return uv__new_sys_error(errno); - } - - *rss = t_info.resident_size; + mach_msg_type_number_t count; + task_basic_info_data_t info; + kern_return_t err; + + count = TASK_BASIC_INFO_COUNT; + err = task_info(mach_task_self(), + TASK_BASIC_INFO, + (task_info_t) &info, + &count); + (void) &err; + /* task_info(TASK_BASIC_INFO) cannot really fail. Anything other than + * KERN_SUCCESS implies a libuv bug. + */ + assert(err == KERN_SUCCESS); + *rss = info.resident_size; return uv_ok_; } diff --git a/src/libuv/src/unix/error.c b/src/libuv/src/unix/error.c index 9e3e84ad..05ab4820 100644 --- a/src/libuv/src/unix/error.c +++ b/src/libuv/src/unix/error.c @@ -79,6 +79,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) { case EMSGSIZE: return UV_EMSGSIZE; case ENAMETOOLONG: return UV_ENAMETOOLONG; case EINVAL: return UV_EINVAL; + case ENETDOWN: return UV_ENETDOWN; case ENETUNREACH: return UV_ENETUNREACH; case ECONNABORTED: return UV_ECONNABORTED; case ELOOP: return UV_ELOOP; diff --git a/src/libuv/src/unix/fs.c b/src/libuv/src/unix/fs.c index 53f46ce7..dde1d3a8 100644 --- a/src/libuv/src/unix/fs.c +++ b/src/libuv/src/unix/fs.c @@ -436,11 +436,14 @@ static ssize_t uv__fs_sendfile(uv_fs_t* req) { * non-blocking mode and not all data could be written. If a non-zero * number of bytes have been sent, we don't consider it an error. */ - len = 0; #if defined(__FreeBSD__) + len = 0; r = sendfile(in_fd, out_fd, req->off, req->len, NULL, &len, 0); #else + /* The darwin sendfile takes len as an input for the length to send, + * so make sure to initialize it with the caller's value. */ + len = req->len; r = sendfile(in_fd, out_fd, req->off, &len, NULL, 0); #endif @@ -595,8 +598,8 @@ int uv_fs_chmod(uv_loop_t* loop, int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, - int uid, - int gid, + uv_uid_t uid, + uv_gid_t gid, uv_fs_cb cb) { INIT(CHOWN); PATH; @@ -628,8 +631,8 @@ int uv_fs_fchmod(uv_loop_t* loop, int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file file, - int uid, - int gid, + uv_uid_t uid, + uv_gid_t gid, uv_fs_cb cb) { INIT(FCHOWN); req->file = file; diff --git a/src/libuv/src/unix/internal.h b/src/libuv/src/unix/internal.h index 35b3b8ca..61cb1ec1 100644 --- a/src/libuv/src/unix/internal.h +++ b/src/libuv/src/unix/internal.h @@ -46,7 +46,7 @@ #endif #define STATIC_ASSERT(expr) \ - void uv__static_assert(int static_assert_failed[0 - !(expr)]) + void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)]) #define ACCESS_ONCE(type, var) \ (*(volatile type*) &(var)) @@ -148,6 +148,9 @@ void uv__stream_init(uv_loop_t* loop, uv_stream_t* stream, uv_handle_type type); int uv__stream_open(uv_stream_t*, int fd, int flags); void uv__stream_destroy(uv_stream_t* stream); +#if defined(__APPLE__) +int uv__stream_try_select(uv_stream_t* stream, int* fd); +#endif /* defined(__APPLE__) */ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); int uv__accept(int sockfd); @@ -253,4 +256,11 @@ static void uv__update_time(uv_loop_t* loop) { loop->time = uv__hrtime() / 1000000; } +#ifdef HAVE_DTRACE +#include "uv-dtrace.h" +#else +#define UV_TICK_START(arg0, arg1) +#define UV_TICK_STOP(arg0, arg1) +#endif + #endif /* UV_UNIX_INTERNAL_H_ */ diff --git a/src/libuv/src/unix/linux-core.c b/src/libuv/src/unix/linux-core.c index daab6f19..e4c34a18 100644 --- a/src/libuv/src/unix/linux-core.c +++ b/src/libuv/src/unix/linux-core.c @@ -284,98 +284,59 @@ uint64_t uv_get_total_memory(void) { uv_err_t uv_resident_set_memory(size_t* rss) { - FILE* f; - int itmp; - char ctmp; - unsigned int utmp; - size_t page_size = getpagesize(); - char *cbuf; - int foundExeEnd; - char buf[PATH_MAX + 1]; - - f = fopen("/proc/self/stat", "r"); - if (!f) return uv__new_sys_error(errno); - - /* PID */ - if (fscanf(f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */ - /* Exec file */ - cbuf = buf; - foundExeEnd = 0; - if (fscanf (f, "%c", cbuf++) == 0) goto error; - while (1) { - if (fscanf(f, "%c", cbuf) == 0) goto error; - if (*cbuf == ')') { - foundExeEnd = 1; - } else if (foundExeEnd && *cbuf == ' ') { - *cbuf = 0; - break; - } + char buf[1024]; + const char* s; + ssize_t n; + long val; + int fd; + int i; - cbuf++; + do + fd = open("/proc/self/stat", O_RDONLY); + while (fd == -1 && errno == EINTR); + + if (fd == -1) + return uv__new_sys_error(errno); + + do + n = read(fd, buf, sizeof(buf) - 1); + while (n == -1 && errno == EINTR); + + SAVE_ERRNO(close(fd)); + if (n == -1) + return uv__new_sys_error(errno); + buf[n] = '\0'; + + s = strchr(buf, ' '); + if (s == NULL) + goto err; + + s += 1; + if (*s != '(') + goto err; + + s = strchr(s, ')'); + if (s == NULL) + goto err; + + for (i = 1; i <= 22; i++) { + s = strchr(s + 1, ' '); + if (s == NULL) + goto err; } - /* State */ - if (fscanf (f, "%c ", &ctmp) == 0) goto error; /* coverity[secure_coding] */ - /* Parent process */ - if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */ - /* Process group */ - if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */ - /* Session id */ - if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */ - /* TTY */ - if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */ - /* TTY owner process group */ - if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */ - /* Flags */ - if (fscanf (f, "%u ", &utmp) == 0) goto error; /* coverity[secure_coding] */ - /* Minor faults (no memory page) */ - if (fscanf (f, "%u ", &utmp) == 0) goto error; /* coverity[secure_coding] */ - /* Minor faults, children */ - if (fscanf (f, "%u ", &utmp) == 0) goto error; /* coverity[secure_coding] */ - /* Major faults (memory page faults) */ - if (fscanf (f, "%u ", &utmp) == 0) goto error; /* coverity[secure_coding] */ - /* Major faults, children */ - if (fscanf (f, "%u ", &utmp) == 0) goto error; /* coverity[secure_coding] */ - /* utime */ - if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */ - /* stime */ - if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */ - /* utime, children */ - if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */ - /* stime, children */ - if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */ - /* jiffies remaining in current time slice */ - if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */ - /* 'nice' value */ - if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */ - /* jiffies until next timeout */ - if (fscanf (f, "%u ", &utmp) == 0) goto error; /* coverity[secure_coding] */ - /* jiffies until next SIGALRM */ - if (fscanf (f, "%u ", &utmp) == 0) goto error; /* coverity[secure_coding] */ - /* start time (jiffies since system boot) */ - if (fscanf (f, "%d ", &itmp) == 0) goto error; /* coverity[secure_coding] */ - - /* Virtual memory size */ - if (fscanf (f, "%u ", &utmp) == 0) goto error; /* coverity[secure_coding] */ - - /* Resident set size */ - if (fscanf (f, "%u ", &utmp) == 0) goto error; /* coverity[secure_coding] */ - *rss = (size_t) utmp * page_size; - - /* rlim */ - if (fscanf (f, "%u ", &utmp) == 0) goto error; /* coverity[secure_coding] */ - /* Start of text */ - if (fscanf (f, "%u ", &utmp) == 0) goto error; /* coverity[secure_coding] */ - /* End of text */ - if (fscanf (f, "%u ", &utmp) == 0) goto error; /* coverity[secure_coding] */ - /* Start of stack */ - if (fscanf (f, "%u ", &utmp) == 0) goto error; /* coverity[secure_coding] */ - - fclose (f); + + errno = 0; + val = strtol(s, NULL, 10); + if (errno != 0) + goto err; + if (val < 0) + goto err; + + *rss = val * getpagesize(); return uv_ok_; -error: - fclose (f); - return uv__new_sys_error(errno); +err: + return uv__new_artificial_error(UV_EINVAL); } @@ -421,12 +382,12 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { return uv__new_sys_error(ENOMEM); if (read_models(numcpus, ci)) { - SAVE_ERRNO(free(ci)); + SAVE_ERRNO(uv_free_cpu_info(ci, numcpus)); return uv__new_sys_error(errno); } if (read_times(numcpus, ci)) { - SAVE_ERRNO(free(ci)); + SAVE_ERRNO(uv_free_cpu_info(ci, numcpus)); return uv__new_sys_error(errno); } @@ -453,76 +414,96 @@ static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) { /* Also reads the CPU frequency on x86. The other architectures only have * a BogoMIPS field, which may not be very accurate. + * + * Note: Simply returns on error, uv_cpu_info() takes care of the cleanup. */ static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) { -#if defined(__i386__) || defined(__x86_64__) static const char model_marker[] = "model name\t: "; static const char speed_marker[] = "cpu MHz\t\t: "; -#elif defined(__arm__) - static const char model_marker[] = "Processor\t: "; - static const char speed_marker[] = ""; -#elif defined(__mips__) - static const char model_marker[] = "cpu model\t\t: "; - static const char speed_marker[] = ""; -#else -# warning uv_cpu_info() is not supported on this architecture. - static const char model_marker[] = ""; - static const char speed_marker[] = ""; -#endif - static const char bogus_model[] = "unknown"; + const char* inferred_model; unsigned int model_idx; unsigned int speed_idx; char buf[1024]; char* model; FILE* fp; - char* inferred_model; - fp = fopen("/proc/cpuinfo", "r"); - if (fp == NULL) - return -1; + /* Most are unused on non-ARM, non-MIPS and non-x86 architectures. */ + (void) &model_marker; + (void) &speed_marker; + (void) &speed_idx; + (void) &model; + (void) &buf; + (void) &fp; model_idx = 0; speed_idx = 0; +#if defined(__arm__) || \ + defined(__i386__) || \ + defined(__mips__) || \ + defined(__x86_64__) + fp = fopen("/proc/cpuinfo", "r"); + if (fp == NULL) + return -1; + while (fgets(buf, sizeof(buf), fp)) { - if (model_marker[0] != '\0' && - model_idx < numcpus && - strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) - { - model = buf + sizeof(model_marker) - 1; - model = strndup(model, strlen(model) - 1); /* strip newline */ - ci[model_idx++].model = model; - continue; + if (model_idx < numcpus) { + if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) { + model = buf + sizeof(model_marker) - 1; + model = strndup(model, strlen(model) - 1); /* Strip newline. */ + if (model == NULL) { + fclose(fp); + return -1; + } + ci[model_idx++].model = model; + continue; + } } - - if (speed_marker[0] != '\0' && - speed_idx < numcpus && - strncmp(buf, speed_marker, sizeof(speed_marker) - 1) == 0) - { - ci[speed_idx++].speed = atoi(buf + sizeof(speed_marker) - 1); - continue; +#if defined(__arm__) || defined(__mips__) + if (model_idx < numcpus) { +#if defined(__arm__) + /* Fallback for pre-3.8 kernels. */ + static const char model_marker[] = "Processor\t: "; +#else /* defined(__mips__) */ + static const char model_marker[] = "cpu model\t\t: "; +#endif + if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) { + model = buf + sizeof(model_marker) - 1; + model = strndup(model, strlen(model) - 1); /* Strip newline. */ + if (model == NULL) { + fclose(fp); + return -1; + } + ci[model_idx++].model = model; + continue; + } } +#else /* !__arm__ && !__mips__ */ + if (speed_idx < numcpus) { + if (strncmp(buf, speed_marker, sizeof(speed_marker) - 1) == 0) { + ci[speed_idx++].speed = atoi(buf + sizeof(speed_marker) - 1); + continue; + } + } +#endif /* __arm__ || __mips__ */ } - fclose(fp); - /* Now we want to make sure that all the models contain *something*: - * it's not safe to leave them as null. - */ - if (model_idx == 0) { - /* No models at all: fake up the first one. */ - ci[0].model = strndup(bogus_model, sizeof(bogus_model) - 1); - model_idx = 1; - } + fclose(fp); +#endif /* __arm__ || __i386__ || __mips__ || __x86_64__ */ - /* Not enough models, but we do have at least one. So we'll just - * copy the rest down: it might be better to indicate somehow that - * the remaining ones have been guessed. + /* Now we want to make sure that all the models contain *something* because + * it's not safe to leave them as null. Copy the last entry unless there + * isn't one, in that case we simply put "unknown" into everything. */ - inferred_model = ci[model_idx - 1].model; + inferred_model = "unknown"; + if (model_idx > 0) + inferred_model = ci[model_idx - 1].model; while (model_idx < numcpus) { - ci[model_idx].model = strndup(inferred_model, strlen(inferred_model)); - model_idx++; + model = strndup(inferred_model, strlen(inferred_model)); + if (model == NULL) + return -1; + ci[model_idx++].model = model; } return 0; diff --git a/src/libuv/src/unix/pipe.c b/src/libuv/src/unix/pipe.c index 1185b91a..4b7f966b 100644 --- a/src/libuv/src/unix/pipe.c +++ b/src/libuv/src/unix/pipe.c @@ -155,6 +155,11 @@ void uv__pipe_close(uv_pipe_t* handle) { int uv_pipe_open(uv_pipe_t* handle, uv_file fd) { +#if defined(__APPLE__) + if (uv__stream_try_select((uv_stream_t*) handle, &fd)) + return -1; +#endif /* defined(__APPLE__) */ + return uv__stream_open((uv_stream_t*)handle, fd, UV_STREAM_READABLE | UV_STREAM_WRITABLE); diff --git a/src/libuv/src/unix/signal.c b/src/libuv/src/unix/signal.c index f7fd2e5e..22c7783b 100644 --- a/src/libuv/src/unix/signal.c +++ b/src/libuv/src/unix/signal.c @@ -160,7 +160,7 @@ static void uv__signal_handler(int signum) { } while (r == -1 && errno == EINTR); assert(r == sizeof msg || - (r == -1 && errno != EAGAIN && errno != EWOULDBLOCK)); + (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))); if (r != -1) handle->caught_signals++; diff --git a/src/libuv/src/unix/stream.c b/src/libuv/src/unix/stream.c index 8137d24e..c9df9797 100644 --- a/src/libuv/src/unix/stream.c +++ b/src/libuv/src/unix/stream.c @@ -33,6 +33,7 @@ #include #include #include +#include /* IOV_MAX */ #if defined(__APPLE__) # include @@ -45,8 +46,8 @@ typedef struct uv__stream_select_s uv__stream_select_t; struct uv__stream_select_s { uv_stream_t* stream; uv_thread_t thread; - uv_sem_t sem; - uv_mutex_t mutex; + uv_sem_t close_sem; + uv_sem_t async_sem; uv_async_t async; int events; int fake_fd; @@ -59,6 +60,7 @@ static void uv__stream_connect(uv_stream_t*); static void uv__write(uv_stream_t* stream); static void uv__read(uv_stream_t* stream); static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events); +static size_t uv__write_req_size(uv_write_t* req); /* Used by the accept() EMFILE party trick. */ @@ -131,7 +133,6 @@ static void uv__stream_osx_select(void* arg) { char buf[1024]; fd_set sread; fd_set swrite; - fd_set serror; int events; int fd; int r; @@ -139,7 +140,7 @@ static void uv__stream_osx_select(void* arg) { stream = arg; s = stream->select; - fd = stream->io_watcher.fd; + fd = s->fd; if (fd > s->int_fd) max_fd = fd; @@ -148,23 +149,21 @@ static void uv__stream_osx_select(void* arg) { while (1) { /* Terminate on semaphore */ - if (uv_sem_trywait(&s->sem) == 0) + if (uv_sem_trywait(&s->close_sem) == 0) break; /* Watch fd using select(2) */ FD_ZERO(&sread); FD_ZERO(&swrite); - FD_ZERO(&serror); if (uv_is_readable(stream)) FD_SET(fd, &sread); if (uv_is_writable(stream)) FD_SET(fd, &swrite); - FD_SET(fd, &serror); FD_SET(s->int_fd, &sread); /* Wait indefinitely for fd events */ - r = select(max_fd + 1, &sread, &swrite, &serror, NULL); + r = select(max_fd + 1, &sread, &swrite, NULL, NULL); if (r == -1) { if (errno == EINTR) continue; @@ -203,15 +202,17 @@ static void uv__stream_osx_select(void* arg) { events |= UV__POLLIN; if (FD_ISSET(fd, &swrite)) events |= UV__POLLOUT; - if (FD_ISSET(fd, &serror)) - events |= UV__POLLERR; - uv_mutex_lock(&s->mutex); - s->events |= events; - uv_mutex_unlock(&s->mutex); + assert(events != 0 || FD_ISSET(s->int_fd, &sread)); + if (events != 0) { + ACCESS_ONCE(int, s->events) = events; - if (events != 0) uv_async_send(&s->async); + uv_sem_wait(&s->async_sem); + + /* Should be processed at this stage */ + assert((s->events == 0) || (stream->flags & UV_CLOSING)); + } } } @@ -244,12 +245,12 @@ static void uv__stream_osx_select_cb(uv_async_t* handle, int status) { stream = s->stream; /* Get and reset stream's events */ - uv_mutex_lock(&s->mutex); events = s->events; - s->events = 0; - uv_mutex_unlock(&s->mutex); + ACCESS_ONCE(int, s->events) = 0; + uv_sem_post(&s->async_sem); - assert(0 == (events & UV__POLLERR)); + assert(events != 0); + assert(events == (events & (UV__POLLIN | UV__POLLOUT))); /* Invoke callback on event-loop */ if ((events & UV__POLLIN) && uv__io_active(&stream->io_watcher, UV__POLLIN)) @@ -268,7 +269,7 @@ static void uv__stream_osx_cb_close(uv_handle_t* async) { } -static int uv__stream_try_select(uv_stream_t* stream, int fd) { +int uv__stream_try_select(uv_stream_t* stream, int* fd) { /* * kqueue doesn't work with some files from /dev mount on osx. * select(2) in separate thread for those fds @@ -288,7 +289,7 @@ static int uv__stream_try_select(uv_stream_t* stream, int fd) { return uv__set_sys_error(stream->loop, errno); } - EV_SET(&filter[0], fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); + EV_SET(&filter[0], *fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); /* Use small timeout, because we only want to capture EINVALs */ timeout.tv_sec = 0; @@ -308,7 +309,8 @@ static int uv__stream_try_select(uv_stream_t* stream, int fd) { if (s == NULL) return uv__set_artificial_error(stream->loop, UV_ENOMEM); - s->fd = fd; + s->events = 0; + s->fd = *fd; if (uv_async_init(stream->loop, &s->async, uv__stream_osx_select_cb)) { SAVE_ERRNO(free(s)); @@ -318,10 +320,10 @@ static int uv__stream_try_select(uv_stream_t* stream, int fd) { s->async.flags |= UV__HANDLE_INTERNAL; uv__handle_unref(&s->async); - if (uv_sem_init(&s->sem, 0)) + if (uv_sem_init(&s->close_sem, 0)) goto fatal1; - if (uv_mutex_init(&s->mutex)) + if (uv_sem_init(&s->async_sem, 0)) goto fatal2; /* Create fds for io watcher and to interrupt the select() loop. */ @@ -336,6 +338,7 @@ static int uv__stream_try_select(uv_stream_t* stream, int fd) { s->stream = stream; stream->select = s; + *fd = s->fake_fd; return 0; @@ -345,9 +348,9 @@ static int uv__stream_try_select(uv_stream_t* stream, int fd) { s->fake_fd = -1; s->int_fd = -1; fatal3: - uv_mutex_destroy(&s->mutex); + uv_sem_destroy(&s->async_sem); fatal2: - uv_sem_destroy(&s->sem); + uv_sem_destroy(&s->close_sem); fatal1: uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close); return uv__set_sys_error(stream->loop, errno); @@ -368,21 +371,6 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) { return uv__set_sys_error(stream->loop, errno); } -#if defined(__APPLE__) - { - uv__stream_select_t* s; - int r; - - r = uv__stream_try_select(stream, fd); - if (r == -1) - return r; - - s = stream->select; - if (s != NULL) - fd = s->fake_fd; - } -#endif /* defined(__APPLE__) */ - stream->io_watcher.fd = fd; return 0; @@ -412,6 +400,7 @@ void uv__stream_destroy(uv_stream_t* stream) { if (req->bufs != req->bufsml) free(req->bufs); + req->bufs = NULL; if (req->cb) { uv__set_artificial_error(req->handle->loop, UV_ECANCELED); @@ -426,6 +415,13 @@ void uv__stream_destroy(uv_stream_t* stream) { req = ngx_queue_data(q, uv_write_t, queue); uv__req_unregister(stream->loop, req); + if (req->bufs != NULL) { + stream->write_queue_size -= uv__write_req_size(req); + if (req->bufs != req->bufsml) + free(req->bufs); + req->bufs = NULL; + } + if (req->cb) { uv__set_sys_error(stream->loop, req->error); req->cb(req, req->error ? -1 : 0); @@ -433,6 +429,11 @@ void uv__stream_destroy(uv_stream_t* stream) { } if (stream->shutdown_req) { + /* The UV_ECANCELED error code is a lie, the shutdown(2) syscall is a + * fait accompli at this point. Maybe we should revisit this in v0.11. + * A possible reason for leaving it unchanged is that it informs the + * callee that the handle has been destroyed. + */ uv__req_unregister(stream->loop, stream->shutdown_req); uv__set_artificial_error(stream->loop, UV_ECANCELED); stream->shutdown_req->cb(stream->shutdown_req, -1); @@ -454,7 +455,6 @@ void uv__stream_destroy(uv_stream_t* stream) { */ static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) { int fd; - int r; if (loop->emfile_fd == -1) return -1; @@ -472,14 +472,8 @@ static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) { if (errno == EINTR) continue; - if (errno == EAGAIN || errno == EWOULDBLOCK) - r = 0; - else - r = -1; - - loop->emfile_fd = uv__open_cloexec("/", O_RDONLY); - - return r; + SAVE_ERRNO(loop->emfile_fd = uv__open_cloexec("/", O_RDONLY)); + return errno; } } @@ -492,10 +486,9 @@ static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) { void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { - static int use_emfile_trick = -1; uv_stream_t* stream; + int err; int fd; - int r; stream = container_of(w, uv_stream_t, io_watcher); assert(events == UV__POLLIN); @@ -510,50 +503,32 @@ void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { */ while (uv__stream_fd(stream) != -1) { assert(stream->accepted_fd == -1); + #if defined(UV_HAVE_KQUEUE) if (w->rcount <= 0) return; #endif /* defined(UV_HAVE_KQUEUE) */ - fd = uv__accept(uv__stream_fd(stream)); + fd = uv__accept(uv__stream_fd(stream)); if (fd == -1) { - switch (errno) { -#if EWOULDBLOCK != EAGAIN - case EWOULDBLOCK: -#endif - case EAGAIN: - return; /* Not an error. */ - - case ECONNABORTED: - UV_DEC_BACKLOG(w) - continue; /* Ignore. */ - - case EMFILE: - case ENFILE: - if (use_emfile_trick == -1) { - const char* val = getenv("UV_ACCEPT_EMFILE_TRICK"); - use_emfile_trick = (val == NULL || atoi(val) != 0); - } + if (errno == EAGAIN || errno == EWOULDBLOCK) + return; /* Not an error. */ - if (use_emfile_trick) { - SAVE_ERRNO(r = uv__emfile_trick(loop, uv__stream_fd(stream))); - if (r == 0) { - UV_DEC_BACKLOG(w) - continue; - } - } - - /* Fall through. */ + if (errno == ECONNABORTED) + continue; /* Ignore. Nothing we can do about that. */ - default: - uv__set_sys_error(loop, errno); - stream->connection_cb(stream, -1); - continue; + if (errno == EMFILE || errno == ENFILE) { + SAVE_ERRNO(err = uv__emfile_trick(loop, uv__stream_fd(stream))); + if (err == EAGAIN || err == EWOULDBLOCK) + break; } + + uv__set_sys_error(loop, errno); + stream->connection_cb(stream, -1); + continue; } UV_DEC_BACKLOG(w) - stream->accepted_fd = fd; stream->connection_cb(stream, 0); @@ -655,10 +630,9 @@ int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { static void uv__drain(uv_stream_t* stream) { uv_shutdown_t* req; + int status; assert(ngx_queue_empty(&stream->write_queue)); - assert(stream->write_queue_size == 0); - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT); /* Shutdown? */ @@ -669,21 +643,17 @@ static void uv__drain(uv_stream_t* stream) { req = stream->shutdown_req; stream->shutdown_req = NULL; + stream->flags &= ~UV_STREAM_SHUTTING; uv__req_unregister(stream->loop, req); - if (shutdown(uv__stream_fd(stream), SHUT_WR)) { - /* Error. Report it. User should call uv_close(). */ + status = shutdown(uv__stream_fd(stream), SHUT_WR); + if (status) uv__set_sys_error(stream->loop, errno); - if (req->cb) { - req->cb(req, -1); - } - } else { - uv__set_sys_error(stream->loop, 0); - ((uv_handle_t*) stream)->flags |= UV_STREAM_SHUT; - if (req->cb) { - req->cb(req, 0); - } - } + else + stream->flags |= UV_STREAM_SHUT; + + if (req->cb != NULL) + req->cb(req, status); } } @@ -691,6 +661,7 @@ static void uv__drain(uv_stream_t* stream) { static size_t uv__write_req_size(uv_write_t* req) { size_t size; + assert(req->bufs != NULL); size = uv__buf_count(req->bufs + req->write_index, req->bufcnt - req->write_index); assert(req->handle->write_queue_size >= size); @@ -704,10 +675,18 @@ static void uv__write_req_finish(uv_write_t* req) { /* Pop the req off tcp->write_queue. */ ngx_queue_remove(&req->queue); - if (req->bufs != req->bufsml) { - free(req->bufs); + + /* Only free when there was no error. On error, we touch up write_queue_size + * right before making the callback. The reason we don't do that right away + * is that a write_queue_size > 0 is our only way to signal to the user that + * he should stop writing - which he should if we got an error. Something to + * revisit in future revisions of the libuv API. + */ + if (req->error == 0) { + if (req->bufs != req->bufsml) + free(req->bufs); + req->bufs = NULL; } - req->bufs = NULL; /* Add it to the write_completed_queue where it will have its * callback called in the near future. @@ -743,10 +722,8 @@ static void uv__write(uv_stream_t* stream) { assert(uv__stream_fd(stream) >= 0); - if (ngx_queue_empty(&stream->write_queue)) { - assert(stream->write_queue_size == 0); + if (ngx_queue_empty(&stream->write_queue)) return; - } q = ngx_queue_head(&stream->write_queue); req = ngx_queue_data(q, uv_write_t, queue); @@ -760,6 +737,10 @@ static void uv__write(uv_stream_t* stream) { iov = (struct iovec*) &(req->bufs[req->write_index]); iovcnt = req->bufcnt - req->write_index; + /* Limit iov count to avoid EINVALs from writev() */ + if (iovcnt > IOV_MAX) + iovcnt = IOV_MAX; + /* * Now do the actual writev. Note that we've been updating the pointers * inside the iov each time we write. So there is no need to offset it. @@ -813,8 +794,10 @@ static void uv__write(uv_stream_t* stream) { if (errno != EAGAIN && errno != EWOULDBLOCK) { /* Error */ req->error = errno; - stream->write_queue_size -= uv__write_req_size(req); 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__handle_stop(stream); return; } else if (stream->flags & UV_STREAM_BLOCKING) { /* If this is a blocking stream, try again. */ @@ -890,6 +873,13 @@ static void uv__write_callbacks(uv_stream_t* stream) { ngx_queue_remove(q); uv__req_unregister(stream->loop, req); + if (req->bufs != NULL) { + stream->write_queue_size -= uv__write_req_size(req); + if (req->bufs != req->bufsml) + free(req->bufs); + req->bufs = NULL; + } + /* NOTE: call callback AFTER freeing the request data. */ if (req->cb) { uv__set_sys_error(stream->loop, req->error); @@ -1128,7 +1118,7 @@ static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { return; /* read_cb closed stream. */ } - if (events & UV__POLLOUT) { + if (events & (UV__POLLOUT | UV__POLLERR | UV__POLLHUP)) { assert(uv__stream_fd(stream) >= 0); uv__write(stream); uv__write_callbacks(stream); @@ -1171,6 +1161,7 @@ static void uv__stream_connect(uv_stream_t* stream) { stream->connect_req = NULL; uv__req_unregister(stream->loop, req); + uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLOUT); if (req->cb) { uv__set_sys_error(stream->loop, error); @@ -1210,6 +1201,12 @@ int uv_write2(uv_write_t* req, return uv__set_artificial_error(stream->loop, UV_EBADF); } + /* It's legal for write_queue_size > 0 even when the write_queue is empty; + * it means there are error-state requests in the write_completed_queue that + * will touch up write_queue_size later, see also uv__write_req_finish(). + * We chould check that write_queue is empty instead but that implies making + * a write() syscall when we know that the handle is in error mode. + */ empty_queue = (stream->write_queue_size == 0); /* Initialize the req */ @@ -1318,9 +1315,10 @@ int uv_read2_start(uv_stream_t* stream, uv_alloc_cb alloc_cb, int uv_read_stop(uv_stream_t* stream) { - uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN); - uv__handle_stop(stream); 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__handle_stop(stream); #if defined(__APPLE__) /* Notify select() thread about state change */ @@ -1370,11 +1368,12 @@ void uv__stream_close(uv_stream_t* handle) { s = handle->select; - uv_sem_post(&s->sem); + uv_sem_post(&s->close_sem); + uv_sem_post(&s->async_sem); uv__stream_osx_interrupt_select(handle); uv_thread_join(&s->thread); - uv_sem_destroy(&s->sem); - uv_mutex_destroy(&s->mutex); + uv_sem_destroy(&s->close_sem); + uv_sem_destroy(&s->async_sem); close(s->fake_fd); close(s->int_fd); uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close); @@ -1383,8 +1382,9 @@ void uv__stream_close(uv_stream_t* handle) { } #endif /* defined(__APPLE__) */ - uv_read_stop(handle); uv__io_close(handle->loop, &handle->io_watcher); + uv_read_stop(handle); + uv__handle_stop(handle); close(handle->io_watcher.fd); handle->io_watcher.fd = -1; diff --git a/src/libuv/src/unix/tcp.c b/src/libuv/src/unix/tcp.c index a51576ba..26ab53db 100644 --- a/src/libuv/src/unix/tcp.c +++ b/src/libuv/src/unix/tcp.c @@ -343,11 +343,11 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) { } -int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int on) { - if (on) - handle->flags |= UV_TCP_SINGLE_ACCEPT; - else +int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { + if (enable) handle->flags &= ~UV_TCP_SINGLE_ACCEPT; + else + handle->flags |= UV_TCP_SINGLE_ACCEPT; return 0; } diff --git a/src/libuv/src/unix/thread.c b/src/libuv/src/unix/thread.c index e44a77ff..4d59e938 100644 --- a/src/libuv/src/unix/thread.c +++ b/src/libuv/src/unix/thread.c @@ -42,7 +42,7 @@ int uv_thread_join(uv_thread_t *tid) { int uv_mutex_init(uv_mutex_t* mutex) { -#ifdef NDEBUG +#if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK) if (pthread_mutex_init(mutex, NULL)) return -1; else diff --git a/src/libuv/src/unix/timer.c b/src/libuv/src/unix/timer.c index 41038c8a..57d32f58 100644 --- a/src/libuv/src/unix/timer.c +++ b/src/libuv/src/unix/timer.c @@ -21,6 +21,8 @@ #include "uv.h" #include "internal.h" #include +#include + static int uv__timer_cmp(const uv_timer_t* a, const uv_timer_t* b) { if (a->timeout < b->timeout) @@ -45,6 +47,7 @@ RB_GENERATE_STATIC(uv__timers, uv_timer_s, tree_entry, uv__timer_cmp) int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) { uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER); handle->timer_cb = NULL; + handle->repeat = 0; return 0; } @@ -54,11 +57,17 @@ int uv_timer_start(uv_timer_t* handle, uv_timer_cb cb, uint64_t timeout, uint64_t repeat) { + uint64_t clamped_timeout; + if (uv__is_active(handle)) uv_timer_stop(handle); + clamped_timeout = handle->loop->time + timeout; + if (clamped_timeout < timeout) + clamped_timeout = (uint64_t) -1; + handle->timer_cb = cb; - handle->timeout = handle->loop->time + timeout; + handle->timeout = clamped_timeout; handle->repeat = repeat; /* start_id is the second index to be compared in uv__timer_cmp() */ handle->start_id = handle->loop->timer_counter++; @@ -106,6 +115,7 @@ uint64_t uv_timer_get_repeat(const uv_timer_t* handle) { int uv__next_timeout(const uv_loop_t* loop) { const uv_timer_t* handle; + uint64_t diff; /* RB_MIN expects a non-const tree root. That's okay, it doesn't modify it. */ handle = RB_MIN(uv__timers, (struct uv__timers*) &loop->timer_handles); @@ -116,7 +126,11 @@ int uv__next_timeout(const uv_loop_t* loop) { if (handle->timeout <= loop->time) return 0; - return handle->timeout - loop->time; + diff = handle->timeout - loop->time; + if (diff > INT_MAX) + diff = INT_MAX; + + return diff; } diff --git a/src/libuv/src/unix/tty.c b/src/libuv/src/unix/tty.c index 49efee7f..a2b76add 100644 --- a/src/libuv/src/unix/tty.c +++ b/src/libuv/src/unix/tty.c @@ -36,6 +36,11 @@ static struct termios orig_termios; int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) { uv__stream_init(loop, (uv_stream_t*)tty, UV_TTY); +#if defined(__APPLE__) + if (uv__stream_try_select((uv_stream_t*) tty, &fd)) + return -1; +#endif /* defined(__APPLE__) */ + if (readable) { uv__nonblock(fd, 1); uv__stream_open((uv_stream_t*)tty, fd, UV_STREAM_READABLE); @@ -118,25 +123,52 @@ int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) { uv_handle_type uv_guess_handle(uv_file file) { + struct sockaddr sa; struct stat s; + socklen_t len; + int type; - if (file < 0) { + if (file < 0) return UV_UNKNOWN_HANDLE; - } - if (isatty(file)) { + if (isatty(file)) return UV_TTY; - } - if (fstat(file, &s)) { + if (fstat(file, &s)) return UV_UNKNOWN_HANDLE; - } - if (!S_ISSOCK(s.st_mode) && !S_ISFIFO(s.st_mode)) { + if (S_ISREG(s.st_mode)) return UV_FILE; + + if (S_ISCHR(s.st_mode)) + return UV_FILE; /* XXX UV_NAMED_PIPE? */ + + if (S_ISFIFO(s.st_mode)) + return UV_NAMED_PIPE; + + if (!S_ISSOCK(s.st_mode)) + return UV_UNKNOWN_HANDLE; + + len = sizeof(type); + if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len)) + return UV_UNKNOWN_HANDLE; + + len = sizeof(sa); + if (getsockname(file, &sa, &len)) + return UV_UNKNOWN_HANDLE; + + if (type == SOCK_DGRAM) + if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6) + return UV_UDP; + + if (type == SOCK_STREAM) { + if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6) + return UV_TCP; + if (sa.sa_family == AF_UNIX) + return UV_NAMED_PIPE; } - return UV_NAMED_PIPE; + return UV_UNKNOWN_HANDLE; } diff --git a/src/libuv/src/unix/udp.c b/src/libuv/src/unix/udp.c index e1a12f2b..3fb8af93 100644 --- a/src/libuv/src/unix/udp.c +++ b/src/libuv/src/unix/udp.c @@ -79,7 +79,6 @@ void uv__udp_finish_close(uv_udp_t* handle) { } /* Now tear down the handle. */ - handle->flags = 0; handle->recv_cb = NULL; handle->alloc_cb = NULL; /* but _do not_ touch close_cb */ diff --git a/src/libuv/src/unix/uv-dtrace.d b/src/libuv/src/unix/uv-dtrace.d new file mode 100644 index 00000000..7848450c --- /dev/null +++ b/src/libuv/src/unix/uv-dtrace.d @@ -0,0 +1,25 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +provider uv { + probe tick__start(void* loop, int mode); + probe tick__stop(void* loop, int mode); +}; diff --git a/src/libuv/src/uv-common.c b/src/libuv/src/uv-common.c index 8c9d323a..f0792f11 100644 --- a/src/libuv/src/uv-common.c +++ b/src/libuv/src/uv-common.c @@ -429,3 +429,8 @@ void uv_unref(uv_handle_t* handle) { void uv_stop(uv_loop_t* loop) { loop->stop_flag = 1; } + + +uint64_t uv_now(uv_loop_t* loop) { + return loop->time; +} diff --git a/src/libuv/src/uv-common.h b/src/libuv/src/uv-common.h index 80c9c719..bbf24859 100644 --- a/src/libuv/src/uv-common.h +++ b/src/libuv/src/uv-common.h @@ -149,6 +149,9 @@ void uv__fs_poll_close(uv_fs_poll_t* handle); #define uv__is_active(h) \ (((h)->flags & UV__HANDLE_ACTIVE) != 0) +#define uv__is_closing(h) \ + (((h)->flags & (UV_CLOSING | UV_CLOSED)) != 0) + #define uv__handle_start(h) \ do { \ assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \ diff --git a/src/libuv/src/version.c b/src/libuv/src/version.c new file mode 100644 index 00000000..1010b2af --- /dev/null +++ b/src/libuv/src/version.c @@ -0,0 +1,66 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" + + /* + * Versions with an even minor version (e.g. 0.6.1 or 1.0.4) are API and ABI + * stable. When the minor version is odd, the API can change between patch + * releases. Make sure you update the -soname directives in config-unix.mk + * and uv.gyp whenever you bump UV_VERSION_MAJOR or UV_VERSION_MINOR (but + * not UV_VERSION_PATCH.) + */ + +#undef UV_VERSION_MAJOR /* TODO(bnoordhuis) Remove in v0.11. */ +#undef UV_VERSION_MINOR /* TODO(bnoordhuis) Remove in v0.11. */ + +#define UV_VERSION_MAJOR 0 +#define UV_VERSION_MINOR 10 +#define UV_VERSION_PATCH 13 +#define UV_VERSION_IS_RELEASE 1 + + +#define UV_VERSION ((UV_VERSION_MAJOR << 16) | \ + (UV_VERSION_MINOR << 8) | \ + (UV_VERSION_PATCH)) + +#define UV_STRINGIFY(v) UV_STRINGIFY_HELPER(v) +#define UV_STRINGIFY_HELPER(v) #v + +#define UV_VERSION_STRING_BASE UV_STRINGIFY(UV_VERSION_MAJOR) "." \ + UV_STRINGIFY(UV_VERSION_MINOR) "." \ + UV_STRINGIFY(UV_VERSION_PATCH) + +#if UV_VERSION_IS_RELEASE +# define UV_VERSION_STRING UV_VERSION_STRING_BASE +#else +# define UV_VERSION_STRING UV_VERSION_STRING_BASE "-pre" +#endif + + +unsigned int uv_version(void) { + return UV_VERSION; +} + + +const char* uv_version_string(void) { + return UV_VERSION_STRING; +} diff --git a/src/libuv/src/win/core.c b/src/libuv/src/win/core.c index a06c23f3..62d6bf8f 100644 --- a/src/libuv/src/win/core.c +++ b/src/libuv/src/win/core.c @@ -55,7 +55,7 @@ static void uv_init(void) { /* Tell the CRT to not exit the application when an invalid parameter is */ /* passed. The main issue is that invalid FDs will trigger this behavior. */ -#ifdef _WRITE_ABORT_MSG +#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800 _set_invalid_parameter_handler(uv__crt_invalid_parameter_handler); #endif @@ -185,7 +185,6 @@ int uv_backend_timeout(const uv_loop_t* loop) { static void uv_poll(uv_loop_t* loop, int block) { - BOOL success; DWORD bytes, timeout; ULONG_PTR key; OVERLAPPED* overlapped; @@ -197,18 +196,16 @@ static void uv_poll(uv_loop_t* loop, int block) { timeout = 0; } - success = GetQueuedCompletionStatus(loop->iocp, - &bytes, - &key, - &overlapped, - timeout); + GetQueuedCompletionStatus(loop->iocp, + &bytes, + &key, + &overlapped, + timeout); if (overlapped) { /* Package was dequeued */ req = uv_overlapped_to_req(overlapped); - uv_insert_pending_req(loop, req); - } else if (GetLastError() != WAIT_TIMEOUT) { /* Serious error */ uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus"); @@ -230,14 +227,13 @@ static void uv_poll_ex(uv_loop_t* loop, int block) { timeout = 0; } - assert(pGetQueuedCompletionStatusEx); - success = pGetQueuedCompletionStatusEx(loop->iocp, overlappeds, ARRAY_SIZE(overlappeds), &count, timeout, FALSE); + if (success) { for (i = 0; i < count; i++) { /* Package was dequeued */ diff --git a/src/libuv/src/win/fs.c b/src/libuv/src/win/fs.c index 60e67a41..e78bc1b8 100644 --- a/src/libuv/src/win/fs.c +++ b/src/libuv/src/win/fs.c @@ -1048,6 +1048,8 @@ static void fs__sendfile(uv_fs_t* req) { } } + free(buf); + SET_REQ_RESULT(req, result); } @@ -1670,8 +1672,8 @@ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, } -int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, int uid, - int gid, uv_fs_cb cb) { +int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid, + uv_gid_t gid, uv_fs_cb cb) { uv_fs_req_init(loop, req, UV_FS_CHOWN, cb); if (fs__capture_path(loop, req, path, NULL, cb != NULL) < 0) { @@ -1689,8 +1691,8 @@ int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, int uid, } -int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int uid, - int gid, uv_fs_cb cb) { +int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid, + uv_gid_t gid, uv_fs_cb cb) { uv_fs_req_init(loop, req, UV_FS_FCHOWN, cb); if (cb) { diff --git a/src/libuv/src/win/poll.c b/src/libuv/src/win/poll.c index 82197241..f6972f96 100644 --- a/src/libuv/src/win/poll.c +++ b/src/libuv/src/win/poll.c @@ -311,7 +311,7 @@ static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop, static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) { uv_req_t* req = (uv_req_t*) arg; uv_poll_t* handle = (uv_poll_t*) req->data; - unsigned char events, reported_events; + unsigned char reported_events; int r; uv_single_fd_set_t rfds, wfds, efds; struct timeval timeout; @@ -319,14 +319,6 @@ static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) { assert(handle->type == UV_POLL); assert(req->type == UV_POLL_REQ); - if (req == &handle->poll_req_1) { - events = handle->submitted_events_1; - } else if (req == &handle->poll_req_2) { - events = handle->submitted_events_2; - } else { - assert(0); - } - if (handle->events & UV_READABLE) { rfds.fd_count = 1; rfds.fd_array[0] = handle->socket; diff --git a/src/libuv/src/win/process.c b/src/libuv/src/win/process.c index c5649d3a..fb445b6c 100644 --- a/src/libuv/src/win/process.c +++ b/src/libuv/src/win/process.c @@ -45,6 +45,51 @@ typedef struct env_var { #define E_V(str) { str "=", L##str, sizeof(str), 0, 0 } +static HANDLE uv_global_job_handle_; +static uv_once_t uv_global_job_handle_init_guard_ = UV_ONCE_INIT; + + +static void uv__init_global_job_handle(void) { + /* Create a job object and set it up to kill all contained processes when + * it's closed. Since this handle is made non-inheritable and we're not + * giving it to anyone, we're the only process holding a reference to it. + * That means that if this process exits it is closed and all the processes + * it contains are killed. All processes created with uv_spawn that are not + * spawned with the UV_PROCESS_DETACHED flag are assigned to this job. + * + * We're setting the JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag so only the + * processes that we explicitly add are affected, and *their* subprocesses + * are not. This ensures that our child processes are not limited in their + * ability to use job control on Windows versions that don't deal with + * nested jobs (prior to Windows 8 / Server 2012). It also lets our child + * processes created detached processes without explicitly breaking away + * from job control (which uv_spawn doesn't, either). + */ + SECURITY_ATTRIBUTES attr; + JOBOBJECT_EXTENDED_LIMIT_INFORMATION info; + + memset(&attr, 0, sizeof attr); + attr.bInheritHandle = FALSE; + + memset(&info, 0, sizeof info); + info.BasicLimitInformation.LimitFlags = + JOB_OBJECT_LIMIT_BREAKAWAY_OK | + JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK | + JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION | + JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + + uv_global_job_handle_ = CreateJobObjectW(&attr, NULL); + if (uv_global_job_handle_ == NULL) + uv_fatal_error(GetLastError(), "CreateJobObjectW"); + + if (!SetInformationJobObject(uv_global_job_handle_, + JobObjectExtendedLimitInformation, + &info, + sizeof info)) + uv_fatal_error(GetLastError(), "SetInformationJobObject"); +} + + static uv_err_t uv_utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) { int ws_len, r; WCHAR* ws; @@ -180,7 +225,7 @@ static WCHAR* search_path_join_test(const WCHAR* dir, attrs = GetFileAttributesW(result); if (attrs != INVALID_FILE_ATTRIBUTES && - !(attrs & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT))) { + !(attrs & FILE_ATTRIBUTE_DIRECTORY)) { return result; } @@ -890,7 +935,18 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, } process_flags = CREATE_UNICODE_ENVIRONMENT; + if (options.flags & UV_PROCESS_DETACHED) { + /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That + * means that libuv might not let you create a fully deamonized process + * when run under job control. However the type of job control that libuv + * itself creates doesn't trickle down to subprocesses so they can still + * daemonize. + * + * A reason to not do this is that CREATE_BREAKAWAY_FROM_JOB makes the + * CreateProcess call fail if we're under job control that doesn't allow + * breakaway. + */ process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP; } @@ -908,6 +964,28 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, process->process_handle = info.hProcess; process->pid = info.dwProcessId; + /* If the process isn't spawned as detached, assign to the global job */ + /* object so windows will kill it when the parent process dies. */ + if (!(options.flags & UV_PROCESS_DETACHED)) { + uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle); + + if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) { + /* AssignProcessToJobObject might fail if this process is under job + * control and the job doesn't have the + * JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag set, on a Windows version + * that doesn't support nested jobs. + * + * When that happens we just swallow the error and continue without + * establishing a kill-child-on-parent-exit relationship, otherwise + * there would be no way for libuv applications run under job control + * to spawn processes at all. + */ + DWORD err = GetLastError(); + if (err != ERROR_ACCESS_DENIED) + uv_fatal_error(err, "AssignProcessToJobObject"); + } + } + /* Set IPC pid to all IPC pipes. */ for (i = 0; i < options.stdio_count; i++) { const uv_stdio_container_t* fdopt = &options.stdio[i]; diff --git a/src/libuv/src/win/stream.c b/src/libuv/src/win/stream.c index 097f3497..edc5407c 100644 --- a/src/libuv/src/win/stream.c +++ b/src/libuv/src/win/stream.c @@ -56,7 +56,7 @@ int uv_accept(uv_stream_t* server, uv_stream_t* client) { int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb) { if (handle->flags & UV_HANDLE_READING) { - uv__set_sys_error(handle->loop, UV_EALREADY); + uv__set_artificial_error(handle->loop, UV_EALREADY); return -1; } @@ -82,7 +82,7 @@ int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb, int uv_read2_start(uv_stream_t* handle, uv_alloc_cb alloc_cb, uv_read2_cb read_cb) { if (handle->flags & UV_HANDLE_READING) { - uv__set_sys_error(handle->loop, UV_EALREADY); + uv__set_artificial_error(handle->loop, UV_EALREADY); return -1; } diff --git a/src/libuv/src/win/tcp.c b/src/libuv/src/win/tcp.c index c3ef6533..59a36de0 100644 --- a/src/libuv/src/win/tcp.c +++ b/src/libuv/src/win/tcp.c @@ -50,7 +50,7 @@ static int uv__tcp_nodelay(uv_tcp_t* handle, SOCKET socket, int enable) { TCP_NODELAY, (const char*)&enable, sizeof enable) == -1) { - uv__set_sys_error(handle->loop, errno); + uv__set_sys_error(handle->loop, WSAGetLastError()); return -1; } return 0; @@ -63,7 +63,7 @@ static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsign SO_KEEPALIVE, (const char*)&enable, sizeof enable) == -1) { - uv__set_sys_error(handle->loop, errno); + uv__set_sys_error(handle->loop, WSAGetLastError()); return -1; } @@ -72,7 +72,7 @@ static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsign TCP_KEEPALIVE, (const char*)&delay, sizeof delay) == -1) { - uv__set_sys_error(handle->loop, errno); + uv__set_sys_error(handle->loop, WSAGetLastError()); return -1; } diff --git a/src/libuv/src/win/timer.c b/src/libuv/src/win/timer.c index 0c055da9..8dae7414 100644 --- a/src/libuv/src/win/timer.c +++ b/src/libuv/src/win/timer.c @@ -45,11 +45,6 @@ void uv_update_time(uv_loop_t* loop) { } -uint64_t uv_now(uv_loop_t* loop) { - return loop->time; -} - - static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) { if (a->due < b->due) return -1; @@ -87,6 +82,17 @@ void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle) { } +static uint64_t get_clamped_due_time(uint64_t loop_time, uint64_t timeout) { + uint64_t clamped_timeout; + + clamped_timeout = loop_time + timeout; + if (clamped_timeout < timeout) + clamped_timeout = (uint64_t) -1; + + return clamped_timeout; +} + + int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, uint64_t timeout, uint64_t repeat) { uv_loop_t* loop = handle->loop; @@ -97,7 +103,7 @@ int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, uint64_t timeout, } handle->timer_cb = timer_cb; - handle->due = loop->time + timeout; + handle->due = get_clamped_due_time(loop->time, timeout); handle->repeat = repeat; handle->flags |= UV_HANDLE_ACTIVE; uv__handle_start(handle); @@ -143,7 +149,7 @@ int uv_timer_again(uv_timer_t* handle) { } if (handle->repeat) { - handle->due = loop->time + handle->repeat; + handle->due = get_clamped_due_time(loop->time, handle->repeat); if (RB_INSERT(uv_timer_tree_s, &loop->timers, handle) != NULL) { uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT"); @@ -212,7 +218,7 @@ void uv_process_timers(uv_loop_t* loop) { if (timer->repeat != 0) { /* If it is a repeating timer, reschedule with repeat timeout. */ - timer->due += timer->repeat; + timer->due = get_clamped_due_time(timer->due, timer->repeat); if (timer->due < loop->time) { timer->due = loop->time; } diff --git a/src/libuv/src/win/tty.c b/src/libuv/src/win/tty.c index 8f7e7657..64934ffa 100644 --- a/src/libuv/src/win/tty.c +++ b/src/libuv/src/win/tty.c @@ -96,7 +96,7 @@ void uv_console_init() { int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) { - HANDLE handle = INVALID_HANDLE_VALUE; + HANDLE handle; CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info; handle = (HANDLE) _get_osfhandle(fd); diff --git a/src/libuv/src/win/udp.c b/src/libuv/src/win/udp.c index b6b6e0f7..4dcb19d8 100644 --- a/src/libuv/src/win/udp.c +++ b/src/libuv/src/win/udp.c @@ -182,7 +182,7 @@ static int uv__bind(uv_udp_t* handle, int addrsize, unsigned int flags) { int r; - DWORD no = 0, yes = 1; + DWORD no = 0; if ((flags & UV_UDP_IPV6ONLY) && family != AF_INET6) { /* UV_UDP_IPV6ONLY is supported only for IPV6 sockets */ @@ -658,7 +658,6 @@ int uv_udp_set_broadcast(uv_udp_t* handle, int value) { int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) { WSAPROTOCOL_INFOW protocol_info; int opt_len; - DWORD yes = 1; /* Detect the address family of the socket. */ opt_len = (int) sizeof protocol_info; diff --git a/src/libuv/src/win/util.c b/src/libuv/src/win/util.c index 362d12c9..4dd07363 100644 --- a/src/libuv/src/win/util.c +++ b/src/libuv/src/win/util.c @@ -580,47 +580,50 @@ uv_err_t uv_uptime(double* uptime) { } -uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { +uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) { + uv_cpu_info_t* cpu_infos; SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi; DWORD sppi_size; SYSTEM_INFO system_info; - DWORD cpu_count, i, r; + DWORD cpu_count, r, i; + NTSTATUS status; ULONG result_size; - size_t size; uv_err_t err; uv_cpu_info_t* cpu_info; - *cpu_infos = NULL; - *count = 0; + cpu_infos = NULL; + cpu_count = 0; + sppi = NULL; uv__once_init(); GetSystemInfo(&system_info); cpu_count = system_info.dwNumberOfProcessors; - size = cpu_count * sizeof(uv_cpu_info_t); - *cpu_infos = (uv_cpu_info_t*) malloc(size); - if (*cpu_infos == NULL) { + cpu_infos = calloc(cpu_count, sizeof *cpu_infos); + if (cpu_infos == NULL) { err = uv__new_artificial_error(UV_ENOMEM); - goto out; + goto error; } - memset(*cpu_infos, 0, size); - sppi_size = sizeof(*sppi) * cpu_count; - sppi = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION*) malloc(sppi_size); - if (!sppi) { - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + sppi_size = cpu_count * sizeof(*sppi); + sppi = malloc(sppi_size); + if (sppi == NULL) { + err = uv__new_artificial_error(UV_ENOMEM); + goto error; } - r = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, - sppi, - sppi_size, - &result_size); - if (r != ERROR_SUCCESS || result_size != sppi_size) { - err = uv__new_sys_error(GetLastError()); - goto out; + status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation, + sppi, + sppi_size, + &result_size); + if (!NT_SUCCESS(status)) { + err = uv__new_sys_error(pRtlNtStatusToDosError(status)); + goto error; } + assert(result_size == sppi_size); + for (i = 0; i < cpu_count; i++) { WCHAR key_name[128]; HKEY processor_key; @@ -628,11 +631,14 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { DWORD cpu_speed_size = sizeof(cpu_speed); WCHAR cpu_brand[256]; DWORD cpu_brand_size = sizeof(cpu_brand); + int len; - _snwprintf(key_name, - ARRAY_SIZE(key_name), - L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", - i); + len = _snwprintf(key_name, + ARRAY_SIZE(key_name), + L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d", + i); + + assert(len > 0 && len < ARRAY_SIZE(key_name)); r = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key_name, @@ -641,32 +647,34 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { &processor_key); if (r != ERROR_SUCCESS) { err = uv__new_sys_error(GetLastError()); - goto out; + goto error; } if (RegQueryValueExW(processor_key, L"~MHz", - NULL, NULL, + NULL, + NULL, (BYTE*) &cpu_speed, &cpu_speed_size) != ERROR_SUCCESS) { err = uv__new_sys_error(GetLastError()); RegCloseKey(processor_key); - goto out; + goto error; } if (RegQueryValueExW(processor_key, L"ProcessorNameString", - NULL, NULL, + NULL, + NULL, (BYTE*) &cpu_brand, &cpu_brand_size) != ERROR_SUCCESS) { err = uv__new_sys_error(GetLastError()); RegCloseKey(processor_key); - goto out; + goto error; } RegCloseKey(processor_key); - cpu_info = &(*cpu_infos)[i]; + cpu_info = &cpu_infos[i]; cpu_info->speed = cpu_speed; cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000; cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart - @@ -675,57 +683,59 @@ uv_err_t uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) { cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000; cpu_info->cpu_times.nice = 0; - size = uv_utf16_to_utf8(cpu_brand, - cpu_brand_size / sizeof(WCHAR), - NULL, - 0); - if (size == 0) { + + len = WideCharToMultiByte(CP_UTF8, + 0, + cpu_brand, + cpu_brand_size / sizeof(WCHAR), + NULL, + 0, + NULL, + NULL); + if (len == 0) { err = uv__new_sys_error(GetLastError()); - goto out; + goto error; } + assert(len > 0); + /* Allocate 1 extra byte for the null terminator. */ - cpu_info->model = (char*) malloc(size + 1); + cpu_info->model = malloc(len + 1); if (cpu_info->model == NULL) { err = uv__new_artificial_error(UV_ENOMEM); - goto out; + goto error; } - if (uv_utf16_to_utf8(cpu_brand, - cpu_brand_size / sizeof(WCHAR), - cpu_info->model, - size) == 0) { + if (WideCharToMultiByte(CP_UTF8, + 0, + cpu_brand, + cpu_brand_size / sizeof(WCHAR), + cpu_info->model, + len, + NULL, + NULL) == 0) { err = uv__new_sys_error(GetLastError()); - goto out; + goto error; } /* Ensure that cpu_info->model is null terminated. */ - cpu_info->model[size] = '\0'; - - (*count)++; + cpu_info->model[len] = '\0'; } - err = uv_ok_; + free(sppi); - out: - if (sppi) { - free(sppi); - } + *cpu_count_ptr = cpu_count; + *cpu_infos_ptr = cpu_infos; - if (err.code != UV_OK && - *cpu_infos != NULL) { - int i; + return uv_ok_; - for (i = 0; i < *count; i++) { - /* This is safe because the cpu_infos memory area is zeroed out */ - /* immediately after allocating it. */ - free((*cpu_infos)[i].model); - } - free(*cpu_infos); + error: + /* This is safe because the cpu_infos array is zeroed on allocation. */ + for (i = 0; i < cpu_count; i++) + free(cpu_infos[i].model); - *cpu_infos = NULL; - *count = 0; - } + free(cpu_infos); + free(sppi); return err; } diff --git a/src/libuv/src/win/winsock.c b/src/libuv/src/win/winsock.c index 47395bb8..cf6d0318 100644 --- a/src/libuv/src/win/winsock.c +++ b/src/libuv/src/win/winsock.c @@ -79,12 +79,6 @@ static int error_means_no_support(DWORD error) { void uv_winsock_init() { - const GUID wsaid_connectex = WSAID_CONNECTEX; - const GUID wsaid_acceptex = WSAID_ACCEPTEX; - const GUID wsaid_getacceptexsockaddrs = WSAID_GETACCEPTEXSOCKADDRS; - const GUID wsaid_disconnectex = WSAID_DISCONNECTEX; - const GUID wsaid_transmitfile = WSAID_TRANSMITFILE; - WSADATA wsa_data; int errorno; SOCKET dummy; diff --git a/src/libuv/test/runner-unix.c b/src/libuv/test/runner-unix.c index eefb7008..b66df51b 100644 --- a/src/libuv/test/runner-unix.c +++ b/src/libuv/test/runner-unix.c @@ -286,6 +286,34 @@ int process_copy_output(process_info_t *p, int fd) { } +/* Copy the last line of the stdio output buffer to `buffer` */ +int process_read_last_line(process_info_t *p, + char* buffer, + size_t buffer_len) { + char* ptr; + + int r = fseek(p->stdout_file, 0, SEEK_SET); + if (r < 0) { + perror("fseek"); + return -1; + } + + buffer[0] = '\0'; + + while (fgets(buffer, buffer_len, p->stdout_file) != NULL) { + for (ptr = buffer; *ptr && *ptr != '\r' && *ptr != '\n'; ptr++); + *ptr = '\0'; + } + + if (ferror(p->stdout_file)) { + perror("read"); + buffer[0] = '\0'; + return -1; + } + return 0; +} + + /* Return the name that was specified when `p` was started by process_start */ char* process_get_name(process_info_t *p) { return p->name; diff --git a/src/libuv/test/runner-win.c b/src/libuv/test/runner-win.c index 8f534bcd..5d232594 100644 --- a/src/libuv/test/runner-win.c +++ b/src/libuv/test/runner-win.c @@ -44,6 +44,11 @@ /* Do platform-specific initialization. */ void platform_init(int argc, char **argv) { + const char* tap; + + tap = getenv("UV_TAP_OUTPUT"); + tap_output = (tap != NULL && atoi(tap) > 0); + /* Disable the "application crashed" popup. */ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); @@ -207,13 +212,34 @@ long int process_output_size(process_info_t *p) { int process_copy_output(process_info_t *p, int fd) { DWORD read; char buf[1024]; + char *line, *start; if (SetFilePointer(p->stdio_out, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) return -1; + if (tap_output) + write(fd, "#", 1); + while (ReadFile(p->stdio_out, (void*)&buf, sizeof(buf), &read, NULL) && - read > 0) - write(fd, buf, read); + read > 0) { + if (tap_output) { + start = buf; + + while ((line = strchr(start, '\n')) != NULL) { + write(fd, start, line - start + 1); + write(fd, "#", 1); + start = line + 1; + } + + if (start < buf + read) + write(fd, start, buf + read - start); + } else { + write(fd, buf, read); + } + } + + if (tap_output) + write(fd, "\n", 1); if (GetLastError() != ERROR_HANDLE_EOF) return -1; @@ -222,6 +248,46 @@ int process_copy_output(process_info_t *p, int fd) { } +int process_read_last_line(process_info_t *p, + char * buffer, + size_t buffer_len) { + DWORD size; + DWORD read; + DWORD start; + OVERLAPPED overlapped; + + ASSERT(buffer_len > 0); + + size = GetFileSize(p->stdio_out, NULL); + if (size == INVALID_FILE_SIZE) + return -1; + + if (size == 0) { + buffer[0] = '\0'; + return 1; + } + + memset(&overlapped, 0, sizeof overlapped); + if (size >= buffer_len) + overlapped.Offset = size - buffer_len - 1; + + if (!ReadFile(p->stdio_out, buffer, buffer_len - 1, &read, &overlapped)) + return -1; + + for (start = read - 1; start >= 0; start--) { + if (buffer[start] == '\n' || buffer[start] == '\r') + break; + } + + if (start > 0) + memmove(buffer, buffer + start, read - start); + + buffer[read - start] = '\0'; + + return 0; +} + + char* process_get_name(process_info_t *p) { return p->name; } diff --git a/src/libuv/test/runner.c b/src/libuv/test/runner.c index bda1080a..d8e9ddeb 100644 --- a/src/libuv/test/runner.c +++ b/src/libuv/test/runner.c @@ -31,12 +31,25 @@ char executable_path[PATHMAX] = { '\0' }; int tap_output = 0; -static void log_progress(int total, int passed, int failed, const char* name) { +static void log_progress(int total, + int passed, + int failed, + int todos, + int skipped, + const char* name) { + int progress; + if (total == 0) total = 1; - LOGF("[%% %3d|+ %3d|- %3d]: %s", (int) ((passed + failed) / ((double) total) * 100.0), - passed, failed, name); + progress = 100 * (passed + failed + skipped + todos) / total; + LOGF("[%% %3d|+ %3d|- %3d|T %3d|S %3d]: %s", + progress, + passed, + failed, + todos, + skipped, + name); } @@ -78,7 +91,13 @@ const char* fmt(double d) { int run_tests(int timeout, int benchmark_output) { - int total, passed, failed, current; + int total; + int passed; + int failed; + int todos; + int skipped; + int current; + int test_result; task_entry_t* task; /* Count the number of tests. */ @@ -96,6 +115,8 @@ int run_tests(int timeout, int benchmark_output) { /* Run all tests. */ passed = 0; failed = 0; + todos = 0; + skipped = 0; current = 1; for (task = TASKS; task->main; task++) { if (task->is_helper) { @@ -106,13 +127,15 @@ int run_tests(int timeout, int benchmark_output) { rewind_cursor(); if (!benchmark_output && !tap_output) { - log_progress(total, passed, failed, task->task_name); + log_progress(total, passed, failed, todos, skipped, task->task_name); } - if (run_test(task->task_name, timeout, benchmark_output, current) == 0) { - passed++; - } else { - failed++; + test_result = run_test(task->task_name, timeout, benchmark_output, current); + switch (test_result) { + case TEST_OK: passed++; break; + case TEST_TODO: todos++; break; + case TEST_SKIP: skipped++; break; + default: failed++; } current++; } @@ -121,13 +144,50 @@ int run_tests(int timeout, int benchmark_output) { rewind_cursor(); if (!benchmark_output && !tap_output) { - log_progress(total, passed, failed, "Done.\n"); + log_progress(total, passed, failed, todos, skipped, "Done.\n"); } return failed; } +void log_tap_result(int test_count, + const char* test, + int status, + process_info_t* process) { + const char* result; + const char* directive; + char reason[1024]; + + switch (status) { + case TEST_OK: + result = "ok"; + directive = ""; + break; + case TEST_TODO: + result = "not ok"; + directive = " # TODO "; + break; + case TEST_SKIP: + result = "ok"; + directive = " # SKIP "; + break; + default: + result = "not ok"; + directive = ""; + } + + if ((status == TEST_SKIP || status == TEST_TODO) && + process_output_size(process) > 0) { + process_read_last_line(process, reason, sizeof reason); + } else { + reason[0] = '\0'; + } + + LOGF("%s %d - %s%s%s\n", result, test_count, test, directive, reason); +} + + int run_test(const char* test, int timeout, int benchmark_output, @@ -231,7 +291,7 @@ int run_test(const char* test, } status = process_reap(main_proc); - if (status != 0) { + if (status != TEST_OK) { snprintf(errmsg, sizeof errmsg, "exit code %d", @@ -255,17 +315,17 @@ int run_test(const char* test, FATAL("process_wait failed"); } - if (tap_output) { - if (status == 0) - LOGF("ok %d - %s\n", test_count, test); - else - LOGF("not ok %d - %s\n", test_count, test); - } + if (tap_output) + log_tap_result(test_count, test, status, &processes[i]); /* Show error and output from processes if the test failed. */ if (status != 0 || task->show_output) { if (tap_output) { LOGF("#"); + } else if (status == TEST_TODO) { + LOGF("\n`%s` todo\n", test); + } else if (status == TEST_SKIP) { + LOGF("\n`%s` skipped\n", test); } else if (status != 0) { LOGF("\n`%s` failed: %s\n", test, errmsg); } else { diff --git a/src/libuv/test/runner.h b/src/libuv/test/runner.h index 8be9e39f..aa7f2054 100644 --- a/src/libuv/test/runner.h +++ b/src/libuv/test/runner.h @@ -143,6 +143,11 @@ long int process_output_size(process_info_t *p); /* Copy the contents of the stdio output buffer to `fd`. */ int process_copy_output(process_info_t *p, int fd); +/* Copy the last line of the stdio output buffer to `buffer` */ +int process_read_last_line(process_info_t *p, + char * buffer, + size_t buffer_len); + /* Return the name that was specified when `p` was started by process_start */ char* process_get_name(process_info_t *p); diff --git a/src/libuv/test/task.h b/src/libuv/test/task.h index de7c80ec..308201e5 100644 --- a/src/libuv/test/task.h +++ b/src/libuv/test/task.h @@ -119,4 +119,28 @@ void uv_sleep(int msec); /* Format big numbers nicely. WARNING: leaks memory. */ const char* fmt(double d); +/* Reserved test exit codes. */ +enum test_status { + TEST_OK = 0, + TEST_TODO, + TEST_SKIP +}; + +#define RETURN_OK() \ + do { \ + return TEST_OK; \ + } while (0) + +#define RETURN_TODO(explanation) \ + do { \ + LOGF("%s\n", explanation); \ + return TEST_TODO; \ + } while (0) + +#define RETURN_SKIP(explanation) \ + do { \ + LOGF("%s\n", explanation); \ + return TEST_SKIP; \ + } while (0) + #endif /* TASK_H_ */ diff --git a/src/libuv/test/test-fs.c b/src/libuv/test/test-fs.c index 0016b3be..ca2ff2bd 100644 --- a/src/libuv/test/test-fs.c +++ b/src/libuv/test/test-fs.c @@ -1391,7 +1391,8 @@ TEST_IMPL(fs_symlink_dir) { #ifdef _WIN32 ASSERT(((struct stat*)req.ptr)->st_size == strlen(test_dir + 4)); #else - ASSERT(((struct stat*)req.ptr)->st_size == strlen(test_dir)); + /* st_size has type off_t. Cast to avoid signed/unsigned warnings. */ + ASSERT((size_t) ((struct stat*)req.ptr)->st_size == strlen(test_dir)); #endif uv_fs_req_cleanup(&req); diff --git a/src/libuv/test/test-list.h b/src/libuv/test/test-list.h index 2341463a..7a9b1a29 100644 --- a/src/libuv/test/test-list.h +++ b/src/libuv/test/test-list.h @@ -95,9 +95,13 @@ TEST_DECLARE (shutdown_eof) TEST_DECLARE (callback_stack) TEST_DECLARE (error_message) TEST_DECLARE (timer) +TEST_DECLARE (timer_init) TEST_DECLARE (timer_again) TEST_DECLARE (timer_start_twice) TEST_DECLARE (timer_order) +TEST_DECLARE (timer_huge_timeout) +TEST_DECLARE (timer_huge_repeat) +TEST_DECLARE (timer_from_check) TEST_DECLARE (idle_starvation) TEST_DECLARE (loop_handles) TEST_DECLARE (get_loadavg) @@ -217,6 +221,9 @@ TEST_DECLARE (we_get_signal) TEST_DECLARE (we_get_signals) TEST_DECLARE (signal_multiple_loops) #endif +#ifdef __APPLE__ +TEST_DECLARE (osx_select) +#endif HELPER_DECLARE (tcp4_echo_server) HELPER_DECLARE (tcp6_echo_server) HELPER_DECLARE (udp4_echo_server) @@ -336,9 +343,13 @@ TASK_LIST_START TEST_ENTRY (error_message) TEST_ENTRY (timer) + TEST_ENTRY (timer_init) TEST_ENTRY (timer_again) TEST_ENTRY (timer_start_twice) TEST_ENTRY (timer_order) + TEST_ENTRY (timer_huge_timeout) + TEST_ENTRY (timer_huge_repeat) + TEST_ENTRY (timer_from_check) TEST_ENTRY (idle_starvation) @@ -434,6 +445,10 @@ TASK_LIST_START TEST_ENTRY (signal_multiple_loops) #endif +#ifdef __APPLE__ + TEST_ENTRY (osx_select) +#endif + TEST_ENTRY (fs_file_noent) TEST_ENTRY (fs_file_nametoolong) TEST_ENTRY (fs_file_loop) diff --git a/src/libuv/test/test-osx-select.c b/src/libuv/test/test-osx-select.c new file mode 100644 index 00000000..bf4c3952 --- /dev/null +++ b/src/libuv/test/test-osx-select.c @@ -0,0 +1,82 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +#ifdef __APPLE__ + +#include +#include + +static int read_count; + + +static uv_buf_t alloc_cb(uv_handle_t* handle, size_t size) { + static char buf[1024]; + + return uv_buf_init(buf, ARRAY_SIZE(buf)); +} + + +static void read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t buf) { + fprintf(stdout, "got data %d\n", ++read_count); + + if (read_count == 3) + uv_close((uv_handle_t*) stream, NULL); +} + + +TEST_IMPL(osx_select) { + int r; + int fd; + size_t i; + size_t len; + const char* str; + uv_tty_t tty; + + fd = open("/dev/tty", O_RDONLY); + + ASSERT(fd >= 0); + + r = uv_tty_init(uv_default_loop(), &tty, fd, 1); + ASSERT(r == 0); + + uv_read_start((uv_stream_t*) &tty, alloc_cb, read_cb); + + /* Emulate user-input */ + str = "got some input\n" + "with a couple of lines\n" + "feel pretty happy\n"; + for (i = 0, len = strlen(str); i < len; i++) { + r = ioctl(fd, TIOCSTI, str + i); + ASSERT(r == 0); + } + + uv_run(uv_default_loop(), UV_RUN_DEFAULT); + + ASSERT(read_count == 3); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + +#endif /* __APPLE__ */ diff --git a/src/libuv/test/test-process-title.c b/src/libuv/test/test-process-title.c index 13d9dddf..c870abd1 100644 --- a/src/libuv/test/test-process-title.c +++ b/src/libuv/test/test-process-title.c @@ -42,8 +42,12 @@ static void set_title(const char* title) { TEST_IMPL(process_title) { +#if defined(__sun) + RETURN_SKIP("uv_(get|set)_process_title is not implemented."); +#else /* Check for format string vulnerabilities. */ - set_title("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"); + set_title("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"); set_title("new title"); return 0; +#endif } diff --git a/src/libuv/test/test-tcp-writealot.c b/src/libuv/test/test-tcp-writealot.c index 3ddcd6d2..ab8c46ad 100644 --- a/src/libuv/test/test-tcp-writealot.c +++ b/src/libuv/test/test-tcp-writealot.c @@ -26,8 +26,8 @@ #define WRITES 3 -#define CHUNKS_PER_WRITE 3 -#define CHUNK_SIZE 10485760 /* 10 MB */ +#define CHUNKS_PER_WRITE 4096 +#define CHUNK_SIZE 10024 /* 10 kb */ #define TOTAL_BYTES (WRITES * CHUNKS_PER_WRITE * CHUNK_SIZE) diff --git a/src/libuv/test/test-timer-from-check.c b/src/libuv/test/test-timer-from-check.c new file mode 100644 index 00000000..2aa3fe41 --- /dev/null +++ b/src/libuv/test/test-timer-from-check.c @@ -0,0 +1,80 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "uv.h" +#include "task.h" + +static uv_prepare_t prepare_handle; +static uv_check_t check_handle; +static uv_timer_t timer_handle; + +static int prepare_cb_called; +static int check_cb_called; +static int timer_cb_called; + + +static void prepare_cb(uv_prepare_t* handle, int status) { + ASSERT(0 == uv_prepare_stop(&prepare_handle)); + ASSERT(0 == prepare_cb_called); + ASSERT(1 == check_cb_called); + ASSERT(0 == timer_cb_called); + prepare_cb_called++; +} + + +static void timer_cb(uv_timer_t* handle, int status) { + ASSERT(0 == uv_timer_stop(&timer_handle)); + ASSERT(1 == prepare_cb_called); + ASSERT(1 == check_cb_called); + ASSERT(0 == timer_cb_called); + timer_cb_called++; +} + + +static void check_cb(uv_check_t* handle, int status) { + ASSERT(0 == uv_check_stop(&check_handle)); + ASSERT(0 == uv_timer_stop(&timer_handle)); /* Runs before timer_cb. */ + ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 50, 0)); + ASSERT(0 == uv_prepare_start(&prepare_handle, prepare_cb)); + ASSERT(0 == prepare_cb_called); + ASSERT(0 == check_cb_called); + ASSERT(0 == timer_cb_called); + check_cb_called++; +} + + +TEST_IMPL(timer_from_check) { + ASSERT(0 == uv_prepare_init(uv_default_loop(), &prepare_handle)); + ASSERT(0 == uv_check_init(uv_default_loop(), &check_handle)); + ASSERT(0 == uv_check_start(&check_handle, check_cb)); + ASSERT(0 == uv_timer_init(uv_default_loop(), &timer_handle)); + ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 50, 0)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + ASSERT(1 == prepare_cb_called); + ASSERT(1 == check_cb_called); + ASSERT(1 == timer_cb_called); + uv_close((uv_handle_t*) &prepare_handle, NULL); + uv_close((uv_handle_t*) &check_handle, NULL); + uv_close((uv_handle_t*) &timer_handle, NULL); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_ONCE)); + MAKE_VALGRIND_HAPPY(); + return 0; +} diff --git a/src/libuv/test/test-timer.c b/src/libuv/test/test-timer.c index 60b080d2..6aa28897 100644 --- a/src/libuv/test/test-timer.c +++ b/src/libuv/test/test-timer.c @@ -28,8 +28,10 @@ static int once_close_cb_called = 0; static int repeat_cb_called = 0; static int repeat_close_cb_called = 0; static int order_cb_called = 0; - static uint64_t start_time; +static uv_timer_t tiny_timer; +static uv_timer_t huge_timer1; +static uv_timer_t huge_timer2; static void once_close_cb(uv_handle_t* handle) { @@ -156,6 +158,18 @@ TEST_IMPL(timer_start_twice) { } +TEST_IMPL(timer_init) { + uv_timer_t handle; + + ASSERT(0 == uv_timer_init(uv_default_loop(), &handle)); + ASSERT(0 == uv_timer_get_repeat(&handle)); + ASSERT(!uv_is_active((uv_handle_t*)&handle)); + + MAKE_VALGRIND_HAPPY(); + return 0; +} + + static void order_cb_a(uv_timer_t *handle, int status) { ASSERT(order_cb_called++ == *(int*)handle->data); } @@ -200,5 +214,53 @@ TEST_IMPL(timer_order) { ASSERT(order_cb_called == 2); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +static void tiny_timer_cb(uv_timer_t* handle, int status) { + ASSERT(handle == &tiny_timer); + uv_close((uv_handle_t*) &tiny_timer, NULL); + uv_close((uv_handle_t*) &huge_timer1, NULL); + uv_close((uv_handle_t*) &huge_timer2, NULL); +} + + +TEST_IMPL(timer_huge_timeout) { + ASSERT(0 == uv_timer_init(uv_default_loop(), &tiny_timer)); + ASSERT(0 == uv_timer_init(uv_default_loop(), &huge_timer1)); + ASSERT(0 == uv_timer_init(uv_default_loop(), &huge_timer2)); + ASSERT(0 == uv_timer_start(&tiny_timer, tiny_timer_cb, 1, 0)); + ASSERT(0 == uv_timer_start(&huge_timer1, tiny_timer_cb, 0xffffffffffffLL, 0)); + ASSERT(0 == uv_timer_start(&huge_timer2, tiny_timer_cb, (uint64_t) -1, 0)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + MAKE_VALGRIND_HAPPY(); + return 0; +} + + +static void huge_repeat_cb(uv_timer_t* handle, int status) { + static int ncalls; + + if (ncalls == 0) + ASSERT(handle == &huge_timer1); + else + ASSERT(handle == &tiny_timer); + + if (++ncalls == 10) { + uv_close((uv_handle_t*) &tiny_timer, NULL); + uv_close((uv_handle_t*) &huge_timer1, NULL); + } +} + + +TEST_IMPL(timer_huge_repeat) { + ASSERT(0 == uv_timer_init(uv_default_loop(), &tiny_timer)); + ASSERT(0 == uv_timer_init(uv_default_loop(), &huge_timer1)); + ASSERT(0 == uv_timer_start(&tiny_timer, huge_repeat_cb, 2, 2)); + ASSERT(0 == uv_timer_start(&huge_timer1, huge_repeat_cb, 1, (uint64_t) -1)); + ASSERT(0 == uv_run(uv_default_loop(), UV_RUN_DEFAULT)); + MAKE_VALGRIND_HAPPY(); return 0; } diff --git a/src/libuv/test/test-tty.c b/src/libuv/test/test-tty.c index eb5d5df5..c26f7fa9 100644 --- a/src/libuv/test/test-tty.c +++ b/src/libuv/test/test-tty.c @@ -30,6 +30,9 @@ # include #endif +#include +#include + TEST_IMPL(tty) { int r, width, height; @@ -62,7 +65,12 @@ TEST_IMPL(tty) { #else /* unix */ ttyin_fd = open("/dev/tty", O_RDONLY, 0); + if (ttyin_fd < 0) + LOGF("Cannot open /dev/tty as read-only: %s\n", strerror(errno)); + ttyout_fd = open("/dev/tty", O_WRONLY, 0); + if (ttyout_fd < 0) + LOGF("Cannot open /dev/tty as write-only: %s\n", strerror(errno)); #endif ASSERT(ttyin_fd >= 0); @@ -73,10 +81,10 @@ TEST_IMPL(tty) { ASSERT(UV_TTY == uv_guess_handle(ttyin_fd)); ASSERT(UV_TTY == uv_guess_handle(ttyout_fd)); - r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); + r = uv_tty_init(uv_default_loop(), &tty_in, ttyin_fd, 1); /* Readable. */ ASSERT(r == 0); - r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 2); + r = uv_tty_init(uv_default_loop(), &tty_out, ttyout_fd, 0); /* Writable. */ ASSERT(r == 0); r = uv_tty_get_winsize(&tty_out, &width, &height); diff --git a/src/libuv/test/test-udp-send-and-recv.c b/src/libuv/test/test-udp-send-and-recv.c index 37df5b62..1ffa6aa8 100644 --- a/src/libuv/test/test-udp-send-and-recv.c +++ b/src/libuv/test/test-udp-send-and-recv.c @@ -53,6 +53,7 @@ static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size) { static void close_cb(uv_handle_t* handle) { CHECK_HANDLE(handle); + ASSERT(uv_is_closing(handle)); close_cb_called++; } diff --git a/src/libuv/uv.gyp b/src/libuv/uv.gyp index 0810bcc4..f61ebb53 100644 --- a/src/libuv/uv.gyp +++ b/src/libuv/uv.gyp @@ -1,4 +1,13 @@ { + 'variables': { + 'uv_use_dtrace%': 'false', + # uv_parent_path is the relative path to libuv in the parent project + # this is only relevant when dtrace is enabled and libuv is a child project + # as it's necessary to correctly locate the object files for post + # processing. + 'uv_parent_path': '', + }, + 'target_defaults': { 'conditions': [ ['OS != "win"', { @@ -56,6 +65,7 @@ 'src/inet.c', 'src/uv-common.c', 'src/uv-common.h', + 'src/version.c' ], 'conditions': [ [ 'OS=="win"', { @@ -114,7 +124,6 @@ '-pedantic', '-Wall', '-Wextra', - '-Wstrict-aliasing', '-Wno-unused-parameter', ], 'sources': [ @@ -155,9 +164,16 @@ ], }, 'conditions': [ - ['"<(library)" == "shared_library"', { + ['library=="shared_library"', { 'cflags': [ '-fPIC' ], }], + ['library=="shared_library" and OS!="mac"', { + 'link_settings': { + # Must correspond with UV_VERSION_MAJOR and UV_VERSION_MINOR + # in src/version.c + 'libraries': [ '-Wl,-soname,libuv.so.0.10' ], + }, + }], ], }], [ 'OS=="linux" or OS=="mac"', { @@ -167,7 +183,7 @@ 'sources': [ 'src/unix/darwin.c', 'src/unix/fsevents.c', - 'src/unix/darwin-proctitle.m', + 'src/unix/darwin-proctitle.c', ], 'link_settings': { 'libraries': [ @@ -180,6 +196,11 @@ '_DARWIN_USE_64_BIT_INODE=1', ] }], + [ 'OS!="mac"', { + # Enable on all platforms except OS X. The antique gcc/clang that + # ships with Xcode emits waaaay too many false positives. + 'cflags': [ '-Wstrict-aliasing' ], + }], [ 'OS=="linux"', { 'sources': [ 'src/unix/linux-core.c', @@ -221,21 +242,16 @@ }], [ 'OS=="freebsd" or OS=="dragonflybsd"', { 'sources': [ 'src/unix/freebsd.c' ], - 'link_settings': { - 'libraries': [ - '-lkvm', - ], - }, }], [ 'OS=="openbsd"', { 'sources': [ 'src/unix/openbsd.c' ], }], [ 'OS=="netbsd"', { 'sources': [ 'src/unix/netbsd.c' ], + }], + [ 'OS in "freebsd dragonflybsd openbsd netbsd".split()', { 'link_settings': { - 'libraries': [ - '-lkvm', - ], + 'libraries': [ '-lkvm' ], }, }], [ 'OS in "mac freebsd dragonflybsd openbsd netbsd".split()', { @@ -243,7 +259,17 @@ }], ['library=="shared_library"', { 'defines': [ 'BUILDING_UV_SHARED=1' ] - }] + }], + ['uv_use_dtrace=="true"', { + 'defines': [ 'HAVE_DTRACE=1' ], + 'dependencies': [ 'uv_dtrace_header' ], + 'include_dirs': [ '<(SHARED_INTERMEDIATE_DIR)' ], + 'conditions': [ + ['OS != "mac"', { + 'sources': ['src/unix/dtrace.c' ], + }], + ], + }], ] }, @@ -285,6 +311,7 @@ 'test/test-loop-stop.c', 'test/test-walk-handles.c', 'test/test-multiple-listen.c', + 'test/test-osx-select.c', 'test/test-pass-always.c', 'test/test-ping-pong.c', 'test/test-pipe-bind-error.c', @@ -326,6 +353,7 @@ 'test/test-barrier.c', 'test/test-condvar.c', 'test/test-timer-again.c', + 'test/test-timer-from-check.c', 'test/test-timer.c', 'test/test-tty.c', 'test/test-udp-dgram-too-big.c', @@ -421,8 +449,48 @@ 'SubSystem': 1, # /subsystem:console }, }, - } - ] -} + }, + { + 'target_name': 'uv_dtrace_header', + 'type': 'none', + 'conditions': [ + [ 'uv_use_dtrace=="true"', { + 'actions': [ + { + 'action_name': 'uv_dtrace_header', + 'inputs': [ 'src/unix/uv-dtrace.d' ], + 'outputs': [ '<(SHARED_INTERMEDIATE_DIR)/uv-dtrace.h' ], + 'action': [ 'dtrace', '-h', '-xnolibs', '-s', '<@(_inputs)', + '-o', '<@(_outputs)' ], + }, + ], + }], + ], + }, + { + 'target_name': 'uv_dtrace_provider', + 'type': 'none', + 'conditions': [ + [ 'uv_use_dtrace=="true" and OS!="mac"', { + 'actions': [ + { + 'action_name': 'uv_dtrace_o', + 'inputs': [ + 'src/unix/uv-dtrace.d', + '<(PRODUCT_DIR)/obj.target/libuv/<(uv_parent_path)/src/unix/core.o', + ], + 'outputs': [ + '<(PRODUCT_DIR)/obj.target/libuv/<(uv_parent_path)/src/unix/dtrace.o', + ], + 'action': [ 'dtrace', '-G', '-xnolibs', '-s', '<@(_inputs)', + '-o', '<@(_outputs)' ] + } + ] + } ] + ] + }, + + ] +} diff --git a/src/libuv/vcbuild.bat b/src/libuv/vcbuild.bat index 2165bda5..1b2f865a 100644 --- a/src/libuv/vcbuild.bat +++ b/src/libuv/vcbuild.bat @@ -41,6 +41,14 @@ shift goto next-arg :args-done +@rem Look for Visual Studio 2012 +if not defined VS110COMNTOOLS goto vc-set-2010 +if not exist "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2010 +call "%VS110COMNTOOLS%\..\..\vc\vcvarsall.bat" %vs_toolset% +set GYP_MSVS_VERSION=2012 +goto select-target + +:vc-set-2010 @rem Look for Visual Studio 2010 if not defined VS100COMNTOOLS goto vc-set-2008 if not exist "%VS100COMNTOOLS%\..\..\vc\vcvarsall.bat" goto vc-set-2008