Compare commits

...

23 Commits
v1.x ... v0.10

Author SHA1 Message Date
Saúl Ibarra Corretgé
74afcb33e2 Now working on v0.10.38 2016-06-13 23:48:46 +02:00
Saúl Ibarra Corretgé
b38158dc47 2016.06.14, Version 0.10.37 (Stable)
Changes since version 0.10.36:

* build: update the location of gyp (Stephen von Takach)

* linux: fix epoll_pwait() fallback on arm64 (Ben Noordhuis)

* test: fix fs_chown when running as root (Ben Noordhuis)

* tests: skip some tests when network is unreachable (Luca Bruno)

* unix: do not discard environmental LDFLAGS (Luca Bruno)

* src: replace ngx_queue_split with ngx_queue_move (Ben Noordhuis)

* unix: use ngx_queue_move when iterating over lists (Ben Noordhuis)

* win: fix unsavory rwlock fallback implementation (Bert Belder)

* unix: map ENFILE errno (Saúl Ibarra Corretgé)

* doc: add note indicating branch status (Saúl Ibarra Corretgé)
2016-06-13 23:48:39 +02:00
Saúl Ibarra Corretgé
7efe7d1dc3 doc: add note indicating branch status
PR-URL: https://github.com/libuv/libuv/pull/905
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
2016-06-11 12:26:01 +02:00
Saúl Ibarra Corretgé
c447d9058c unix: map ENFILE errno
Fixes: https://github.com/libuv/libuv/issues/899
PR-URL: https://github.com/libuv/libuv/pull/904
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
2016-06-11 10:02:28 +02:00
Bert Belder
d4ff8fd5c1 win: fix unsavory rwlock fallback implementation
Before this patch an uv_mutex_t (backed by a critical section) could be
released by a tread different from the thread that acquired it, which is
not allowed. This is fixed by using a semaphore instead.

Note that the affected code paths were used on Windows XP and Windows
Server 2003 only.

This is a back-port of commits 3eb6764, 1ad6ad7, 9a4fd26, 9823922
85adf43 and bd1777f from the v1.x branch.

Fixes: https://github.com/libuv/libuv/issues/515
Refs: https://github.com/libuv/libuv/pull/525
PR-URL: https://github.com/libuv/libuv/pull/903
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Bert Belder <bertbelder@gmail.com>
2016-06-11 09:59:32 +02:00
Ben Noordhuis
65223248da unix: use ngx_queue_move when iterating over lists
Replace uses of ngx_queue_foreach when the list can get modified while
iterating over it, in particular when a callback is made into the
user's code.  This should fix a number of spurious failures that
people have been reporting.

This is a backport of commit 442b8a5 from the v1.x branch.

PR-URL: https://github.com/libuv/libuv/pull/566
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
2015-10-12 01:54:29 +02:00
Ben Noordhuis
82f025e036 src: replace ngx_queue_split with ngx_queue_move
All uses of ngx_queue_split in libuv split the list at the head so
introduce a ngx_queue_move macro that automates that.

This is a backport of commit 1867a6c from the v1.x branch.

PR-URL: https://github.com/libuv/libuv/pull/566
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
2015-10-12 01:54:02 +02:00
Luca Bruno
cbc83c6d0c unix: do not discard environmental LDFLAGS
The build environment may carry additional global LDFLAGS, which
are currently being discarded.
Debian uses them for distro-wide hardening, see dpkg-buildflags(1).
Fix by not overwriting the variable.

Signed-off-by: Luca Bruno <lucab@debian.org>

PR-URL: https://github.com/libuv/libuv/pull/447
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
2015-07-20 09:43:01 +02:00
Luca Bruno
fa0fa2fac4 tests: skip some tests when network is unreachable
Do not hard-fail network tests when libuv is built on
an isolated host/container.

This is a backport of 5df06b3 (v1.x)

Signed-off-by: Luca Bruno <lucab@debian.org>

PR-URL: https://github.com/libuv/libuv/pull/441
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
2015-07-15 19:41:49 +02:00
Ben Noordhuis
8af26a7b84 test: fix fs_chown when running as root
chown(2) to root is expected to fail - unless you're root, of course.

This is a backport of d0be852 (v1.x)

PR-URL: https://github.com/libuv/libuv/pull/441
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
2015-07-15 19:41:20 +02:00
Ben Noordhuis
8f931a229a linux: fix epoll_pwait() fallback on arm64
arm64 doesn't have a epoll_wait() system call but a logic error stopped
libuv from falling back to epoll_pwait().

