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>
Logan Rosen <loganrosen@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
Changes since version 0.10.32:

View File

@ -6,6 +6,9 @@ eventually contain all platform differences in this library.
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
* 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
project tree manually:
mkdir -p build
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
git clone https://chromium.googlesource.com/external/gyp.git build/gyp
Unix users run

View File

@ -127,6 +127,7 @@ TESTS= \
test/test-tcp-connect-timeout.o \
test/test-tcp-flags.o \
test/test-tcp-open.o \
test/test-tcp-oob.o \
test/test-tcp-read-stop.o \
test/test-tcp-shutdown-after-write.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-shutdown-after-write.c
test/test-tcp-unexpected-read.c
test/test-tcp-oob.c
test/test-tcp-write-error.c
test/test-tcp-write-to-half-open-connection.c
test/test-tcp-writealot.c

View File

@ -22,7 +22,7 @@ E=
CSTDFLAG=--std=c89 -pedantic -Wall -Wextra -Wno-unused-parameter
CFLAGS += -g
CPPFLAGS += -I$(SRCDIR)/src
LDFLAGS=-lm -pthread
LDFLAGS += -lm -pthread
CPPFLAGS += -D_LARGEFILE_SOURCE
CPPFLAGS += -D_FILE_OFFSET_BITS=64
@ -186,7 +186,7 @@ src/.buildstamp src/unix/.buildstamp test/.buildstamp:
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 $(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 $@
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)
#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) \
do { \
(h)->prev->next = (n)->next; \
@ -120,6 +131,9 @@ struct ngx_queue_s {
((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) \
for ((q) = ngx_queue_head(h); \
(q) != ngx_queue_sentinel(h) && !ngx_queue_empty(h); \

View File

@ -235,14 +235,20 @@ typedef union {
} uv_cond_t;
typedef union {
/* srwlock_ has type SRWLOCK, but not all toolchains define this type in */
/* windows.h. */
SRWLOCK srwlock_;
struct {
uv_mutex_t read_mutex_;
uv_mutex_t write_mutex_;
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;
typedef struct {

View File

@ -24,6 +24,7 @@
#include "uv.h"
#include "internal.h"
#include "atomic-ops.h"
#include <errno.h>
#include <assert.h>
@ -34,7 +35,6 @@
static void uv__async_event(uv_loop_t* loop,
struct uv__async* w,
unsigned int nevents);
static int uv__async_make_pending(int* pending);
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) {
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);
return 0;
@ -70,49 +74,26 @@ void uv__async_close(uv_async_t* handle) {
static void uv__async_event(uv_loop_t* loop,
struct uv__async* w,
unsigned int nevents) {
ngx_queue_t queue;
ngx_queue_t* q;
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);
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);
}
}
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) {
struct uv__async* wa;
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;
uv_mutex_lock(&loop->cf_mutex);
ngx_queue_init(&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);
}
ngx_queue_move(&loop->cf_signals, &split_head);
uv_mutex_unlock(&loop->cf_mutex);
while (!ngx_queue_empty(&split_head)) {
item = ngx_queue_head(&split_head);
ngx_queue_remove(item);
s = ngx_queue_data(item, uv__cf_loop_signal_t, member);
@ -151,7 +148,6 @@ static void uv__cf_loop_cb(void* arg) {
else
s->cb(s->arg);
ngx_queue_remove(item);
free(s);
}
}

View File

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

View File

@ -55,11 +55,7 @@ struct uv__fsevents_event_s {
ngx_queue_t split_head; \
uv__fsevents_event_t* event; \
uv_mutex_lock(&(handle)->cf_mutex); \
ngx_queue_init(&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); \
} \
ngx_queue_move(&(handle)->cf_events, &split_head); \
uv_mutex_unlock(&(handle)->cf_mutex); \
while (!ngx_queue_empty(&split_head)) { \
curr = ngx_queue_head(&split_head); \

View File

@ -66,6 +66,21 @@
} \
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__)
# define UV__POLLIN UV__EPOLLIN
# 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))
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,
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;
struct watcher_list* w;
uv_fs_event_t* h;
ngx_queue_t queue;
ngx_queue_t* q;
const char* path;
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);
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);
ngx_queue_remove(q);
ngx_queue_insert_tail(&w->watchers, q);
h->cb(h, path, events, 0);
}
}

View File

@ -48,9 +48,14 @@
\
void uv__run_##name(uv_loop_t* loop) { \
uv_##name##_t* h; \
ngx_queue_t queue; \
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); \
ngx_queue_remove(q); \
ngx_queue_insert_tail(&loop->name##_handles, q); \
h->name##_cb(h, 0); \
} \
} \

View File

