Commit 379e2ddf authored by Jérémy Lal's avatar Jérémy Lal

Imported Upstream version 0.10.22~dfsg1

parent ec138705
......@@ -467,3 +467,6 @@ Edward Hutchins <eahutchins@gmail.com>
Chris Wren <cthewren@gmail.com>
Duan Yao <duanyao@ustc.edu>
Eric Schrock <Eric.Schrock@delphix.com>
Zarko Stankovic <stankovic.zarko@gmail.com>
Maxim Bogushevich <boga1@mail.ru>
Phillip Alexander <git@phillipalexander.io>
2013.10.18, Version 0.10.21 (Stable)
2013.11.12, Version 0.10.22 (Stable)
* npm: Upgrade to 1.3.14
* uv: Upgrade to v0.10.19
* child_process: don't assert on stale file descriptor events (Fedor Indutny)
* darwin: Fix "Not Responding" in Mavericks activity monitor (Fedor Indutny)
* debugger: Fix bug in sb() with unnamed script (Maxim Bogushevich)
* repl: do not insert duplicates into completions (Maciej Małecki)
* src: Fix memory leak on closed handles (Timothy J Fontaine)
* tls: prevent stalls by using read(0) (Fedor Indutny)
* v8: use correct timezone information on Solaris (Maciej Małecki)
2013.10.18, Version 0.10.21 (Stable), e2da042844a830fafb8031f6c477eb4f96195210
* uv: Upgrade to v0.10.18
......
......@@ -46,9 +46,9 @@ endif
out/Makefile: common.gypi deps/uv/uv.gyp deps/http_parser/http_parser.gyp deps/zlib/zlib.gyp deps/v8/build/common.gypi deps/v8/tools/gyp/v8.gyp node.gyp config.gypi
ifeq ($(USE_NINJA),1)
touch out/Makefile
$(PYTHON) tools/gyp_node -f ninja
$(PYTHON) tools/gyp_node.py -f ninja
else
$(PYTHON) tools/gyp_node -f make
$(PYTHON) tools/gyp_node.py -f make
endif
config.gypi: configure
......@@ -82,16 +82,16 @@ test-http1: all
test-valgrind: all
$(PYTHON) tools/test.py --mode=release --valgrind simple message
test/gc/node_modules/weak/build:
test/gc/node_modules/weak/build/Release/weakref.node:
@if [ ! -f node ]; then make all; fi
./node deps/npm/node_modules/node-gyp/bin/node-gyp rebuild \
--directory="$(shell pwd)/test/gc/node_modules/weak" \
--nodedir="$(shell pwd)"
test-gc: all test/gc/node_modules/weak/build
test-gc: all test/gc/node_modules/weak/build/Release/weakref.node
$(PYTHON) tools/test.py --mode=release gc
test-all: all test/gc/node_modules/weak/build
test-all: all test/gc/node_modules/weak/build/Release/weakref.node
$(PYTHON) tools/test.py --mode=debug,release
make test-npm
......
......@@ -704,4 +704,4 @@ elif flavor == 'win':
else:
gyp_args = ['-f', 'make-' + flavor]
subprocess.call([sys.executable, 'tools/gyp_node'] + gyp_args)
subprocess.call([sys.executable, 'tools/gyp_node.py'] + gyp_args)
......@@ -85,3 +85,5 @@ Miroslav Bajtoš <miro.bajtos@gmail.com>
Elliot Saba <staticfloat@gmail.com>
Wynn Wilkes <wynnw@movenetworks.com>
Andrei Sedoi <bsnote@gmail.com>
Chris Bank <cbank@adobe.com>
Geert Jansen <geertj@gmail.com>
2013.10.19, Version 0.10.18 (Stable)
2013.11.13, Version 0.10.19 (Stable)
Changes since version 0.10.18:
* darwin: avoid calling GetCurrentProcess (Fedor Indutny)
* unix: update events from pevents between polls (Fedor Indutny)
* fsevents: support japaneese characters in path (Chris Bank)
* linux: don't turn on SO_REUSEPORT socket option (Ben Noordhuis)
* build: fix windows smp build with gyp (Geert Jansen)
* linux: handle EPOLLHUP without EPOLLIN/EPOLLOUT (Ben Noordhuis)
* unix: fix reopened fd bug (Fedor Indutny)
* core: fix fake watcher list and count preservation (Fedor Indutny)
2013.10.19, Version 0.10.18 (Stable), 9ec52963b585e822e87bdc5de28d6143aff0d2e5
Changes since version 0.10.17:
......
......@@ -91,12 +91,12 @@ Or:
Unix users run
./gyp_uv -f make
./gyp_uv.py -f make
make -C out
Macintosh users run
./gyp_uv -f xcode
./gyp_uv.py -f xcode
xcodebuild -project uv.xcodeproj -configuration Release -target All
Note for UNIX users: compile your project with `-D_LARGEFILE_SOURCE` and
......
......@@ -114,6 +114,7 @@ TESTS= \
test/test-tcp-bind6-error.o \
test/test-tcp-bind-error.o \
test/test-tcp-close.o \
test/test-tcp-close-accept.o \
test/test-tcp-close-while-connecting.o \
test/test-tcp-connect6-error.o \
test/test-tcp-connect-error-after-write.o \
......@@ -142,6 +143,7 @@ TESTS= \
test/test-udp-send-and-recv.o \
test/test-util.o \
test/test-walk-handles.o \
test/test-watcher-cross-stop.o \
.PHONY: all bench clean clean-platform distclean test
......
......@@ -133,6 +133,7 @@ test/test-stdio-over-pipes.c
test/test-tcp-bind-error.c
test/test-tcp-bind6-error.c
test/test-tcp-close-while-connecting.c
test/test-tcp-close-accept.c
test/test-tcp-close.c
test/test-tcp-connect-error-after-write.c
test/test-tcp-connect-error.c
......@@ -161,6 +162,7 @@ test/test-udp-options.c
test/test-udp-send-and-recv.c
test/test-util.c
test/test-walk-handles.c
test/test-watcher-cross-stop.c
"
case `uname -s` in
......
......@@ -595,20 +595,33 @@ static unsigned int next_power_of_two(unsigned int val) {
static void maybe_resize(uv_loop_t* loop, unsigned int len) {
uv__io_t** watchers;
void* fake_watcher_list;
void* fake_watcher_count;
unsigned int nwatchers;
unsigned int i;
if (len <= loop->nwatchers)
return;
nwatchers = next_power_of_two(len);
watchers = realloc(loop->watchers, nwatchers * sizeof(loop->watchers[0]));
/* Preserve fake watcher list and count at the end of the watchers */
if (loop->watchers != NULL) {
fake_watcher_list = loop->watchers[loop->nwatchers];
fake_watcher_count = loop->watchers[loop->nwatchers + 1];
} else {
fake_watcher_list = NULL;
fake_watcher_count = NULL;
}
nwatchers = next_power_of_two(len + 2) - 2;
watchers = realloc(loop->watchers,
(nwatchers + 2) * sizeof(loop->watchers[0]));
if (watchers == NULL)
abort();
for (i = loop->nwatchers; i < nwatchers; i++)
watchers[i] = NULL;
watchers[nwatchers] = fake_watcher_list;
watchers[nwatchers + 1] = fake_watcher_count;
loop->watchers = watchers;
loop->nwatchers = nwatchers;
......@@ -700,6 +713,9 @@ void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
uv__io_stop(loop, w, UV__POLLIN | UV__POLLOUT);
ngx_queue_remove(&w->pending_queue);
/* Remove stale events for this file descriptor */
uv__platform_invalidate_fd(loop, w->fd);
}
......
......@@ -36,14 +36,22 @@ int uv__set_process_title(const char* title) {
CFStringRef,
CFStringRef,
CFDictionaryRef*);
typedef CFDictionaryRef (*LSApplicationCheckInType)(int, CFDictionaryRef);
typedef OSStatus (*SetApplicationIsDaemonType)(int);
typedef void (*LSSetApplicationLaunchServicesServerConnectionStatusType)(
uint64_t, void*);
CFBundleRef launch_services_bundle;
LSGetCurrentApplicationASNType ls_get_current_application_asn;
LSSetApplicationInformationItemType ls_set_application_information_item;
CFStringRef* display_name_key;
ProcessSerialNumber psn;
CFTypeRef asn;
CFStringRef display_name;
OSStatus err;
CFBundleRef hi_services_bundle;
LSApplicationCheckInType ls_application_check_in;
SetApplicationIsDaemonType set_application_is_daemon;
LSSetApplicationLaunchServicesServerConnectionStatusType
ls_set_application_launch_services_server_connection_status;
launch_services_bundle =
CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices"));
......@@ -71,8 +79,36 @@ int uv__set_process_title(const char* title) {
if (display_name_key == NULL || *display_name_key == NULL)
return -1;
/* Force the process manager to initialize. */
GetCurrentProcess(&psn);
/* Black 10.9 magic, to remove (Not responding) mark in Activity Monitor */
hi_services_bundle =
CFBundleGetBundleWithIdentifier(CFSTR("com.apple.HIServices"));
if (hi_services_bundle == NULL)
return -1;
set_application_is_daemon = CFBundleGetFunctionPointerForName(
hi_services_bundle,
CFSTR("SetApplicationIsDaemon"));
ls_application_check_in = CFBundleGetFunctionPointerForName(
launch_services_bundle,
CFSTR("_LSApplicationCheckIn"));
ls_set_application_launch_services_server_connection_status =
CFBundleGetFunctionPointerForName(
launch_services_bundle,
CFSTR("_LSSetApplicationLaunchServicesServerConnectionStatus"));
if (set_application_is_daemon == NULL ||
ls_application_check_in == NULL ||
ls_set_application_launch_services_server_connection_status == NULL) {
return -1;
}
if (set_application_is_daemon(1) != noErr)
return -1;
ls_set_application_launch_services_server_connection_status(0, NULL);
/* Check into process manager?! */
ls_application_check_in(-2,
CFBundleGetInfoDictionary(CFBundleGetMainBundle()));
display_name = CFStringCreateWithCString(NULL, title, kCFStringEncodingUTF8);
asn = ls_get_current_application_asn();
......
......@@ -102,6 +102,25 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
}
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
struct kevent* events;
uintptr_t i;
uintptr_t nfds;
assert(loop->watchers != NULL);
events = (struct kevent*) loop->watchers[loop->nwatchers];
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
if (events == NULL)
return;
/* Invalidate events with same file descriptor */
for (i = 0; i < nfds; i++)
if ((int) events[i].ident == fd)
events[i].ident = -1;
}
static void uv__cf_loop_runner(void* arg) {
uv_loop_t* loop;
......
......@@ -223,9 +223,7 @@ int uv__fsevents_init(uv_fs_event_t* handle) {
handle->realpath_len = strlen(handle->realpath);
/* Initialize paths array */
path = CFStringCreateWithCString(NULL,
handle->filename,
CFStringGetSystemEncoding());
path = CFStringCreateWithFileSystemRepresentation(NULL, handle->filename);
paths = CFArrayCreate(NULL, (const void**)&path, 1, NULL);
latency = 0.15;
......
......@@ -183,6 +183,7 @@ uint64_t uv__hrtime(void);
int uv__kqueue_init(uv_loop_t* loop);
int uv__platform_loop_init(uv_loop_t* loop, int default_loop);
void uv__platform_loop_delete(uv_loop_t* loop);
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd);
/* various */
void uv__async_close(uv_async_t* handle);
......
......@@ -162,11 +162,18 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
nevents = 0;
assert(loop->watchers != NULL);
loop->watchers[loop->nwatchers] = (void*) events;
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
for (i = 0; i < nfds; i++) {
ev = events + i;
fd = ev->ident;
w = loop->watchers[fd];
/* Skip invalidated events, see uv__platform_invalidate_fd */
if (fd == -1)
continue;
if (w == NULL) {
/* File descriptor that we've stopped watching, disarm it. */
/* TODO batch up */
......@@ -191,7 +198,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
revents = 0;
if (ev->filter == EVFILT_READ) {
if (w->events & UV__POLLIN) {
if (w->pevents & UV__POLLIN) {
revents |= UV__POLLIN;
w->rcount = ev->data;
} else {
......@@ -205,7 +212,7 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
}
if (ev->filter == EVFILT_WRITE) {
if (w->events & UV__POLLOUT) {
if (w->pevents & UV__POLLOUT) {
revents |= UV__POLLOUT;
w->wcount = ev->data;
} else {
......@@ -227,6 +234,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
w->cb(loop, w, revents);
nevents++;
}
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) {
......
......@@ -97,6 +97,25 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
}
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
struct uv__epoll_event* events;
uintptr_t i;
uintptr_t nfds;
assert(loop->watchers != NULL);
events = (struct uv__epoll_event*) loop->watchers[loop->nwatchers];
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
if (events == NULL)
return;
/* Invalidate events with same file descriptor */
for (i = 0; i < nfds; i++)
if ((int) events[i].data == fd)
events[i].data = -1;
}
void uv__io_poll(uv_loop_t* loop, int timeout) {
struct uv__epoll_event events[1024];
struct uv__epoll_event* pe;
......@@ -189,10 +208,17 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
nevents = 0;
assert(loop->watchers != NULL);
loop->watchers[loop->nwatchers] = (void*) events;
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
for (i = 0; i < nfds; i++) {
pe = events + i;
fd = pe->data;
/* Skip invalidated events, see uv__platform_invalidate_fd */
if (fd == -1)
continue;
assert(fd >= 0);
assert((unsigned) fd < loop->nwatchers);
......@@ -208,9 +234,38 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
continue;
}
w->cb(loop, w, pe->events);
nevents++;
/* Give users only events they're interested in. Prevents spurious
* callbacks when previous callback invocation in this loop has stopped
* the current watcher. Also, filters out events that users has not
* requested us to watch.
*/
pe->events &= w->pevents | UV__POLLERR | UV__POLLHUP;
/* Work around an epoll quirk where it sometimes reports just the
* EPOLLERR or EPOLLHUP event. In order to force the event loop to
* move forward, we merge in the read/write events that the watcher
* is interested in; uv__read() and uv__write() will then deal with
* the error or hangup in the usual fashion.
*
* Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user
* reads the available data, calls uv_read_stop(), then sometime later
* calls uv_read_start() again. By then, libuv has forgotten about the
* hangup and the kernel won't report EPOLLIN again because there's
* nothing left to read. If anything, libuv is to blame here. The
* current hack is just a quick bandaid; to properly fix it, libuv
* needs to remember the error/hangup event. We should get that for
* free when we switch over to edge-triggered I/O.
*/
if (pe->events == UV__EPOLLERR || pe->events == UV__EPOLLHUP)
pe->events |= w->pevents & (UV__EPOLLIN | UV__EPOLLOUT);
if (pe->events != 0) {
w->cb(loop, w, pe->events);
nevents++;
}
}
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) {
......
......@@ -87,6 +87,25 @@ void uv__platform_loop_delete(uv_loop_t* loop) {
}
void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
struct port_event* events;
uintptr_t i;
uintptr_t nfds;
assert(loop->watchers != NULL);
events = (struct port_event*) loop->watchers[loop->nwatchers];
nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
if (events == NULL)
return;
/* Invalidate events with same file descriptor */
for (i = 0; i < nfds; i++)
if ((int) events[i].portev_object == fd)
events[i].portev_object = -1;
}
void uv__io_poll(uv_loop_t* loop, int timeout) {
struct port_event events[1024];
struct port_event* pe;
......@@ -173,10 +192,17 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
nevents = 0;
assert(loop->watchers != NULL);
loop->watchers[loop->nwatchers] = (void*) events;
loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
for (i = 0; i < nfds; i++) {
pe = events + i;
fd = pe->portev_object;
/* Skip invalidated events, see uv__platform_invalidate_fd */
if (fd == -1)
continue;
assert(fd >= 0);
assert((unsigned) fd < loop->nwatchers);
......@@ -193,6 +219,8 @@ void uv__io_poll(uv_loop_t* loop, int timeout) {
if (w->pevents != 0 && ngx_queue_empty(&w->watcher_queue))
ngx_queue_insert_tail(&loop->watcher_queue, &w->watcher_queue);
}
loop->watchers[loop->nwatchers] = NULL;
loop->watchers[loop->nwatchers + 1] = NULL;
if (nevents != 0) {
if (nfds == ARRAY_SIZE(events) && --count != 0) {
......
......@@ -286,6 +286,31 @@ static void uv__udp_sendmsg(uv_loop_t* loop,
}
/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
* refinements for programs that use multicast.
*
* Linux as of 3.9 has a SO_REUSEPORT socket option but with semantics that
* are different from the BSDs: it _shares_ the port rather than steal it
* from the current listener. While useful, it's not something we can emulate
* on other platforms so we don't enable it.
*/
static int uv__set_reuse(int fd) {
int yes;
#if defined(SO_REUSEPORT) && !defined(__linux__)
yes = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
return -errno;
#else
yes = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
return -errno;
#endif
return 0;
}
static int uv__bind(uv_udp_t* handle,
int domain,
struct sockaddr* addr,
......@@ -293,6 +318,7 @@ static int uv__bind(uv_udp_t* handle,
unsigned flags) {
int saved_errno;
int status;
int err;
int yes;
int fd;
......@@ -321,28 +347,12 @@ static int uv__bind(uv_udp_t* handle,
}
fd = handle->io_watcher.fd;
yes = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) == -1) {
uv__set_sys_error(handle->loop, errno);
err = uv__set_reuse(fd);
if (err) {
uv__set_sys_error(handle->loop, -err);
goto out;
}
/* On the BSDs, SO_REUSEADDR lets you reuse an address that's in the TIME_WAIT
* state (i.e. was until recently tied to a socket) while SO_REUSEPORT lets
* multiple processes bind to the same address. Yes, it's something of a
* misnomer but then again, SO_REUSEADDR was already taken.
*
* None of the above applies to Linux: SO_REUSEADDR implies SO_REUSEPORT on
* Linux and hence it does not have SO_REUSEPORT at all.
*/
#ifdef SO_REUSEPORT
yes = 1;
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof yes) == -1) {
uv__set_sys_error(handle->loop, errno);
goto out;
}
#endif
if (flags & UV_UDP_IPV6ONLY) {
#ifdef IPV6_V6ONLY
yes = 1;
......
......@@ -34,7 +34,7 @@
#define UV_VERSION_MAJOR 0
#define UV_VERSION_MINOR 10
#define UV_VERSION_PATCH 18
#define UV_VERSION_PATCH 19
#define UV_VERSION_IS_RELEASE 1
......
......@@ -64,6 +64,7 @@ TEST_DECLARE (tcp_connect_error_fault)
TEST_DECLARE (tcp_connect_timeout)
TEST_DECLARE (tcp_close_while_connecting)
TEST_DECLARE (tcp_close)
TEST_DECLARE (tcp_close_accept)
TEST_DECLARE (tcp_flags)
TEST_DECLARE (tcp_write_to_half_open_connection)
TEST_DECLARE (tcp_unexpected_read)
......@@ -106,6 +107,7 @@ TEST_DECLARE (idle_starvation)
TEST_DECLARE (loop_handles)
TEST_DECLARE (get_loadavg)
TEST_DECLARE (walk_handles)
TEST_DECLARE (watcher_cross_stop)
TEST_DECLARE (ref)
TEST_DECLARE (idle_ref)
TEST_DECLARE (async_ref)
......@@ -297,6 +299,7 @@ TASK_LIST_START
TEST_ENTRY (tcp_connect_timeout)
TEST_ENTRY (tcp_close_while_connecting)
TEST_ENTRY (tcp_close)
TEST_ENTRY (tcp_close_accept)
TEST_ENTRY (tcp_flags)
TEST_ENTRY (tcp_write_to_half_open_connection)
TEST_ENTRY (tcp_unexpected_read)
......@@ -385,6 +388,8 @@ TASK_LIST_START
TEST_ENTRY (loop_handles)
TEST_ENTRY (walk_handles)
TEST_ENTRY (watcher_cross_stop)
TEST_ENTRY (active)
TEST_ENTRY (embed)
......
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"
#include "task.h"
#include <stdio.h>
#include <string.h>
static struct sockaddr_in addr;
static uv_tcp_t tcp_server;
static uv_tcp_t tcp_outgoing[2];
static uv_tcp_t tcp_incoming[ARRAY_SIZE(tcp_outgoing)];
static uv_connect_t connect_reqs[ARRAY_SIZE(tcp_outgoing)];
static uv_tcp_t tcp_check;
static uv_connect_t tcp_check_req;
static uv_write_t write_reqs[ARRAY_SIZE(tcp_outgoing)];
static unsigned int got_connections;
static unsigned int close_cb_called;
static unsigned int write_cb_called;
static unsigned int read_cb_called;
static void close_cb(uv_handle_t* handle) {
close_cb_called++;
}
static void write_cb(uv_write_t* req, int status) {
ASSERT(status == 0);
write_cb_called++;
}
static void connect_cb(uv_connect_t* req, int status) {
unsigned int i;
uv_buf_t buf;
uv_stream_t* outgoing;
if (req == &tcp_check_req) {
ASSERT(status != 0);
/* Close check and incoming[0], time to finish test */
uv_close((uv_handle_t*) &tcp_incoming[0], close_cb);
uv_close((uv_handle_t*) &tcp_check, close_cb);
return;
}
ASSERT(status == 0);
ASSERT(connect_reqs <= req);
ASSERT(req <= connect_reqs + ARRAY_SIZE(connect_reqs));
i = req - connect_reqs;
buf = uv_buf_init("x", 1);
outgoing = (uv_stream_t*) &tcp_outgoing[i];
ASSERT(0 == uv_write(&write_reqs[i], outgoing, &buf, 1, write_cb));
}
static uv_buf_t alloc_cb(uv_handle_t* handle, size_t suggested_size) {
static char buf[1];
return uv_buf_init(buf, sizeof(buf));
}
static void read_cb(uv_stream_t* stream, ssize_t nread, uv_buf_t b) {
uv_loop_t* loop;
unsigned int i;
/* Only first stream should receive read events */
ASSERT(stream == (uv_stream_t*) &tcp_incoming[0]);
ASSERT(0 == uv_read_stop(stream));
ASSERT(1 == nread);
loop = stream->loop;
read_cb_called++;
/* Close all active incomings, except current one */
for (i = 1; i < got_connections; i++)
uv_close((uv_handle_t*) &tcp_incoming[i], close_cb);
/* Create new fd that should be one of the closed incomings */