This bug was introduced in commit 67bb2b5 ("linux: fix epoll_pwait()
regression with < 2.6.19") which sadly exchanged one regression for
another.

This is a backport of 1d8332f (v1.x)

PR-URL: https://github.com/libuv/libuv/pull/308
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
2015-05-06 22:28:25 +02:00
Stephen von Takach
b52d74e21b build: update the location of gyp
Google moved the repository

Cherry-picked from v1.x (5abb33d)

PR-URL: https://github.com/libuv/libuv/pull/240
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
2015-03-03 10:18:46 +01:00
Saúl Ibarra Corretgé
84fe1e744a Now working on v0.10.37 2015-02-26 11:23:29 +01:00
Saúl Ibarra Corretgé
cc4d42a89a 2015.02.27, Version 0.10.36 (Stable)
Changes since version 0.10.35:

* stream: ignore EINVAL for SO_OOBINLINE on OS X (Fedor Indutny)
2015-02-26 11:23:25 +01:00
Fedor Indutny
e28a5d55ba stream: ignore EINVAL for SO_OOBINLINE on OS X
Calling `setsockopt()` on shutdown fds/stdio will result in EINVAL.
There is not much problem here as the OOB data can't be sent to already
shutdown fds. Just ignore it and go on.

Cherry-picked from v1.x (19d3d50)

PR-URL: https://github.com/libuv/libuv/pull/228
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Bert Belder <bertbelder@gmail.com>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
2015-02-26 11:22:34 +01:00
Saúl Ibarra Corretgé
2797aa329e Now working on v0.10.36 2015-02-24 21:29:30 +01:00
Saúl Ibarra Corretgé
4dc978825d 2015.02.25, Version 0.10.35 (Stable)
Changes since version 0.10.34:

* stream: use SO_OOBINLINE on OS X (Fedor Indutny)
2015-02-24 21:29:25 +01:00
Fedor Indutny
5c274ae47b stream: use SO_OOBINLINE on OS X
In the collaboration with Ben Noordhuis <info@bnoordhuis.nl> and
Saúl Ibarra Corretgé <saghul@gmail.com>.

Cherry-picked from v1.x (e19089f)

Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
2015-02-24 21:18:40 +01:00
Saúl Ibarra Corretgé
80b6f6912f Now working on v0.10.35 2015-02-20 18:31:21 +01:00
Saúl Ibarra Corretgé
37aa4aa9b9 2015.02.21, Version 0.10.34 (Stable)
Changes since version 0.10.33:

* unix: add atomic-ops.h (Ben Noordhuis)

* unix: fix for uv_async data race (Michael Penick)

* unix: call setgoups before calling setuid/setgid (Saúl Ibarra
  Corretgé)
2015-02-20 18:31:15 +01:00
Saúl Ibarra Corretgé
2773e1181d unix: call setgoups before calling setuid/setgid
Backported from v1.x (66ab389)

PR-URL: https://github.com/libuv/libuv/pull/215
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
2015-02-20 08:09:07 +01:00
Michael Penick
22725f2433 unix: fix for uv_async data race
There's a data race in the consuming side of uv_async. The "pending"
flag could be trampled by producing thread causing an async send event
to be missed.

PR-URL: https://github.com/libuv/libuv/pull/197
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
2015-02-11 22:32:26 +01:00
Ben Noordhuis
91d3598475 unix: add atomic-ops.h
Add cmpxchgi(), cmpxchgl() and cpu_relax() functions that we can use
as simple primitives to build spinlocks out of.

PR-URL: https://github.com/libuv/libuv/pull/197
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>

[NB: This is a back-port of commit a3c3b37 from the v1.x branch.]
2015-02-11 22:30:38 +01:00
37 changed files with 560 additions and 333 deletions

View File

@ -134,3 +134,5 @@ Michael Hudson-Doyle <michael.hudson@linaro.org>
Helge Deller <deller@gmx.de> Helge Deller <deller@gmx.de>
Logan Rosen <loganrosen@gmail.com> Logan Rosen <loganrosen@gmail.com>
Kenneth Perry <thothonegan@gmail.com> Kenneth Perry <thothonegan@gmail.com>
Michael Penick <michael.penick@datastax.com>
Stephen von Takach <steve@advancedcontrol.com.au>

View File

@ -1,3 +1,53 @@
2016.06.14, Version 0.10.37 (Stable), b38158dc473f1534c5a819e6a8afa76d0657ffa5
Changes since version 0.10.36:
* build: update the location of gyp (Stephen von Takach)
* linux: fix epoll_pwait() fallback on arm64 (Ben Noordhuis)
* test: fix fs_chown when running as root (Ben Noordhuis)
* tests: skip some tests when network is unreachable (Luca Bruno)
* unix: do not discard environmental LDFLAGS (Luca Bruno)
* src: replace ngx_queue_split with ngx_queue_move (Ben Noordhuis)
* unix: use ngx_queue_move when iterating over lists (Ben Noordhuis)
* win: fix unsavory rwlock fallback implementation (Bert Belder)
* unix: map ENFILE errno (Saúl Ibarra Corretgé)
* doc: add note indicating branch status (Saúl Ibarra Corretgé)
2015.02.27, Version 0.10.36 (Stable), cc4d42a89a2a0ae0ff8e14321de086eba3c3b4ca
Changes since version 0.10.35:
* stream: ignore EINVAL for SO_OOBINLINE on OS X (Fedor Indutny)
2015.02.25, Version 0.10.35 (Stable), 4dc978825d870643bbaa4660f71d22975efba29e
Changes since version 0.10.34:
* stream: use SO_OOBINLINE on OS X (Fedor Indutny)
2015.02.21, Version 0.10.34 (Stable), 37aa4aa9b9712c778d7b249563e868cabfdb8332
Changes since version 0.10.33:
* unix: add atomic-ops.h (Ben Noordhuis)
* unix: fix for uv_async data race (Michael Penick)
* unix: call setgoups before calling setuid/setgid (Saúl Ibarra Corretgé)
2015.01.29, Version 0.10.33 (Stable), 7a2253d33ad8215a26c1b34f1952aee7242dd687 2015.01.29, Version 0.10.33 (Stable), 7a2253d33ad8215a26c1b34f1952aee7242dd687
Changes since version 0.10.32: Changes since version 0.10.32:

View File

@ -6,6 +6,9 @@ eventually contain all platform differences in this library.
http://nodejs.org/ http://nodejs.org/
**This branch only receives security fixes and will be EOL'd by the end of 2016,
please switch to version v1.x**
## Features ## Features
* Non-blocking TCP sockets * Non-blocking TCP sockets
@ -81,13 +84,7 @@ To have GYP generate build script for another system, make sure that
you have Python 2.6 or 2.7 installed, then checkout GYP into the you have Python 2.6 or 2.7 installed, then checkout GYP into the
project tree manually: project tree manually:
mkdir -p build git clone https://chromium.googlesource.com/external/gyp.git build/gyp
svn co http://gyp.googlecode.com/svn/trunk build/gyp
Or:
mkdir -p build
git clone https://git.chromium.org/external/gyp.git build/gyp
Unix users run Unix users run

View File

@ -127,6 +127,7 @@ TESTS= \
test/test-tcp-connect-timeout.o \ test/test-tcp-connect-timeout.o \
test/test-tcp-flags.o \ test/test-tcp-flags.o \
test/test-tcp-open.o \ test/test-tcp-open.o \
test/test-tcp-oob.o \
test/test-tcp-read-stop.o \ test/test-tcp-read-stop.o \
test/test-tcp-shutdown-after-write.o \ test/test-tcp-shutdown-after-write.o \
test/test-tcp-unexpected-read.o \ test/test-tcp-unexpected-read.o \

View File

@ -145,6 +145,7 @@ test/test-tcp-open.c
test/test-tcp-read-stop.c test/test-tcp-read-stop.c
test/test-tcp-shutdown-after-write.c test/test-tcp-shutdown-after-write.c
test/test-tcp-unexpected-read.c test/test-tcp-unexpected-read.c
test/test-tcp-oob.c
test/test-tcp-write-error.c test/test-tcp-write-error.c
test/test-tcp-write-to-half-open-connection.c test/test-tcp-write-to-half-open-connection.c
test/test-tcp-writealot.c test/test-tcp-writealot.c

View File

@ -22,7 +22,7 @@ E=
CSTDFLAG=--std=c89 -pedantic -Wall -Wextra -Wno-unused-parameter CSTDFLAG=--std=c89 -pedantic -Wall -Wextra -Wno-unused-parameter
CFLAGS += -g CFLAGS += -g
CPPFLAGS += -I$(SRCDIR)/src CPPFLAGS += -I$(SRCDIR)/src
LDFLAGS=-lm -pthread LDFLAGS += -lm -pthread
CPPFLAGS += -D_LARGEFILE_SOURCE CPPFLAGS += -D_LARGEFILE_SOURCE
CPPFLAGS += -D_FILE_OFFSET_BITS=64 CPPFLAGS += -D_FILE_OFFSET_BITS=64
@ -186,7 +186,7 @@ src/.buildstamp src/unix/.buildstamp test/.buildstamp:
mkdir -p $(@D) mkdir -p $(@D)
touch $@ 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 $(DTRACE_HEADER) src/unix/%.o src/unix/%.pic.o: src/unix/%.c include/uv.h include/uv-private/uv-unix.h src/unix/atomic-ops.h src/unix/internal.h src/unix/.buildstamp $(DTRACE_HEADER)
$(CC) $(CSTDFLAG) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ $(CC) $(CSTDFLAG) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
src/%.o src/%.pic.o: src/%.c include/uv.h include/uv-private/uv-unix.h src/.buildstamp src/%.o src/%.pic.o: src/%.c include/uv.h include/uv-private/uv-unix.h src/.buildstamp

View File

@ -106,6 +106,17 @@ struct ngx_queue_s {
while (0) while (0)
#define ngx_queue_move(h, n) \
do { \
if (ngx_queue_empty(h)) \
ngx_queue_init(n); \
else { \
ngx_queue_t* q = ngx_queue_head(h); \
ngx_queue_split(h, q, n); \
} \
} \
while (0)
#define ngx_queue_add(h, n) \ #define ngx_queue_add(h, n) \
do { \ do { \
(h)->prev->next = (n)->next; \ (h)->prev->next = (n)->next; \
@ -120,6 +131,9 @@ struct ngx_queue_s {
((type *) ((unsigned char *) q - offsetof(type, link))) ((type *) ((unsigned char *) q - offsetof(type, link)))
/* Important note: mutating the list while ngx_queue_foreach is
* iterating over its elements results in undefined behavior.
*/
#define ngx_queue_foreach(q, h) \ #define ngx_queue_foreach(q, h) \
for ((q) = ngx_queue_head(h); \ for ((q) = ngx_queue_head(h); \
(q) != ngx_queue_sentinel(h) && !ngx_queue_empty(h); \ (q) != ngx_queue_sentinel(h) && !ngx_queue_empty(h); \

View File

@ -235,14 +235,20 @@ typedef union {
} uv_cond_t; } uv_cond_t;
typedef union { typedef union {
/* srwlock_ has type SRWLOCK, but not all toolchains define this type in */
/* windows.h. */
SRWLOCK srwlock_;
struct { struct {
uv_mutex_t read_mutex_;
uv_mutex_t write_mutex_;
unsigned int num_readers_; unsigned int num_readers_;
} fallback_; CRITICAL_SECTION num_readers_lock_;
HANDLE write_semaphore_;
} state_;
/* TODO: remove me in v2.x. */
struct {
SRWLOCK unused_;
} unused1_;
/* TODO: remove me in v2.x. */
struct {
uv_mutex_t unused1_;
uv_mutex_t unused2_;
} unused2_;
} uv_rwlock_t; } uv_rwlock_t;
typedef struct { typedef struct {

View File

@ -24,6 +24,7 @@
#include "uv.h" #include "uv.h"
#include "internal.h" #include "internal.h"
#include "atomic-ops.h"
#include <errno.h> #include <errno.h>
#include <assert.h> #include <assert.h>
@ -34,7 +35,6 @@
static void uv__async_event(uv_loop_t* loop, static void uv__async_event(uv_loop_t* loop,
struct uv__async* w, struct uv__async* w,
unsigned int nevents); unsigned int nevents);
static int uv__async_make_pending(int* pending);
static int uv__async_eventfd(void); static int uv__async_eventfd(void);
@ -54,7 +54,11 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
int uv_async_send(uv_async_t* handle) { int uv_async_send(uv_async_t* handle) {
if (uv__async_make_pending(&handle->pending) == 0) /* Do a cheap read first. */
if (ACCESS_ONCE(int, handle->pending) != 0)
return 0;
if (cmpxchgi(&handle->pending, 0, 1) == 0)
uv__async_send(&handle->loop->async_watcher); uv__async_send(&handle->loop->async_watcher);
return 0; return 0;
@ -70,49 +74,26 @@ void uv__async_close(uv_async_t* handle) {
static void uv__async_event(uv_loop_t* loop, static void uv__async_event(uv_loop_t* loop,
struct uv__async* w, struct uv__async* w,
unsigned int nevents) { unsigned int nevents) {
ngx_queue_t queue;
ngx_queue_t* q; ngx_queue_t* q;
uv_async_t* h; uv_async_t* h;
ngx_queue_foreach(q, &loop->async_handles) { ngx_queue_move(&loop->async_handles, &queue);
while (!ngx_queue_empty(&queue)) {
q = ngx_queue_head(&queue);
h = ngx_queue_data(q, uv_async_t, queue); h = ngx_queue_data(q, uv_async_t, queue);
if (!h->pending) continue;
h->pending = 0; ngx_queue_remove(q);
ngx_queue_insert_tail(&loop->async_handles, q);
if (cmpxchgi(&h->pending, 1, 0) == 0)
continue;
h->async_cb(h, 0); h->async_cb(h, 0);
} }
} }
static int uv__async_make_pending(int* pending) {
/* Do a cheap read first. */
if (ACCESS_ONCE(int, *pending) != 0)
return 1;
/* Micro-optimization: use atomic memory operations to detect if we've been
* preempted by another thread and don't have to make an expensive syscall.
* This speeds up the heavily contended case by about 1-2% and has little
* if any impact on the non-contended case.
*
* Use XCHG instead of the CMPXCHG that __sync_val_compare_and_swap() emits
* on x86, it's about 4x faster. It probably makes zero difference in the
* grand scheme of things but I'm OCD enough not to let this one pass.
*/
#if defined(__i386__) || defined(__x86_64__)
{
unsigned int val = 1;
__asm__ __volatile__ ("xchgl %0, %1"
: "+r" (val)
: "m" (*pending));
return val != 0;
}
#elif defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ > 0)
return __sync_val_compare_and_swap(pending, 0, 1) != 0;
#else
ACCESS_ONCE(int, *pending) = 1;
return 0;
#endif
}
static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) { static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
struct uv__async* wa; struct uv__async* wa;
char buf[1024]; char buf[1024];

60
src/unix/atomic-ops.h Normal file
View File

@ -0,0 +1,60 @@
/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef UV_ATOMIC_OPS_H_
#define UV_ATOMIC_OPS_H_
#include "internal.h" /* UV_UNUSED */
UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval));
UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval));
UV_UNUSED(static void cpu_relax(void));
/* Prefer hand-rolled assembly over the gcc builtins because the latter also
* issue full memory barriers.
*/
UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
#if defined(__i386__) || defined(__x86_64__)
int out;
__asm__ __volatile__ ("lock; cmpxchg %2, %1;"
: "=a" (out), "+m" (*(volatile int*) ptr)
: "r" (newval), "0" (oldval)
: "memory");
return out;
#else
return __sync_val_compare_and_swap(ptr, oldval, newval);
#endif
}
UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) {
#if defined(__i386__) || defined(__x86_64__)
long out;
__asm__ __volatile__ ("lock; cmpxchg %2, %1;"
: "=a" (out), "+m" (*(volatile long*) ptr)
: "r" (newval), "0" (oldval)
: "memory");
return out;
#else
return __sync_val_compare_and_swap(ptr, oldval, newval);
#endif
}
UV_UNUSED(static void cpu_relax(void)) {
#if defined(__i386__) || defined(__x86_64__)
__asm__ __volatile__ ("rep; nop"); /* a.k.a. PAUSE */
#endif
}
#endif /* UV_ATOMIC_OPS_H_ */

View File

@ -133,15 +133,12 @@ static void uv__cf_loop_cb(void* arg) {
loop = arg; loop = arg;
uv_mutex_lock(&loop->cf_mutex); uv_mutex_lock(&loop->cf_mutex);
ngx_queue_init(&split_head); ngx_queue_move(&loop->cf_signals, &split_head);
if (!ngx_queue_empty(&loop->cf_signals)) {
ngx_queue_t* split_pos = ngx_queue_next(&loop->cf_signals);
ngx_queue_split(&loop->cf_signals, split_pos, &split_head);
}
uv_mutex_unlock(&loop->cf_mutex); uv_mutex_unlock(&loop->cf_mutex);
while (!ngx_queue_empty(&split_head)) { while (!ngx_queue_empty(&split_head)) {
item = ngx_queue_head(&split_head); item = ngx_queue_head(&split_head);
ngx_queue_remove(item);
s = ngx_queue_data(item, uv__cf_loop_signal_t, member); s = ngx_queue_data(item, uv__cf_loop_signal_t, member);
@ -151,7 +148,6 @@ static void uv__cf_loop_cb(void* arg) {
else else
s->cb(s->arg); s->cb(s->arg);
ngx_queue_remove(item);
free(s); free(s);
} }
} }

View File

@ -110,6 +110,7 @@ uv_err_code uv_translate_sys_error(int sys_errno) {
case ERANGE: return UV_ERANGE; case ERANGE: return UV_ERANGE;
case ENXIO: return UV_ENXIO; case ENXIO: return UV_ENXIO;
case EMLINK: return UV_EMLINK; case EMLINK: return UV_EMLINK;
case ENFILE: return UV_ENFILE;
default: return UV_UNKNOWN; default: return UV_UNKNOWN;
} }
UNREACHABLE(); UNREACHABLE();

View File

@ -55,11 +55,7 @@ struct uv__fsevents_event_s {
ngx_queue_t split_head; \ ngx_queue_t split_head; \
uv__fsevents_event_t* event; \ uv__fsevents_event_t* event; \
uv_mutex_lock(&(handle)->cf_mutex); \ uv_mutex_lock(&(handle)->cf_mutex); \
ngx_queue_init(&split_head); \ ngx_queue_move(&(handle)->cf_events, &split_head); \
if (!ngx_queue_empty(&(handle)->cf_events)) { \
ngx_queue_t* split_pos = ngx_queue_next(&(handle)->cf_events); \
ngx_queue_split(&(handle)->cf_events, split_pos, &split_head); \
} \
uv_mutex_unlock(&(handle)->cf_mutex); \ uv_mutex_unlock(&(handle)->cf_mutex); \
while (!ngx_queue_empty(&split_head)) { \ while (!ngx_queue_empty(&split_head)) { \
curr = ngx_queue_head(&split_head); \ curr = ngx_queue_head(&split_head); \

View File

@ -66,6 +66,21 @@
} \ } \
while (0) while (0)
/* The __clang__ and __INTEL_COMPILER checks are superfluous because they
* define __GNUC__. They are here to convey to you, dear reader, that these
* macros are enabled when compiling with clang or icc.
*/
#if defined(__clang__) || \
defined(__GNUC__) || \
defined(__INTEL_COMPILER) || \
defined(__SUNPRO_C)
# define UV_DESTRUCTOR(declaration) __attribute__((destructor)) declaration
# define UV_UNUSED(declaration) __attribute__((unused)) declaration
#else
# define UV_DESTRUCTOR(declaration) declaration
# define UV_UNUSED(declaration) declaration
#endif
#if defined(__linux__) #if defined(__linux__)
# define UV__POLLIN UV__EPOLLIN # define UV__POLLIN UV__EPOLLIN
# define UV__POLLOUT UV__EPOLLOUT # define UV__POLLOUT UV__EPOLLOUT

View File

@ -199,7 +199,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (pthread_sigmask(SIG_BLOCK, &sigset, NULL)) if (pthread_sigmask(SIG_BLOCK, &sigset, NULL))
abort(); abort();
if (sigmask != 0 && no_epoll_pwait == 0) { if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) {
nfds = uv__epoll_pwait(loop->backend_fd, nfds = uv__epoll_pwait(loop->backend_fd,
events, events,
ARRAY_SIZE(events), ARRAY_SIZE(events),

View File

@ -119,6 +119,7 @@ static void uv__inotify_read(uv_loop_t* loop,
const struct uv__inotify_event* e; const struct uv__inotify_event* e;
struct watcher_list* w; struct watcher_list* w;
uv_fs_event_t* h; uv_fs_event_t* h;
ngx_queue_t queue;
ngx_queue_t* q; ngx_queue_t* q;
const char* path; const char* path;
ssize_t size; ssize_t size;
@ -158,8 +159,14 @@ static void uv__inotify_read(uv_loop_t* loop,
*/ */
path = e->len ? (const char*) (e + 1) : basename_r(w->path); path = e->len ? (const char*) (e + 1) : basename_r(w->path);
ngx_queue_foreach(q, &w->watchers) { ngx_queue_move(&w->watchers, &queue);
while (!ngx_queue_empty(&queue)) {
q = ngx_queue_head(&queue);
h = ngx_queue_data(q, uv_fs_event_t, watchers); h = ngx_queue_data(q, uv_fs_event_t, watchers);
ngx_queue_remove(q);
ngx_queue_insert_tail(&w->watchers, q);
h->cb(h, path, events, 0); h->cb(h, path, events, 0);
} }
} }

View File

@ -48,9 +48,14 @@
\ \
void uv__run_##name(uv_loop_t* loop) { \ void uv__run_##name(uv_loop_t* loop) { \
uv_##name##_t* h; \ uv_##name##_t* h; \
ngx_queue_t queue; \
ngx_queue_t* q; \ ngx_queue_t* q; \
ngx_queue_foreach(q, &loop->name##_handles) { \ ngx_queue_move(&loop->name##_handles, &queue); \
while (!ngx_queue_empty(&queue)) { \
q = ngx_queue_head(&queue); \
h = ngx_queue_data(q, uv_##name##_t, queue); \ h = ngx_queue_data(q, uv_##name##_t, queue); \
ngx_queue_remove(q); \
ngx_queue_insert_tail(&loop->name##_handles, q); \
h->name##_cb(h, 0); \ h->name##_cb(h, 0); \
} \ } \
} \ } \

View File

@ -40,6 +40,10 @@
extern char **environ; extern char **environ;
#endif #endif
#ifdef __linux__
# include <grp.h>
#endif
static ngx_queue_t* uv__process_queue(uv_loop_t* loop, int pid) { static ngx_queue_t* uv__process_queue(uv_loop_t* loop, int pid) {
assert(pid > 0); assert(pid > 0);
@ -331,6 +335,17 @@ static void uv__process_child_init(uv_process_options_t options,
_exit(127); _exit(127);
} }
if (options.flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) {
/* When dropping privileges from root, the `setgroups` call will
* remove any extraneous groups. If we don't call this, then
* even though our uid has dropped, we may still have groups
* that enable us to do super-user things. This will fail if we
* aren't root, so don't bother checking the return value, this
* is just done as an optimistic privilege dropping function.
*/
SAVE_ERRNO(setgroups(0, NULL));
}
if ((options.flags & UV_PROCESS_SETGID) && setgid(options.gid)) { if ((options.flags & UV_PROCESS_SETGID) && setgid(options.gid)) {
uv__write_int(error_fd, errno); uv__write_int(error_fd, errno);
_exit(127); _exit(127);

View File

@ -231,6 +231,8 @@ void uv__signal_loop_cleanup(uv_loop_t* loop) {
/* Stop all the signal watchers that are still attached to this loop. This /* Stop all the signal watchers that are still attached to this loop. This
* ensures that the (shared) signal tree doesn't contain any invalid entries * ensures that the (shared) signal tree doesn't contain any invalid entries
* entries, and that signal handlers are removed when appropriate. * entries, and that signal handlers are removed when appropriate.
* It's safe to use QUEUE_FOREACH here because the handles and the handle
* queue are not modified by uv__signal_stop().
*/ */
ngx_queue_foreach(q, &loop->handle_queue) { ngx_queue_foreach(q, &loop->handle_queue) {
uv_handle_t* handle = ngx_queue_data(q, uv_handle_t, handle_queue); uv_handle_t* handle = ngx_queue_data(q, uv_handle_t, handle_queue);

View File

@ -403,6 +403,10 @@ failed_malloc:
int uv__stream_open(uv_stream_t* stream, int fd, int flags) { int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
#if defined(__APPLE__)
int enable;
#endif
assert(fd >= 0); assert(fd >= 0);
stream->flags |= flags; stream->flags |= flags;
@ -415,6 +419,15 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
return uv__set_sys_error(stream->loop, errno); return uv__set_sys_error(stream->loop, errno);
} }
#if defined(__APPLE__)
enable = 1;
if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) &&
errno != ENOTSOCK &&
errno != EINVAL) {
return uv__set_sys_error(stream->loop, errno);
}
#endif
stream->io_watcher.fd = fd; stream->io_watcher.fd = fd;
return 0; return 0;

View File

@ -84,12 +84,11 @@ int uv_mutex_trylock(uv_mutex_t* mutex) {
r = pthread_mutex_trylock(mutex); r = pthread_mutex_trylock(mutex);
if (r && r != EBUSY && r != EAGAIN) if (r) {
if (r != EBUSY && r != EAGAIN)
abort(); abort();
if (r)
return -1; return -1;
else }
return 0; return 0;
} }
@ -125,12 +124,11 @@ int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
r = pthread_rwlock_tryrdlock(rwlock); r = pthread_rwlock_tryrdlock(rwlock);
if (r && r != EBUSY && r != EAGAIN) if (r) {
if (r != EBUSY && r != EAGAIN)
abort(); abort();
if (r)
return -1; return -1;
else }
return 0; return 0;
} }
@ -152,12 +150,11 @@ int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
r = pthread_rwlock_trywrlock(rwlock); r = pthread_rwlock_trywrlock(rwlock);
if (r && r != EBUSY && r != EAGAIN) if (r) {
if (r != EBUSY && r != EAGAIN)
abort(); abort();
if (r)
return -1; return -1;
else }
return 0; return 0;
} }

View File

@ -202,13 +202,8 @@ void uv__work_done(uv_async_t* handle, int status) {
int err; int err;
loop = container_of(handle, uv_loop_t, wq_async); loop = container_of(handle, uv_loop_t, wq_async);
ngx_queue_init(&wq);
uv_mutex_lock(&loop->wq_mutex); uv_mutex_lock(&loop->wq_mutex);
if (!ngx_queue_empty(&loop->wq)) { ngx_queue_move(&loop->wq, &wq);
q = ngx_queue_head(&loop->wq);
ngx_queue_split(&loop->wq, q, &wq);
}
uv_mutex_unlock(&loop->wq_mutex); uv_mutex_unlock(&loop->wq_mutex);
while (!ngx_queue_empty(&wq)) { while (!ngx_queue_empty(&wq)) {

View File

@ -362,11 +362,18 @@ unsigned long uv_thread_self(void) {
void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) { void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
ngx_queue_t queue;
ngx_queue_t* q; ngx_queue_t* q;
uv_handle_t* h; uv_handle_t* h;
ngx_queue_foreach(q, &loop->handle_queue) { ngx_queue_move(&loop->handle_queue, &queue);
while (!ngx_queue_empty(&queue)) {
q = ngx_queue_head(&queue);
h = ngx_queue_data(q, uv_handle_t, handle_queue); h = ngx_queue_data(q, uv_handle_t, handle_queue);
ngx_queue_remove(q);
ngx_queue_insert_tail(&loop->handle_queue, q);
if (h->flags & UV__HANDLE_INTERNAL) continue; if (h->flags & UV__HANDLE_INTERNAL) continue;
walk_cb(h, arg); walk_cb(h, arg);
} }

View File

@ -34,7 +34,7 @@
#define UV_VERSION_MAJOR 0 #define UV_VERSION_MAJOR 0
#define UV_VERSION_MINOR 10 #define UV_VERSION_MINOR 10
#define UV_VERSION_PATCH 34 #define UV_VERSION_PATCH 38
#define UV_VERSION_IS_RELEASE 0 #define UV_VERSION_IS_RELEASE 0

View File

@ -26,7 +26,6 @@
#include "internal.h" #include "internal.h"
#define HAVE_SRWLOCK_API() (pTryAcquireSRWLockShared != NULL)
#define HAVE_CONDVAR_API() (pInitializeConditionVariable != NULL) #define HAVE_CONDVAR_API() (pInitializeConditionVariable != NULL)
#ifdef _MSC_VER /* msvc */ #ifdef _MSC_VER /* msvc */
@ -38,25 +37,6 @@
#endif #endif
inline static int uv__rwlock_srwlock_init(uv_rwlock_t* rwlock);
inline static void uv__rwlock_srwlock_destroy(uv_rwlock_t* rwlock);
inline static void uv__rwlock_srwlock_rdlock(uv_rwlock_t* rwlock);
inline static int uv__rwlock_srwlock_tryrdlock(uv_rwlock_t* rwlock);
inline static void uv__rwlock_srwlock_rdunlock(uv_rwlock_t* rwlock);
inline static void uv__rwlock_srwlock_wrlock(uv_rwlock_t* rwlock);
inline static int uv__rwlock_srwlock_trywrlock(uv_rwlock_t* rwlock);
inline static void uv__rwlock_srwlock_wrunlock(uv_rwlock_t* rwlock);
inline static int uv__rwlock_fallback_init(uv_rwlock_t* rwlock);
inline static void uv__rwlock_fallback_destroy(uv_rwlock_t* rwlock);
inline static void uv__rwlock_fallback_rdlock(uv_rwlock_t* rwlock);
inline static int uv__rwlock_fallback_tryrdlock(uv_rwlock_t* rwlock);
inline static void uv__rwlock_fallback_rdunlock(uv_rwlock_t* rwlock);
inline static void uv__rwlock_fallback_wrlock(uv_rwlock_t* rwlock);
inline static int uv__rwlock_fallback_trywrlock(uv_rwlock_t* rwlock);
inline static void uv__rwlock_fallback_wrunlock(uv_rwlock_t* rwlock);
inline static int uv_cond_fallback_init(uv_cond_t* cond); inline static int uv_cond_fallback_init(uv_cond_t* cond);
inline static void uv_cond_fallback_destroy(uv_cond_t* cond); inline static void uv_cond_fallback_destroy(uv_cond_t* cond);
inline static void uv_cond_fallback_signal(uv_cond_t* cond); inline static void uv_cond_fallback_signal(uv_cond_t* cond);
@ -158,68 +138,112 @@ void uv_mutex_unlock(uv_mutex_t* mutex) {
int uv_rwlock_init(uv_rwlock_t* rwlock) { int uv_rwlock_init(uv_rwlock_t* rwlock) {
uv__once_init(); /* Initialize the semaphore that acts as the write lock. */
HANDLE handle = CreateSemaphoreW(NULL, 1, 1, NULL);
if (handle == NULL)
return -1;
rwlock->state_.write_semaphore_ = handle;
if (HAVE_SRWLOCK_API()) /* Initialize the critical section protecting the reader count. */
return uv__rwlock_srwlock_init(rwlock); InitializeCriticalSection(&rwlock->state_.num_readers_lock_);
else
return uv__rwlock_fallback_init(rwlock); /* Initialize the reader count. */
rwlock->state_.num_readers_ = 0;
return 0;
} }
void uv_rwlock_destroy(uv_rwlock_t* rwlock) { void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
if (HAVE_SRWLOCK_API()) DeleteCriticalSection(&rwlock->state_.num_readers_lock_);
uv__rwlock_srwlock_destroy(rwlock); CloseHandle(rwlock->state_.write_semaphore_);
else
uv__rwlock_fallback_destroy(rwlock);
} }
void uv_rwlock_rdlock(uv_rwlock_t* rwlock) { void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
if (HAVE_SRWLOCK_API()) /* Acquire the lock that protects the reader count. */
uv__rwlock_srwlock_rdlock(rwlock); EnterCriticalSection(&rwlock->state_.num_readers_lock_);
else
uv__rwlock_fallback_rdlock(rwlock); /* Increase the reader count, and lock for write if this is the first
* reader.
*/
if (++rwlock->state_.num_readers_ == 1) {
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
if (r != WAIT_OBJECT_0)
uv_fatal_error(GetLastError(), "WaitForSingleObject");
}
/* Release the lock that protects the reader count. */
LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
} }
int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) { int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
if (HAVE_SRWLOCK_API()) int err;
return uv__rwlock_srwlock_tryrdlock(rwlock);
else if (!TryEnterCriticalSection(&rwlock->state_.num_readers_lock_))
return uv__rwlock_fallback_tryrdlock(rwlock); return -1;
err = 0;
if (rwlock->state_.num_readers_ == 0) {
/* Currently there are no other readers, which means that the write lock
* needs to be acquired.
*/
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
if (r == WAIT_OBJECT_0)
rwlock->state_.num_readers_++;
else if (r == WAIT_TIMEOUT)
err = -1;
else if (r == WAIT_FAILED)
uv_fatal_error(GetLastError(), "WaitForSingleObject");
} else {
/* The write lock has already been acquired because there are other
* active readers.
*/
rwlock->state_.num_readers_++;
}
LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
return err;
} }
void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) { void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
if (HAVE_SRWLOCK_API()) EnterCriticalSection(&rwlock->state_.num_readers_lock_);
uv__rwlock_srwlock_rdunlock(rwlock);
else if (--rwlock->state_.num_readers_ == 0) {
uv__rwlock_fallback_rdunlock(rwlock); if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
uv_fatal_error(GetLastError(), "ReleaseSemaphore");
}
LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
} }
void uv_rwlock_wrlock(uv_rwlock_t* rwlock) { void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
if (HAVE_SRWLOCK_API()) DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
uv__rwlock_srwlock_wrlock(rwlock); if (r != WAIT_OBJECT_0)
else uv_fatal_error(GetLastError(), "WaitForSingleObject");
uv__rwlock_fallback_wrlock(rwlock);
} }
int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) { int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
if (HAVE_SRWLOCK_API()) DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
return uv__rwlock_srwlock_trywrlock(rwlock); if (r == WAIT_OBJECT_0)
return 0;
else if (r == WAIT_TIMEOUT)
return -1;
else else
return uv__rwlock_fallback_trywrlock(rwlock); uv_fatal_error(GetLastError(), "WaitForSingleObject");
return -1;
} }
void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) { void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
if (HAVE_SRWLOCK_API()) if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
uv__rwlock_srwlock_wrunlock(rwlock); uv_fatal_error(GetLastError(), "ReleaseSemaphore");
else
uv__rwlock_fallback_wrunlock(rwlock);
} }
@ -261,133 +285,6 @@ int uv_sem_trywait(uv_sem_t* sem) {
} }
inline static int uv__rwlock_srwlock_init(uv_rwlock_t* rwlock) {
pInitializeSRWLock(&rwlock->srwlock_);
return 0;
}
inline static void uv__rwlock_srwlock_destroy(uv_rwlock_t* rwlock) {
(void) rwlock;
}
inline static void uv__rwlock_srwlock_rdlock(uv_rwlock_t* rwlock) {
pAcquireSRWLockShared(&rwlock->srwlock_);
}
inline static int uv__rwlock_srwlock_tryrdlock(uv_rwlock_t* rwlock) {
if (pTryAcquireSRWLockShared(&rwlock->srwlock_))
return 0;
else
return -1;
}
inline static void uv__rwlock_srwlock_rdunlock(uv_rwlock_t* rwlock) {
pReleaseSRWLockShared(&rwlock->srwlock_);
}
inline static void uv__rwlock_srwlock_wrlock(uv_rwlock_t* rwlock) {
pAcquireSRWLockExclusive(&rwlock->srwlock_);
}
inline static int uv__rwlock_srwlock_trywrlock(uv_rwlock_t* rwlock) {
if (pTryAcquireSRWLockExclusive(&rwlock->srwlock_))
return 0;
else
return -1;
}
inline static void uv__rwlock_srwlock_wrunlock(uv_rwlock_t* rwlock) {
pReleaseSRWLockExclusive(&rwlock->srwlock_);
}
inline static int uv__rwlock_fallback_init(uv_rwlock_t* rwlock) {
if (uv_mutex_init(&rwlock->fallback_.read_mutex_))
return -1;
if (uv_mutex_init(&rwlock->fallback_.write_mutex_)) {
uv_mutex_destroy(&rwlock->fallback_.read_mutex_);
return -1;
}
rwlock->fallback_.num_readers_ = 0;
return 0;
}
inline static void uv__rwlock_fallback_destroy(uv_rwlock_t* rwlock) {
uv_mutex_destroy(&rwlock->fallback_.read_mutex_);
uv_mutex_destroy(&rwlock->fallback_.write_mutex_);
}
inline static void uv__rwlock_fallback_rdlock(uv_rwlock_t* rwlock) {
uv_mutex_lock(&rwlock->fallback_.read_mutex_);
if (++rwlock->fallback_.num_readers_ == 1)
uv_mutex_lock(&rwlock->fallback_.write_mutex_);
uv_mutex_unlock(&rwlock->fallback_.read_mutex_);
}
inline static int uv__rwlock_fallback_tryrdlock(uv_rwlock_t* rwlock) {
int ret;
ret = -1;
if (uv_mutex_trylock(&rwlock->fallback_.read_mutex_))
goto out;
if (rwlock->fallback_.num_readers_ == 0)
ret = uv_mutex_trylock(&rwlock->fallback_.write_mutex_);
else
ret = 0;
if (ret == 0)
rwlock->fallback_.num_readers_++;
uv_mutex_unlock(&rwlock->fallback_.read_mutex_);
out:
return ret;
}
inline static void uv__rwlock_fallback_rdunlock(uv_rwlock_t* rwlock) {
uv_mutex_lock(&rwlock->fallback_.read_mutex_);
if (--rwlock->fallback_.num_readers_ == 0)
uv_mutex_unlock(&rwlock->fallback_.write_mutex_);
uv_mutex_unlock(&rwlock->fallback_.read_mutex_);
}
inline static void uv__rwlock_fallback_wrlock(uv_rwlock_t* rwlock) {
uv_mutex_lock(&rwlock->fallback_.write_mutex_);
}
inline static int uv__rwlock_fallback_trywrlock(uv_rwlock_t* rwlock) {
return uv_mutex_trylock(&rwlock->fallback_.write_mutex_);
}
inline static void uv__rwlock_fallback_wrunlock(uv_rwlock_t* rwlock) {
uv_mutex_unlock(&rwlock->fallback_.write_mutex_);
}
/* This condition variable implementation is based on the SetEvent solution /* This condition variable implementation is based on the SetEvent solution
* (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html * (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
* We could not use the SignalObjectAndWait solution (section 3.4) because * We could not use the SignalObjectAndWait solution (section 3.4) because

View File

@ -38,13 +38,6 @@ sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
sCreateSymbolicLinkW pCreateSymbolicLinkW; sCreateSymbolicLinkW pCreateSymbolicLinkW;
sCancelIoEx pCancelIoEx; sCancelIoEx pCancelIoEx;
sInitializeSRWLock pInitializeSRWLock;
sAcquireSRWLockShared pAcquireSRWLockShared;
sAcquireSRWLockExclusive pAcquireSRWLockExclusive;
sTryAcquireSRWLockShared pTryAcquireSRWLockShared;
sTryAcquireSRWLockExclusive pTryAcquireSRWLockExclusive;
sReleaseSRWLockShared pReleaseSRWLockShared;
sReleaseSRWLockExclusive pReleaseSRWLockExclusive;
sInitializeConditionVariable pInitializeConditionVariable; sInitializeConditionVariable pInitializeConditionVariable;
sSleepConditionVariableCS pSleepConditionVariableCS; sSleepConditionVariableCS pSleepConditionVariableCS;
sSleepConditionVariableSRW pSleepConditionVariableSRW; sSleepConditionVariableSRW pSleepConditionVariableSRW;
@ -114,27 +107,6 @@ void uv_winapi_init() {
pCancelIoEx = (sCancelIoEx) pCancelIoEx = (sCancelIoEx)
GetProcAddress(kernel32_module, "CancelIoEx"); GetProcAddress(kernel32_module, "CancelIoEx");
pInitializeSRWLock = (sInitializeSRWLock)
GetProcAddress(kernel32_module, "InitializeSRWLock");
pAcquireSRWLockShared = (sAcquireSRWLockShared)
GetProcAddress(kernel32_module, "AcquireSRWLockShared");
pAcquireSRWLockExclusive = (sAcquireSRWLockExclusive)
GetProcAddress(kernel32_module, "AcquireSRWLockExclusive");
pTryAcquireSRWLockShared = (sTryAcquireSRWLockShared)
GetProcAddress(kernel32_module, "TryAcquireSRWLockShared");
pTryAcquireSRWLockExclusive = (sTryAcquireSRWLockExclusive)
GetProcAddress(kernel32_module, "TryAcquireSRWLockExclusive");
pReleaseSRWLockShared = (sReleaseSRWLockShared)
GetProcAddress(kernel32_module, "ReleaseSRWLockShared");
pReleaseSRWLockExclusive = (sReleaseSRWLockExclusive)
GetProcAddress(kernel32_module, "ReleaseSRWLockExclusive");
pInitializeConditionVariable = (sInitializeConditionVariable) pInitializeConditionVariable = (sInitializeConditionVariable)
GetProcAddress(kernel32_module, "InitializeConditionVariable"); GetProcAddress(kernel32_module, "InitializeConditionVariable");

View File

@ -4405,27 +4405,6 @@ typedef BOOL (WINAPI* sCancelIoEx)
(HANDLE hFile, (HANDLE hFile,
LPOVERLAPPED lpOverlapped); LPOVERLAPPED lpOverlapped);
typedef VOID (WINAPI* sInitializeSRWLock)
(PSRWLOCK SRWLock);
typedef VOID (WINAPI* sAcquireSRWLockShared)
(PSRWLOCK SRWLock);
typedef VOID (WINAPI* sAcquireSRWLockExclusive)
(PSRWLOCK SRWLock);
typedef BOOL (WINAPI* sTryAcquireSRWLockShared)
(PSRWLOCK SRWLock);
typedef BOOL (WINAPI* sTryAcquireSRWLockExclusive)
(PSRWLOCK SRWLock);
typedef VOID (WINAPI* sReleaseSRWLockShared)
(PSRWLOCK SRWLock);
typedef VOID (WINAPI* sReleaseSRWLockExclusive)
(PSRWLOCK SRWLock);
typedef VOID (WINAPI* sInitializeConditionVariable) typedef VOID (WINAPI* sInitializeConditionVariable)
(PCONDITION_VARIABLE ConditionVariable); (PCONDITION_VARIABLE ConditionVariable);
@ -4460,13 +4439,6 @@ extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
extern sCreateSymbolicLinkW pCreateSymbolicLinkW; extern sCreateSymbolicLinkW pCreateSymbolicLinkW;
extern sCancelIoEx pCancelIoEx; extern sCancelIoEx pCancelIoEx;
extern sInitializeSRWLock pInitializeSRWLock;
extern sAcquireSRWLockShared pAcquireSRWLockShared;
extern sAcquireSRWLockExclusive pAcquireSRWLockExclusive;
extern sTryAcquireSRWLockShared pTryAcquireSRWLockShared;
extern sTryAcquireSRWLockExclusive pTryAcquireSRWLockExclusive;
extern sReleaseSRWLockShared pReleaseSRWLockShared;
extern sReleaseSRWLockExclusive pReleaseSRWLockExclusive;
extern sInitializeConditionVariable pInitializeConditionVariable; extern sInitializeConditionVariable pInitializeConditionVariable;
extern sSleepConditionVariableCS pSleepConditionVariableCS; extern sSleepConditionVariableCS pSleepConditionVariableCS;
extern sSleepConditionVariableSRW pSleepConditionVariableSRW; extern sSleepConditionVariableSRW pSleepConditionVariableSRW;

View File

@ -196,9 +196,16 @@ static void chown_root_cb(uv_fs_t* req) {
/* On windows, chown is a no-op and always succeeds. */ /* On windows, chown is a no-op and always succeeds. */
ASSERT(req->result == 0); ASSERT(req->result == 0);
#else #else
/* On unix, chown'ing the root directory is not allowed. */ /* On unix, chown'ing the root directory is not allowed -
* unless you're root, of course.
*/
if (geteuid() == 0) {
ASSERT(req->result == 0);
}
else {
ASSERT(req->result == -1); ASSERT(req->result == -1);
ASSERT(req->errorno == UV_EPERM); ASSERT(req->errorno == UV_EPERM);
}
#endif #endif
chown_cb_count++; chown_cb_count++;
uv_fs_req_cleanup(req); uv_fs_req_cleanup(req);