@ -40,6 +40,10 @@
extern char **environ;
#endif
#ifdef __linux__
# include <grp.h>
#endif
static ngx_queue_t* uv__process_queue(uv_loop_t* loop, int pid) {
assert(pid > 0);
@ -331,6 +335,17 @@ static void uv__process_child_init(uv_process_options_t options,
_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)) {
uv__write_int(error_fd, errno);
_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
* ensures that the (shared) signal tree doesn't contain any invalid entries
* 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) {
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) {
#if defined(__APPLE__)
int enable;
#endif
assert(fd >= 0);
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);
}
#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;
return 0;

View File

@ -84,13 +84,12 @@ int uv_mutex_trylock(uv_mutex_t* mutex) {
r = pthread_mutex_trylock(mutex);
if (r && r != EBUSY && r != EAGAIN)
abort();
if (r)
if (r) {
if (r != EBUSY && r != EAGAIN)
abort();
return -1;
else
return 0;
}
return 0;
}
@ -125,13 +124,12 @@ int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
r = pthread_rwlock_tryrdlock(rwlock);
if (r && r != EBUSY && r != EAGAIN)
abort();
if (r)
if (r) {
if (r != EBUSY && r != EAGAIN)
abort();
return -1;
else
return 0;
}
return 0;
}
@ -152,13 +150,12 @@ int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
r = pthread_rwlock_trywrlock(rwlock);
if (r && r != EBUSY && r != EAGAIN)
abort();
if (r)
if (r) {
if (r != EBUSY && r != EAGAIN)
abort();
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;
loop = container_of(handle, uv_loop_t, wq_async);
ngx_queue_init(&wq);
uv_mutex_lock(&loop->wq_mutex);
if (!ngx_queue_empty(&loop->wq)) {
q = ngx_queue_head(&loop->wq);
ngx_queue_split(&loop->wq, q, &wq);
}
ngx_queue_move(&loop->wq, &wq);
uv_mutex_unlock(&loop->wq_mutex);
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) {
ngx_queue_t queue;
ngx_queue_t* q;
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);
ngx_queue_remove(q);
ngx_queue_insert_tail(&loop->handle_queue, q);
if (h->flags & UV__HANDLE_INTERNAL) continue;
walk_cb(h, arg);
}

View File

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

View File

