#define ngx_queue_foreach(q, h) \
- for ((q) = ngx_queue_head(h); (q) != (h); (q) = ngx_queue_next(q))
+ for ((q) = ngx_queue_head(h); \
+ (q) != ngx_queue_sentinel(h); \
+ (q) = ngx_queue_next(q))
#endif /* NGX_QUEUE_H_INCLUDED_ */
#include <semaphore.h>
#include <pthread.h>
+#include <signal.h>
#if __sun
# include <sys/port.h>
ngx_queue_t prepare_handles; \
ngx_queue_t check_handles; \
ngx_queue_t idle_handles; \
+ ngx_queue_t async_handles; \
+ uv__io_t async_watcher; \
+ int async_pipefd[2]; \
/* RB_HEAD(uv__timers, uv_timer_s) */ \
struct uv__timers { struct uv_timer_s* rbh_root; } timer_handles; \
uint64_t time; \
/* UV_ASYNC */
-#define UV_ASYNC_PRIVATE_FIELDS \
- ev_async async_watcher; \
- uv_async_cb async_cb;
+#define UV_ASYNC_PRIVATE_FIELDS \
+ volatile sig_atomic_t pending; \
+ uv_async_cb async_cb; \
+ ngx_queue_t queue;
/* UV_TIMER */
#include "uv.h"
#include "internal.h"
+#include <errno.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <unistd.h>
-static void uv__async(EV_P_ ev_async* w, int revents) {
- uv_async_t* async = container_of(w, uv_async_t, async_watcher);
+static int uv__async_init(uv_loop_t* loop);
+static void uv__async_io(uv_loop_t* loop, uv__io_t* handle, int events);
- if (async->async_cb) {
- async->async_cb(async, 0);
- }
-}
+int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
+ if (uv__async_init(loop))
+ return uv__set_sys_error(loop, errno);
-int uv_async_init(uv_loop_t* loop, uv_async_t* async, uv_async_cb async_cb) {
- uv__handle_init(loop, (uv_handle_t*)async, UV_ASYNC);
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC);
loop->counters.async_init++;
- ev_async_init(&async->async_watcher, uv__async);
- async->async_cb = async_cb;
+ handle->async_cb = async_cb;
+ handle->pending = 0;
- /* Note: This does not have symmetry with the other libev wrappers. */
- ev_async_start(loop->ev, &async->async_watcher);
- uv__handle_unref(async);
- uv__handle_start(async);
+ ngx_queue_insert_tail(&loop->async_handles, &handle->queue);
+ uv__handle_start(handle);
return 0;
}
-int uv_async_send(uv_async_t* async) {
- ev_async_send(async->loop->ev, &async->async_watcher);
+int uv_async_send(uv_async_t* handle) {
+ int r;
+
+ handle->pending = 1; /* XXX needs a memory barrier? */
+
+ do
+ r = write(handle->loop->async_pipefd[1], "x", 1);
+ while (r == -1 && errno == EINTR);
+
+ if (r == -1 && errno != EAGAIN && errno != EWOULDBLOCK)
+ return uv__set_sys_error(handle->loop, errno);
+
return 0;
}
void uv__async_close(uv_async_t* handle) {
- ev_async_stop(handle->loop->ev, &handle->async_watcher);
- uv__handle_ref(handle);
+ ngx_queue_remove(&handle->queue);
uv__handle_stop(handle);
}
+
+
+static int uv__async_init(uv_loop_t* loop) {
+ if (loop->async_pipefd[0] != -1)
+ return 0;
+
+ if (uv__make_pipe(loop->async_pipefd, UV__F_NONBLOCK))
+ return -1;
+
+ uv__io_init(&loop->async_watcher,
+ uv__async_io,
+ loop->async_pipefd[0],
+ UV__IO_READ);
+ uv__io_start(loop, &loop->async_watcher);
+
+ return 0;
+}
+
+
+static void uv__async_io(uv_loop_t* loop, uv__io_t* handle, int events) {
+ char buf[1024];
+ ngx_queue_t* q;
+ uv_async_t* h;
+ ssize_t r;
+
+ while (1) {
+ r = read(loop->async_pipefd[0], buf, sizeof(buf));
+
+ if (r == sizeof(buf))
+ continue;
+
+ if (r != -1)
+ break;
+
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ break;
+
+ if (errno == EINTR)
+ continue;
+
+ abort();
+ }
+
+ ngx_queue_foreach(q, &loop->async_handles) {
+ h = ngx_queue_data(q, uv_async_t, queue);
+ if (!h->pending) continue;
+ h->pending = 0;
+ h->async_cb(h, 0);
+ }
+}
if (!ngx_queue_empty(&loop->idle_handles))
return 0;
+ if (loop->closing_handles)
+ return 0;
+
return uv__next_timeout(loop);
}
#include <time.h>
#undef NANOSEC
-#define NANOSEC 1000000000
+#define NANOSEC ((uint64_t) 1e9)
uint64_t uv_hrtime() {
int uv_dlopen(const char* filename, uv_lib_t* lib) {
+ dlerror(); /* Reset error status. */
lib->errmsg = NULL;
lib->handle = dlopen(filename, RTLD_LAZY);
return uv__dlerror(lib);
#include <fcntl.h>
#undef NANOSEC
-#define NANOSEC 1000000000
+#define NANOSEC ((uint64_t) 1e9)
#ifndef CPUSTATES
# define CPUSTATES 5U
void uv__udp_close(uv_udp_t* handle);
void uv__udp_finish_close(uv_udp_t* handle);
-#define UV__F_IPC (1 << 0)
-#define UV__F_NONBLOCK (1 << 1)
+#ifdef UV__O_NONBLOCK
+# define UV__F_NONBLOCK UV__O_NONBLOCK
+#else
+# define UV__F_NONBLOCK 1
+#endif
+
int uv__make_socketpair(int fds[2], int flags);
int uv__make_pipe(int fds[2], int flags);
#endif
#undef NANOSEC
-#define NANOSEC 1000000000
+#define NANOSEC ((uint64_t) 1e9)
/* This is rather annoying: CLOCK_BOOTTIME lives in <linux/time.h> but we can't
* include that file because it conflicts with <time.h>. We'll just have to
# endif
#endif /* __NR_accept4 */
+#ifndef __NR_eventfd
+# if __x86_64__
+# define __NR_eventfd 284
+# elif __i386__
+# define __NR_eventfd 323
+# elif __arm__
+# define __NR_eventfd (UV_SYSCALL_BASE + 351)
+# endif
+#endif /* __NR_eventfd */
+
+#ifndef __NR_eventfd2
+# if __x86_64__
+# define __NR_eventfd2 290
+# elif __i386__
+# define __NR_eventfd2 328
+# elif __arm__
+# define __NR_eventfd2 (UV_SYSCALL_BASE + 356)
+# endif
+#endif /* __NR_eventfd2 */
+
#ifndef __NR_inotify_init
# if __x86_64__
# define __NR_inotify_init 253
}
+int uv__eventfd(unsigned int count) {
+#if __NR_eventfd
+ return syscall(__NR_eventfd, count);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__eventfd2(unsigned int count, int flags) {
+#if __NR_eventfd2
+ return syscall(__NR_eventfd2, count, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
int uv__inotify_init(void) {
#if __NR_inotify_init
return syscall(__NR_inotify_init);
#define UV__O_NONBLOCK 0x800
#define UV__O_CLOEXEC 0x80000
-#define UV__SOCK_CLOEXEC UV__O_CLOEXEC
-#define UV__SOCK_NONBLOCK UV__O_NONBLOCK
+#define UV__EFD_CLOEXEC UV__O_CLOEXEC
+#define UV__EFD_NONBLOCK UV__O_NONBLOCK
#define UV__IN_CLOEXEC UV__O_CLOEXEC
#define UV__IN_NONBLOCK UV__O_NONBLOCK
+#define UV__SOCK_CLOEXEC UV__O_CLOEXEC
+#define UV__SOCK_NONBLOCK UV__O_NONBLOCK
+
+/* inotify flags */
#define UV__IN_ACCESS 0x001
#define UV__IN_MODIFY 0x002
#define UV__IN_ATTRIB 0x004
};
int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags);
+int uv__eventfd(unsigned int count);
+int uv__eventfd2(unsigned int count, int flags);
int uv__inotify_init(void);
int uv__inotify_init1(int flags);
int uv__inotify_add_watch(int fd, const char* path, __u32 mask);
RB_INIT(&loop->timer_handles);
ngx_queue_init(&loop->active_reqs);
ngx_queue_init(&loop->idle_handles);
+ ngx_queue_init(&loop->async_handles);
ngx_queue_init(&loop->check_handles);
ngx_queue_init(&loop->prepare_handles);
ngx_queue_init(&loop->handle_queue);
loop->closing_handles = NULL;
loop->channel = NULL;
loop->time = uv_hrtime() / 1000000;
+ loop->async_pipefd[0] = -1;
+ loop->async_pipefd[1] = -1;
loop->ev = (default_loop ? ev_default_loop : ev_loop_new)(flags);
ev_set_userdata(loop->ev, loop);
eio_channel_init(&loop->uv_eio_channel, loop);
#include <time.h>
#undef NANOSEC
-#define NANOSEC 1000000000
+#define NANOSEC ((uint64_t) 1e9)
uint64_t uv_hrtime(void) {
#include <unistd.h>
#undef NANOSEC
-#define NANOSEC 1000000000
+#define NANOSEC ((uint64_t) 1e9)
static char *process_title;
int uv__make_socketpair(int fds[2], int flags) {
-#ifdef SOCK_NONBLOCK
- int fl;
-
- fl = SOCK_CLOEXEC;
-
- if (flags & UV__F_NONBLOCK)
- fl |= SOCK_NONBLOCK;
-
- if (socketpair(AF_UNIX, SOCK_STREAM|fl, 0, fds) == 0)
+#if __linux__
+ if (socketpair(AF_UNIX, SOCK_STREAM | UV__SOCK_CLOEXEC | flags, 0, fds) == 0)
return 0;
+ /* Retry on EINVAL, it means SOCK_CLOEXEC is not supported.
+ * Anything else is a genuine error.
+ */
if (errno != EINVAL)
return -1;
-
- /* errno == EINVAL so maybe the kernel headers lied about
- * the availability of SOCK_NONBLOCK. This can happen if people
- * build libuv against newer kernel headers than the kernel
- * they actually run the software on.
- */
#endif
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
int uv__make_pipe(int fds[2], int flags) {
#if __linux__
- int fl;
-
- fl = UV__O_CLOEXEC;
-
- if (flags & UV__F_NONBLOCK)
- fl |= UV__O_NONBLOCK;
-
- if (uv__pipe2(fds, fl) == 0)
+ if (uv__pipe2(fds, flags | UV__O_CLOEXEC) == 0)
return 0;
if (errno != ENOSYS)
stream->flags & UV_STREAM_SHUT ||
stream->flags & UV_CLOSED ||
stream->flags & UV_CLOSING) {
- uv__set_sys_error(stream->loop, EINVAL);
+ uv__set_artificial_error(stream->loop, UV_ENOTCONN);
return -1;
}
#include <assert.h>
#include <errno.h>
-#ifdef SUNOS_HAVE_IFADDRS
-# include <ifaddrs.h>
-#endif
+#include <ifaddrs.h>
#include <net/if.h>
#include <sys/loadavg.h>
uv_err_t uv_interface_addresses(uv_interface_address_t** addresses,
int* count) {
-#ifndef SUNOS_HAVE_IFADDRS
- return uv__new_artificial_error(UV_ENOSYS);
-#else
+
struct ifaddrs *addrs, *ent;
char ip[INET6_ADDRSTRLEN];
uv_interface_address_t* address;
freeifaddrs(addrs);
return uv_ok_;
-#endif /* SUNOS_HAVE_IFADDRS */
}
&loop->uv_eio_want_poll_notifier,
uv_eio_want_poll_notifier_cb);
loop->uv_eio_want_poll_notifier.flags |= UV__HANDLE_INTERNAL;
+ uv__handle_unref(&loop->uv_eio_want_poll_notifier);
uv_async_init(loop,
&loop->uv_eio_done_poll_notifier,
uv_eio_done_poll_notifier_cb);
loop->uv_eio_done_poll_notifier.flags |= UV__HANDLE_INTERNAL;
+ uv__handle_unref(&loop->uv_eio_done_poll_notifier);
uv_once(&uv__eio_init_once_guard, uv__eio_init);
}
static uv_err_t uv__kill(HANDLE process_handle, int signum) {
- DWORD status;
- uv_err_t err;
+ switch (signum) {
+ case SIGTERM:
+ case SIGKILL:
+ case SIGINT: {
+ /* Unconditionally terminate the process. On Windows, killed processes */
+ /* normally return 1. */
+ DWORD error, status;
+
+ if (TerminateProcess(process_handle, 1))
+ return uv_ok_;
+
+ /* If the process already exited before TerminateProcess was called, */
+ /* TerminateProcess will fail with ERROR_ACESS_DENIED. */
+ error = GetLastError();
+ if (error == ERROR_ACCESS_DENIED &&
+ GetExitCodeProcess(process_handle, &status) &&
+ status != STILL_ACTIVE) {
+ return uv__new_artificial_error(UV_ESRCH);
+ }
- if (signum == SIGTERM || signum == SIGKILL || signum == SIGINT) {
- /* Kill the process. On Windows, killed processes normally return 1. */
- if (TerminateProcess(process_handle, 1)) {
- err = uv_ok_;
- } else {
- err = uv__new_sys_error(GetLastError());
+ return uv__new_sys_error(error);
}
- } else if (signum == 0) {
- /* Health check: is the process still alive? */
- if (GetExitCodeProcess(process_handle, &status)) {
- if (status == STILL_ACTIVE) {
- err = uv_ok_;
- } else {
- err = uv__new_artificial_error(UV_ESRCH);
- }
- } else {
- err = uv__new_sys_error(GetLastError());
+
+ case 0: {
+ /* Health check: is the process still alive? */
+ DWORD status;
+
+ if (!GetExitCodeProcess(process_handle, &status))
+ return uv__new_sys_error(GetLastError());
+
+ if (status != STILL_ACTIVE)
+ return uv__new_artificial_error(UV_ESRCH);
+
+ return uv_ok_;
}
- } else {
- err = uv__new_artificial_error(UV_ENOSYS);
- }
- return err;
+ default:
+ /* Unsupported signal. */
+ return uv__new_artificial_error(UV_ENOSYS);
+ }
}
int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, int64_t timeout,
int64_t repeat) {
uv_loop_t* loop = handle->loop;
+ uv_timer_t* old;
if (handle->flags & UV_HANDLE_ACTIVE) {
RB_REMOVE(uv_timer_tree_s, &loop->timers, handle);
handle->flags |= UV_HANDLE_ACTIVE;
uv__handle_start(handle);
- if (RB_INSERT(uv_timer_tree_s, &loop->timers, handle) != NULL) {
- uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT");
- }
+ old = RB_INSERT(uv_timer_tree_s, &loop->timers, handle);
+ assert(old == NULL);
return 0;
}
#include <assert.h>
#include <direct.h>
+#include <limits.h>
#include <malloc.h>
#include <stdio.h>
#include <string.h>
for (adapter_address = adapter_addresses;
adapter_address != NULL;
adapter_address = adapter_address->Next) {
+
+ if (adapter_address->OperStatus != IfOperStatusUp)
+ continue;
+
unicast_address = (IP_ADAPTER_UNICAST_ADDRESS_XP*)
adapter_address->FirstUnicastAddress;
+
while (unicast_address) {
(*count)++;
unicast_address = unicast_address->Next;
for (adapter_address = adapter_addresses;
adapter_address != NULL;
adapter_address = adapter_address->Next) {
+
+ if (adapter_address->OperStatus != IfOperStatusUp)
+ continue;
+
name = NULL;
unicast_address = (IP_ADAPTER_UNICAST_ADDRESS_XP*)
adapter_address->FirstUnicastAddress;
#include "internal.h"
+/* Ntdll function pointers */
sRtlNtStatusToDosError pRtlNtStatusToDosError;
sNtDeviceIoControlFile pNtDeviceIoControlFile;
sNtQueryInformationFile pNtQueryInformationFile;
sNtSetInformationFile pNtSetInformationFile;
sNtQuerySystemInformation pNtQuerySystemInformation;
+
+
+/* Kernel32 function pointers */
sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
sCreateSymbolicLinkW pCreateSymbolicLinkW;
-/* Ntapi function pointers */
+/* Ntdll function pointers */
extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
extern sNtQueryInformationFile pNtQueryInformationFile;
BENCHMARK_DECLARE (getaddrinfo)
BENCHMARK_DECLARE (spawn)
BENCHMARK_DECLARE (thread_create)
+BENCHMARK_DECLARE (million_timers)
HELPER_DECLARE (tcp4_blackhole_server)
HELPER_DECLARE (tcp_pump_server)
HELPER_DECLARE (pipe_pump_server)
BENCHMARK_ENTRY (spawn)
BENCHMARK_ENTRY (thread_create)
+ BENCHMARK_ENTRY (million_timers)
TASK_LIST_END
--- /dev/null
+/* 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 "task.h"
+#include "uv.h"
+
+#define NUM_TIMERS (1000 * 1000)
+
+static int timer_cb_called;
+
+
+static void timer_cb(uv_timer_t* handle, int status) {
+ timer_cb_called++;
+}
+
+
+BENCHMARK_IMPL(million_timers) {
+ uv_timer_t* timers;
+ uv_loop_t* loop;
+ uint64_t before;
+ uint64_t after;
+ int timeout;
+ int i;
+
+ timers = malloc(NUM_TIMERS * sizeof(timers[0]));
+ ASSERT(timers != NULL);
+
+ loop = uv_default_loop();
+ timeout = 0;
+
+ for (i = 0; i < NUM_TIMERS; i++) {
+ if (i % 1000 == 0) timeout++;
+ ASSERT(0 == uv_timer_init(loop, timers + i));
+ ASSERT(0 == uv_timer_start(timers + i, timer_cb, timeout, 0));
+ }
+
+ before = uv_hrtime();
+ ASSERT(0 == uv_run(loop));
+ after = uv_hrtime();
+
+ ASSERT(timer_cb_called == NUM_TIMERS);
+ free(timers);
+
+ LOGF("%.2f seconds\n", (after - before) / 1e9);
+
+ return 0;
+}
#define MAX_CONNS 1000
#undef NANOSEC
-#define NANOSEC ((uint64_t)10e8)
+#define NANOSEC ((uint64_t) 1e9)
#undef DEBUG
#define DEBUG 0
if (total == 0)
total = 1;
- LOGF("[%% %3d|+ %3d|- %3d]: %s", (passed + failed) / total * 100,
+ LOGF("[%% %3d|+ %3d|- %3d]: %s", (int) ((passed + failed) / ((double) total) * 100.0),
passed, failed, name);
}
#endif
#ifndef NANOSEC
-# define NANOSEC 1000000000
+# define NANOSEC ((uint64_t) 1e9)
#endif
TEST_IMPL(hrtime) {
uint64_t a, b, diff;
-
- a = uv_hrtime();
- uv_sleep(100);
- b = uv_hrtime();
-
- diff = b - a;
-
- printf("diff = %llu\n", (unsigned long long int) diff);
-
- /* The windows Sleep() function has only a resolution of 10-20 ms. */
- /* Check that the difference between the two hrtime values is somewhat in */
- /* the range we expect it to be. */
- ASSERT(diff > (uint64_t) 80 * NANOSEC / MILLISEC);
- ASSERT(diff < (uint64_t) 120 * NANOSEC / MILLISEC);
+ int i = 100;
+ while (i > 0) {
+ a = uv_hrtime();
+ uv_sleep(45);
+ b = uv_hrtime();
+
+ diff = b - a;
+
+ /* printf("i= %d diff = %llu\n", i, (unsigned long long int) diff); */
+
+ /* The windows Sleep() function has only a resolution of 10-20 ms. */
+ /* Check that the difference between the two hrtime values is somewhat in */
+ /* the range we expect it to be. */
+ ASSERT(diff > (uint64_t) 25 * NANOSEC / MILLISEC);
+ ASSERT(diff < (uint64_t) 60 * NANOSEC / MILLISEC);
+ --i;
+ }
return 0;
}
TEST_DECLARE (tcp_listen_without_bind)
TEST_DECLARE (tcp_connect_error_fault)
TEST_DECLARE (tcp_connect_timeout)
+TEST_DECLARE (tcp_close_while_connecting)
TEST_DECLARE (tcp_close)
TEST_DECLARE (tcp_flags)
TEST_DECLARE (tcp_write_error)
TEST_ENTRY (tcp_listen_without_bind)
TEST_ENTRY (tcp_connect_error_fault)
TEST_ENTRY (tcp_connect_timeout)
+ TEST_ENTRY (tcp_close_while_connecting)
TEST_ENTRY (tcp_close)
TEST_ENTRY (tcp_flags)
TEST_ENTRY (tcp_write_error)
--- /dev/null
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "task.h"
+
+static uv_timer_t timer1_handle;
+static uv_timer_t timer2_handle;
+static uv_tcp_t tcp_handle;
+
+static int connect_cb_called;
+static int timer1_cb_called;
+static int close_cb_called;
+
+
+static void close_cb(uv_handle_t* handle) {
+ close_cb_called++;
+}
+
+
+static void connect_cb(uv_connect_t* req, int status) {
+ ASSERT(status == -1);
+ ASSERT(uv_last_error(req->handle->loop).code == UV_EINTR);
+ uv_timer_stop(&timer2_handle);
+ connect_cb_called++;
+}
+
+
+static void timer1_cb(uv_timer_t* handle, int status) {
+ uv_close((uv_handle_t*)handle, close_cb);
+ uv_close((uv_handle_t*)&tcp_handle, close_cb);
+ timer1_cb_called++;
+}
+
+
+static void timer2_cb(uv_timer_t* handle, int status) {
+ ASSERT(0 && "should not be called");
+}
+
+
+TEST_IMPL(tcp_close_while_connecting) {
+ uv_connect_t connect_req;
+ struct sockaddr_in addr;
+ uv_loop_t* loop;
+
+ 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));
+ 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));
+ ASSERT(0 == uv_timer_start(&timer2_handle, timer2_cb, 86400 * 1000, 0));
+ ASSERT(0 == uv_run(loop));
+
+ ASSERT(connect_cb_called == 1);
+ ASSERT(timer1_cb_called == 1);
+ ASSERT(close_cb_called == 2);
+
+ return 0;
+}
}
+static void read_cb(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) {
+}
+
+
static void connect_cb(uv_connect_t* req, int status) {
+ int r;
+
ASSERT(status == 0);
connect_cb_called++;
-}
-
-static void read_cb(uv_stream_t* handle, ssize_t nread, uv_buf_t buf) {
+ r = uv_read_start((uv_stream_t*)&conn, alloc_cb, read_cb);
+ ASSERT(r == 0);
}
r = uv_tcp_connect(&connect_req, &conn, addr, connect_cb);
ASSERT(r == 0);
- r = uv_read_start((uv_stream_t*)&conn, alloc_cb, read_cb);
- ASSERT(r == 0);
-
r = uv_run(loop);
ASSERT(r == 0);
'test/test-tcp-bind-error.c',
'test/test-tcp-bind6-error.c',
'test/test-tcp-close.c',
+ 'test/test-tcp-close-while-connecting.c',
'test/test-tcp-connect-error-after-write.c',
'test/test-tcp-shutdown-after-write.c',
'test/test-tcp-flags.c',
'test/benchmark-getaddrinfo.c',
'test/benchmark-list.h',
'test/benchmark-loop-count.c',
+ 'test/benchmark-million-timers.c',
'test/benchmark-ping-pongs.c',
'test/benchmark-pound.c',
'test/benchmark-pump.c',