View File

@ -65,7 +65,10 @@ TEST_DECLARE (tcp_connect_error_fault)
TEST_DECLARE (tcp_connect_timeout) TEST_DECLARE (tcp_connect_timeout)
TEST_DECLARE (tcp_close_while_connecting) TEST_DECLARE (tcp_close_while_connecting)
TEST_DECLARE (tcp_close) TEST_DECLARE (tcp_close)
#ifndef _WIN32
TEST_DECLARE (tcp_close_accept) TEST_DECLARE (tcp_close_accept)
TEST_DECLARE (tcp_oob)
#endif
TEST_DECLARE (tcp_flags) TEST_DECLARE (tcp_flags)
TEST_DECLARE (tcp_write_to_half_open_connection) TEST_DECLARE (tcp_write_to_half_open_connection)
TEST_DECLARE (tcp_unexpected_read) TEST_DECLARE (tcp_unexpected_read)
@ -208,6 +211,7 @@ TEST_DECLARE (threadpool_cancel_fs)
TEST_DECLARE (threadpool_cancel_single) TEST_DECLARE (threadpool_cancel_single)
TEST_DECLARE (thread_mutex) TEST_DECLARE (thread_mutex)
TEST_DECLARE (thread_rwlock) TEST_DECLARE (thread_rwlock)
TEST_DECLARE (thread_rwlock_trylock)
TEST_DECLARE (thread_create) TEST_DECLARE (thread_create)
TEST_DECLARE (strlcpy) TEST_DECLARE (strlcpy)
TEST_DECLARE (strlcat) TEST_DECLARE (strlcat)
@ -311,7 +315,10 @@ TASK_LIST_START
TEST_ENTRY (tcp_connect_timeout) TEST_ENTRY (tcp_connect_timeout)
TEST_ENTRY (tcp_close_while_connecting) TEST_ENTRY (tcp_close_while_connecting)
TEST_ENTRY (tcp_close) TEST_ENTRY (tcp_close)
#ifndef _WIN32
TEST_ENTRY (tcp_close_accept) TEST_ENTRY (tcp_close_accept)
TEST_ENTRY (tcp_oob)
#endif
TEST_ENTRY (tcp_flags) TEST_ENTRY (tcp_flags)
TEST_ENTRY (tcp_write_to_half_open_connection) TEST_ENTRY (tcp_write_to_half_open_connection)
TEST_ENTRY (tcp_unexpected_read) TEST_ENTRY (tcp_unexpected_read)
@ -516,6 +523,7 @@ TASK_LIST_START
TEST_ENTRY (threadpool_cancel_single) TEST_ENTRY (threadpool_cancel_single)
TEST_ENTRY (thread_mutex) TEST_ENTRY (thread_mutex)
TEST_ENTRY (thread_rwlock) TEST_ENTRY (thread_rwlock)
TEST_ENTRY (thread_rwlock_trylock)
TEST_ENTRY (thread_create) TEST_ENTRY (thread_create)
TEST_ENTRY (strlcpy) TEST_ENTRY (strlcpy)
TEST_ENTRY (strlcat) TEST_ENTRY (strlcat)