@ -26,7 +26,6 @@
#include "internal.h"
#define HAVE_SRWLOCK_API() (pTryAcquireSRWLockShared != NULL)
#define HAVE_CONDVAR_API() (pInitializeConditionVariable != NULL)
#ifdef _MSC_VER /* msvc */
@ -38,25 +37,6 @@
#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 void uv_cond_fallback_destroy(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) {
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())
return uv__rwlock_srwlock_init(rwlock);
else
return uv__rwlock_fallback_init(rwlock);
/* Initialize the critical section protecting the reader count. */
InitializeCriticalSection(&rwlock->state_.num_readers_lock_);
/* Initialize the reader count. */
rwlock->state_.num_readers_ = 0;
return 0;
}
void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
if (HAVE_SRWLOCK_API())
uv__rwlock_srwlock_destroy(rwlock);
else
uv__rwlock_fallback_destroy(rwlock);
DeleteCriticalSection(&rwlock->state_.num_readers_lock_);
CloseHandle(rwlock->state_.write_semaphore_);
}
void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
if (HAVE_SRWLOCK_API())
uv__rwlock_srwlock_rdlock(rwlock);
else
uv__rwlock_fallback_rdlock(rwlock);
/* Acquire the lock that protects the reader count. */
EnterCriticalSection(&rwlock->state_.num_readers_lock_);
/* 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) {
if (HAVE_SRWLOCK_API())
return uv__rwlock_srwlock_tryrdlock(rwlock);
else
return uv__rwlock_fallback_tryrdlock(rwlock);
int err;
if (!TryEnterCriticalSection(&rwlock->state_.num_readers_lock_))
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) {
if (HAVE_SRWLOCK_API())
uv__rwlock_srwlock_rdunlock(rwlock);
else
uv__rwlock_fallback_rdunlock(rwlock);
EnterCriticalSection(&rwlock->state_.num_readers_lock_);
if (--rwlock->state_.num_readers_ == 0) {
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) {
if (HAVE_SRWLOCK_API())
uv__rwlock_srwlock_wrlock(rwlock);
else
uv__rwlock_fallback_wrlock(rwlock);
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
if (r != WAIT_OBJECT_0)
uv_fatal_error(GetLastError(), "WaitForSingleObject");
}
int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
if (HAVE_SRWLOCK_API())
return uv__rwlock_srwlock_trywrlock(rwlock);
DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
if (r == WAIT_OBJECT_0)
return 0;
else if (r == WAIT_TIMEOUT)
return -1;
else
return uv__rwlock_fallback_trywrlock(rwlock);
uv_fatal_error(GetLastError(), "WaitForSingleObject");
return -1;
}
void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
if (HAVE_SRWLOCK_API())
uv__rwlock_srwlock_wrunlock(rwlock);
else
uv__rwlock_fallback_wrunlock(rwlock);
if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
uv_fatal_error(GetLastError(), "ReleaseSemaphore");
}
@ -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
* (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

View File

@ -38,13 +38,6 @@ sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
sCreateSymbolicLinkW pCreateSymbolicLinkW;
sCancelIoEx pCancelIoEx;
sInitializeSRWLock pInitializeSRWLock;
sAcquireSRWLockShared pAcquireSRWLockShared;
sAcquireSRWLockExclusive pAcquireSRWLockExclusive;
sTryAcquireSRWLockShared pTryAcquireSRWLockShared;
sTryAcquireSRWLockExclusive pTryAcquireSRWLockExclusive;
sReleaseSRWLockShared pReleaseSRWLockShared;
sReleaseSRWLockExclusive pReleaseSRWLockExclusive;
sInitializeConditionVariable pInitializeConditionVariable;
sSleepConditionVariableCS pSleepConditionVariableCS;
sSleepConditionVariableSRW pSleepConditionVariableSRW;
@ -114,27 +107,6 @@ void uv_winapi_init() {
pCancelIoEx = (sCancelIoEx)
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)
GetProcAddress(kernel32_module, "InitializeConditionVariable");

View File

@ -4405,27 +4405,6 @@ typedef BOOL (WINAPI* sCancelIoEx)
(HANDLE hFile,
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)
(PCONDITION_VARIABLE ConditionVariable);
@ -4460,13 +4439,6 @@ extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
extern sCreateSymbolicLinkW pCreateSymbolicLinkW;
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 sSleepConditionVariableCS pSleepConditionVariableCS;
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. */
ASSERT(req->result == 0);
#else
/* On unix, chown'ing the root directory is not allowed. */
ASSERT(req->result == -1);
ASSERT(req->errorno == UV_EPERM);
/* 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->errorno == UV_EPERM);
}
#endif
chown_cb_count++;
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_close_while_connecting)
TEST_DECLARE (tcp_close)
#ifndef _WIN32
TEST_DECLARE (tcp_close_accept)
TEST_DECLARE (tcp_oob)
#endif
TEST_DECLARE (tcp_flags)
TEST_DECLARE (tcp_write_to_half_open_connection)
TEST_DECLARE (tcp_unexpected_read)
@ -208,6 +211,7 @@ TEST_DECLARE (threadpool_cancel_fs)
TEST_DECLARE (threadpool_cancel_single)
TEST_DECLARE (thread_mutex)
TEST_DECLARE (thread_rwlock)
TEST_DECLARE (thread_rwlock_trylock)
TEST_DECLARE (thread_create)
TEST_DECLARE (strlcpy)
TEST_DECLARE (strlcat)
@ -311,7 +315,10 @@ TASK_LIST_START
TEST_ENTRY (tcp_connect_timeout)
TEST_ENTRY (tcp_close_while_connecting)
TEST_ENTRY (tcp_close)
#ifndef _WIN32
TEST_ENTRY (tcp_close_accept)
TEST_ENTRY (tcp_oob)
#endif
TEST_ENTRY (tcp_flags)
TEST_ENTRY (tcp_write_to_half_open_connection)
TEST_ENTRY (tcp_unexpected_read)
@ -516,6 +523,7 @@ TASK_LIST_START
TEST_ENTRY (threadpool_cancel_single)
TEST_ENTRY (thread_mutex)
TEST_ENTRY (thread_rwlock)
TEST_ENTRY (thread_rwlock_trylock)
TEST_ENTRY (thread_create)
TEST_ENTRY (strlcpy)
TEST_ENTRY (strlcat)

View File

@ -61,3 +61,62 @@ TEST_IMPL(thread_rwlock) {
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;
struct sockaddr_in addr;
uv_loop_t* loop;
int r;
addr = uv_ip4_addr("1.2.3.4", TEST_PORT);
loop = uv_default_loop();
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_start(&timer1_handle, timer1_cb, 50, 0));
ASSERT(0 == uv_timer_init(loop, &timer2_handle));

View File

@ -76,6 +76,8 @@ TEST_IMPL(tcp_connect_timeout) {
ASSERT(r == 0);
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);
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 */
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);
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) {
ASSERT(req != NULL);
ASSERT(status == 0);
if (status == -1) {
ASSERT(uv_last_error(uv_default_loop()).code == UV_ENETUNREACH);
} else {
ASSERT(status == 0);
}
CHECK_HANDLE(req->handle);
sv_send_cb_called++;

2
uv.gyp
View File

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

View File

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