View File

@ -61,3 +61,62 @@ TEST_IMPL(thread_rwlock) {
return 0; return 0;
} }
TEST_IMPL(thread_rwlock_trylock) {
uv_rwlock_t rwlock;
int r;
r = uv_rwlock_init(&rwlock);
ASSERT(r == 0);
/* No locks held. */
r = uv_rwlock_trywrlock(&rwlock);
ASSERT(r == 0);
/* Write lock held. */
r = uv_rwlock_tryrdlock(&rwlock);
ASSERT(r == -1);
r = uv_rwlock_trywrlock(&rwlock);
ASSERT(r == -1);
uv_rwlock_wrunlock(&rwlock);
/* No locks held. */
r = uv_rwlock_tryrdlock(&rwlock);
ASSERT(r == 0);
/* One read lock held. */
r = uv_rwlock_tryrdlock(&rwlock);
ASSERT(r == 0);
/* Two read locks held. */
r = uv_rwlock_trywrlock(&rwlock);
ASSERT(r == -1);
uv_rwlock_rdunlock(&rwlock);
/* One read lock held. */
uv_rwlock_rdunlock(&rwlock);
/* No read locks held. */
r = uv_rwlock_trywrlock(&rwlock);
ASSERT(r == 0);
/* Write lock held. */
uv_rwlock_wrunlock(&rwlock);
/* No locks held. */
uv_rwlock_destroy(&rwlock);
return 0;
}

View File

@ -60,12 +60,16 @@ TEST_IMPL(tcp_close_while_connecting) {
uv_connect_t connect_req; uv_connect_t connect_req;
struct sockaddr_in addr; struct sockaddr_in addr;
uv_loop_t* loop; uv_loop_t* loop;
int r;
addr = uv_ip4_addr("1.2.3.4", TEST_PORT); addr = uv_ip4_addr("1.2.3.4", TEST_PORT);
loop = uv_default_loop(); loop = uv_default_loop();
ASSERT(0 == uv_tcp_init(loop, &tcp_handle)); ASSERT(0 == uv_tcp_init(loop, &tcp_handle));
ASSERT(0 == uv_tcp_connect(&connect_req, &tcp_handle, addr, connect_cb)); r = uv_tcp_connect(&connect_req, &tcp_handle, addr, connect_cb);
if (r == -1 && uv_last_error(uv_default_loop()).code == UV_ENETUNREACH)
RETURN_SKIP("Network unreachable.");
ASSERT(r == 0);
ASSERT(0 == uv_timer_init(loop, &timer1_handle)); ASSERT(0 == uv_timer_init(loop, &timer1_handle));
ASSERT(0 == uv_timer_start(&timer1_handle, timer1_cb, 50, 0)); ASSERT(0 == uv_timer_start(&timer1_handle, timer1_cb, 50, 0));
ASSERT(0 == uv_timer_init(loop, &timer2_handle)); ASSERT(0 == uv_timer_init(loop, &timer2_handle));

View File

@ -76,6 +76,8 @@ TEST_IMPL(tcp_connect_timeout) {
ASSERT(r == 0); ASSERT(r == 0);
r = uv_tcp_connect(&connect_req, &conn, addr, connect_cb); r = uv_tcp_connect(&connect_req, &conn, addr, connect_cb);
if (r == -1 && uv_last_error(uv_default_loop()).code == UV_ENETUNREACH)
RETURN_SKIP("Network unreachable.");
ASSERT(r == 0); ASSERT(r == 0);
r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); r = uv_run(uv_default_loop(), UV_RUN_DEFAULT);

137
test/test-tcp-oob.c Normal file
View File

@ -0,0 +1,137 @@
/* Copyright Fedor Indutny. 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.
*/
#if !defined(_WIN32)
#include "uv.h"
#include "task.h"
#include <errno.h>
#include <sys/socket.h>
#include <unistd.h>
static uv_tcp_t server_handle;
static uv_tcp_t client_handle;
static uv_tcp_t peer_handle;
static uv_idle_t idle;
static uv_connect_t connect_req;
static int ticks;
static const int kMaxTicks = 10;
static void set_nonblocking(int fd, int set) {
int r;
int flags = fcntl(fd, F_GETFL, 0);
ASSERT(flags >= 0);
if (set)
flags |= O_NONBLOCK;
else
flags &= ~O_NONBLOCK;
r = fcntl(fd, F_SETFL, flags);
ASSERT(r >= 0);
}
static uv_buf_t alloc_cb(uv_handle_t* handle, size_t size) {
static char storage[1024];
return uv_buf_init(storage, sizeof(storage));
}
static void idle_cb(uv_idle_t* idle, int status) {
ASSERT(status == 0);
if (++ticks < kMaxTicks)
return;
uv_close((uv_handle_t*) &server_handle, NULL);
uv_close((uv_handle_t*) &client_handle, NULL);
uv_close((uv_handle_t*) &peer_handle, NULL);
uv_close((uv_handle_t*) idle, NULL);
}
static void read_cb(uv_stream_t* tcp, ssize_t nread, uv_buf_t buf) {
ASSERT(nread > 0);
ASSERT(0 == uv_idle_start(&idle, idle_cb));
}
static void connect_cb(uv_connect_t* req, int status) {
ASSERT(req->handle == (uv_stream_t*) &client_handle);
ASSERT(0 == status);
}
static void connection_cb(uv_stream_t* handle, int status) {
int r;
int fd;
ASSERT(0 == status);
ASSERT(0 == uv_accept(handle, (uv_stream_t*) &peer_handle));
ASSERT(0 == uv_read_start((uv_stream_t*) &peer_handle, alloc_cb, read_cb));
/* Send some OOB data */
fd = client_handle.io_watcher.fd;
set_nonblocking(fd, 0);
/* The problem triggers only on a second message, it seem that xnu is not
* triggering `kevent()` for the first one
*/
do {
r = send(fd, "hello", 5, MSG_OOB);
} while (r < 0 && errno == EINTR);
ASSERT(5 == r);
do {
r = send(fd, "hello", 5, MSG_OOB);
} while (r < 0 && errno == EINTR);
ASSERT(5 == r);
set_nonblocking(fd, 1);
}
TEST_IMPL(tcp_oob) {
uv_loop_t* loop;
loop = uv_default_loop();
ASSERT(0 == uv_tcp_init(loop, &server_handle));
ASSERT(0 == uv_tcp_init(loop, &client_handle));
ASSERT(0 == uv_tcp_init(loop, &peer_handle));
ASSERT(0 == uv_idle_init(loop, &idle));
ASSERT(0 == uv_tcp_bind(&server_handle, uv_ip4_addr("127.0.0.1", TEST_PORT)));
ASSERT(0 == uv_listen((uv_stream_t*) &server_handle, 1, connection_cb));
/* Ensure two separate packets */
ASSERT(0 == uv_tcp_nodelay(&client_handle, 1));
ASSERT(0 == uv_tcp_connect(&connect_req,
&client_handle,
uv_ip4_addr("127.0.0.1", TEST_PORT),
connect_cb));
ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT));
ASSERT(ticks == kMaxTicks);
MAKE_VALGRIND_HAPPY();
return 0;
}
#endif

View File

@ -113,6 +113,8 @@ TEST_IMPL(udp_multicast_join) {
/* join the multicast channel */ /* join the multicast channel */
r = uv_udp_set_membership(&client, "239.255.0.1", NULL, UV_JOIN_GROUP); r = uv_udp_set_membership(&client, "239.255.0.1", NULL, UV_JOIN_GROUP);
if (r == -1 && uv_last_error(uv_default_loop()).code == UV_ENODEV)
RETURN_SKIP("No multicast support.");
ASSERT(r == 0); ASSERT(r == 0);
r = uv_udp_recv_start(&client, alloc_cb, cl_recv_cb); r = uv_udp_recv_start(&client, alloc_cb, cl_recv_cb);

View File

@ -44,7 +44,11 @@ static void close_cb(uv_handle_t* handle) {
static void sv_send_cb(uv_udp_send_t* req, int status) { static void sv_send_cb(uv_udp_send_t* req, int status) {
ASSERT(req != NULL); ASSERT(req != NULL);
if (status == -1) {
ASSERT(uv_last_error(uv_default_loop()).code == UV_ENETUNREACH);
} else {
ASSERT(status == 0); ASSERT(status == 0);
}
CHECK_HANDLE(req->handle); CHECK_HANDLE(req->handle);
sv_send_cb_called++; sv_send_cb_called++;

2
uv.gyp
View File

@ -133,6 +133,7 @@
'include/uv-private/uv-darwin.h', 'include/uv-private/uv-darwin.h',
'include/uv-private/uv-bsd.h', 'include/uv-private/uv-bsd.h',
'src/unix/async.c', 'src/unix/async.c',
'src/unix/atomic-ops.h',
'src/unix/core.c', 'src/unix/core.c',
'src/unix/dl.c', 'src/unix/dl.c',
'src/unix/error.c', 'src/unix/error.c',
@ -354,6 +355,7 @@
'test/test-tcp-write-to-half-open-connection.c', 'test/test-tcp-write-to-half-open-connection.c',
'test/test-tcp-writealot.c', 'test/test-tcp-writealot.c',
'test/test-tcp-unexpected-read.c', 'test/test-tcp-unexpected-read.c',
'test/test-tcp-oob.c',
'test/test-tcp-read-stop.c', 'test/test-tcp-read-stop.c',
'test/test-threadpool.c', 'test/test-threadpool.c',
'test/test-threadpool-cancel.c', 'test/test-threadpool-cancel.c',

View File

@ -90,8 +90,8 @@ if defined noprojgen goto msbuild
@rem Generate the VS project. @rem Generate the VS project.
if exist build\gyp goto have_gyp if exist build\gyp goto have_gyp
echo git clone https://git.chromium.org/external/gyp.git build/gyp echo git clone https://chromium.googlesource.com/external/gyp build/gyp
git clone https://git.chromium.org/external/gyp.git build/gyp git clone https://chromium.googlesource.com/external/gyp build/gyp
if errorlevel 1 goto gyp_install_failed if errorlevel 1 goto gyp_install_failed
goto have_gyp goto have_gyp