From 2c79f13634371d284d9a7034671d057b00cc609f Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Sun, 22 May 2011 13:05:48 -0700 Subject: [PATCH] Upgrade libuv to 40f0ad6d364cff76adaf1c7f182b1dc939f36617 --- deps/uv/config-mingw.mk | 7 +- deps/uv/config-unix.mk | 7 +- ...chmark.vcxproj => libuv-benchmark.vcxproj} | 0 ...liboio-test.vcxproj => libuv-test.vcxproj} | 3 +- deps/uv/msvs/{liboio.sln => libuv.sln} | 92 ++++---- .../uv/msvs/{liboio.vcxproj => libuv.vcxproj} | 3 + deps/uv/test/benchmark-ping-pongs.c | 20 +- deps/uv/test/benchmark-pump.c | 68 +++--- deps/uv/test/echo-server.c | 10 +- deps/uv/test/task.h | 4 +- deps/uv/test/test-async.c | 4 +- deps/uv/test/test-bind-error.c | 4 +- deps/uv/test/test-callback-stack.c | 40 ++-- deps/uv/test/test-connection-fail.c | 4 +- deps/uv/test/test-delayed-accept.c | 37 ++-- deps/uv/test/test-list.h | 19 +- deps/uv/test/test-loop-handles.c | 87 ++++++-- deps/uv/test/test-ping-pong.c | 8 +- deps/uv/test/test-tcp-writealot.c | 10 +- deps/uv/test/test-timeout.c | 105 --------- deps/uv/test/test-timer-again.c | 153 +++++++++++++ deps/uv/test/test-timer.c | 148 +++++++++++++ deps/uv/uv-common.c | 69 ++++++ deps/uv/uv-unix.c | 205 +++++++++++++---- deps/uv/uv-unix.h | 9 +- deps/uv/uv-win.c | 207 ++++++++++++++---- deps/uv/uv-win.h | 56 ++--- deps/uv/uv.h | 36 ++- src/node.cc | 7 +- 29 files changed, 1025 insertions(+), 397 deletions(-) rename deps/uv/msvs/{liboio-benchmark.vcxproj => libuv-benchmark.vcxproj} (100%) rename deps/uv/msvs/{liboio-test.vcxproj => libuv-test.vcxproj} (98%) rename deps/uv/msvs/{liboio.sln => libuv.sln} (77%) rename deps/uv/msvs/{liboio.vcxproj => libuv.vcxproj} (98%) delete mode 100644 deps/uv/test/test-timeout.c create mode 100644 deps/uv/test/test-timer-again.c create mode 100644 deps/uv/test/test-timer.c create mode 100644 deps/uv/uv-common.c diff --git a/deps/uv/config-mingw.mk b/deps/uv/config-mingw.mk index 054e1ce2ad..7cd59d0f25 100644 --- a/deps/uv/config-mingw.mk +++ b/deps/uv/config-mingw.mk @@ -32,11 +32,14 @@ RUNNER_LINKFLAGS=$(LINKFLAGS) RUNNER_LIBS=-lws2_32 RUNNER_SRC=test/runner-win.c -uv.a: uv-win.o - $(AR) rcs uv.a uv-win.o +uv.a: uv-win.o uv-common.o + $(AR) rcs uv.a uv-win.o uv-common.o uv-win.o: uv-win.c uv.h uv-win.h $(CC) $(CFLAGS) -c uv-win.c -o uv-win.o +uv-common.o: uv-common.c uv.h uv-win.h + $(CC) $(CFLAGS) -c uv-common.c -o uv-common.o + distclean-platform: clean-platform: diff --git a/deps/uv/config-unix.mk b/deps/uv/config-unix.mk index 500b1890c2..af8c7d8157 100644 --- a/deps/uv/config-unix.mk +++ b/deps/uv/config-unix.mk @@ -35,12 +35,15 @@ RUNNER_LINKFLAGS=$(LINKFLAGS) -pthread RUNNER_LIBS= RUNNER_SRC=test/runner-unix.c -uv.a: uv-unix.o ev/ev.o - $(AR) rcs uv.a uv-unix.o ev/ev.o +uv.a: uv-unix.o uv-common.o ev/ev.o + $(AR) rcs uv.a uv-unix.o uv-common.o ev/ev.o uv-unix.o: uv-unix.c uv.h uv-unix.h $(CC) $(CFLAGS) -c uv-unix.c -o uv-unix.o +uv-common.o: uv-common.c uv.h uv-unix.h + $(CC) $(CFLAGS) -c uv-common.c -o uv-common.o + ev/ev.o: ev/config.h ev/ev.c $(MAKE) -C ev diff --git a/deps/uv/msvs/liboio-benchmark.vcxproj b/deps/uv/msvs/libuv-benchmark.vcxproj similarity index 100% rename from deps/uv/msvs/liboio-benchmark.vcxproj rename to deps/uv/msvs/libuv-benchmark.vcxproj diff --git a/deps/uv/msvs/liboio-test.vcxproj b/deps/uv/msvs/libuv-test.vcxproj similarity index 98% rename from deps/uv/msvs/liboio-test.vcxproj rename to deps/uv/msvs/libuv-test.vcxproj index 0a8ff79d0a..7d1922a398 100644 --- a/deps/uv/msvs/liboio-test.vcxproj +++ b/deps/uv/msvs/libuv-test.vcxproj @@ -155,7 +155,8 @@ - + + diff --git a/deps/uv/msvs/liboio.sln b/deps/uv/msvs/libuv.sln similarity index 77% rename from deps/uv/msvs/liboio.sln rename to deps/uv/msvs/libuv.sln index a1cf5e76f4..e68d41d38c 100644 --- a/deps/uv/msvs/liboio.sln +++ b/deps/uv/msvs/libuv.sln @@ -1,46 +1,46 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libuv", "libuv.vcxproj", "{301FE650-CD34-14E5-6B63-42E383FA02BC}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libuv-test", "libuv-test.vcxproj", "{1D7C3F6C-A4AF-DD73-2D20-B2FC919B3744}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libuv-benchmark", "libuv-benchmark.vcxproj", "{65312F30-3B19-A87E-E8D1-491D0F4A6536}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Debug|x64 = Debug|x64 - Release|Win32 = Release|Win32 - Release|x64 = Release|x64 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {301FE650-CD34-14E5-6B63-42E383FA02BC}.Debug|Win32.ActiveCfg = Debug|Win32 - {301FE650-CD34-14E5-6B63-42E383FA02BC}.Debug|Win32.Build.0 = Debug|Win32 - {301FE650-CD34-14E5-6B63-42E383FA02BC}.Debug|x64.ActiveCfg = Debug|x64 - {301FE650-CD34-14E5-6B63-42E383FA02BC}.Debug|x64.Build.0 = Debug|x64 - {301FE650-CD34-14E5-6B63-42E383FA02BC}.Release|Win32.ActiveCfg = Release|Win32 - {301FE650-CD34-14E5-6B63-42E383FA02BC}.Release|Win32.Build.0 = Release|Win32 - {301FE650-CD34-14E5-6B63-42E383FA02BC}.Release|x64.ActiveCfg = Release|x64 - {301FE650-CD34-14E5-6B63-42E383FA02BC}.Release|x64.Build.0 = Release|x64 - {1D7C3F6C-A4AF-DD73-2D20-B2FC919B3744}.Debug|Win32.ActiveCfg = Debug|Win32 - {1D7C3F6C-A4AF-DD73-2D20-B2FC919B3744}.Debug|Win32.Build.0 = Debug|Win32 - {1D7C3F6C-A4AF-DD73-2D20-B2FC919B3744}.Debug|x64.ActiveCfg = Debug|x64 - {1D7C3F6C-A4AF-DD73-2D20-B2FC919B3744}.Debug|x64.Build.0 = Debug|x64 - {1D7C3F6C-A4AF-DD73-2D20-B2FC919B3744}.Release|Win32.ActiveCfg = Release|Win32 - {1D7C3F6C-A4AF-DD73-2D20-B2FC919B3744}.Release|Win32.Build.0 = Release|Win32 - {1D7C3F6C-A4AF-DD73-2D20-B2FC919B3744}.Release|x64.ActiveCfg = Release|x64 - {1D7C3F6C-A4AF-DD73-2D20-B2FC919B3744}.Release|x64.Build.0 = Release|x64 - {65312F30-3B19-A87E-E8D1-491D0F4A6536}.Debug|Win32.ActiveCfg = Debug|Win32 - {65312F30-3B19-A87E-E8D1-491D0F4A6536}.Debug|Win32.Build.0 = Debug|Win32 - {65312F30-3B19-A87E-E8D1-491D0F4A6536}.Debug|x64.ActiveCfg = Debug|x64 - {65312F30-3B19-A87E-E8D1-491D0F4A6536}.Debug|x64.Build.0 = Debug|x64 - {65312F30-3B19-A87E-E8D1-491D0F4A6536}.Release|Win32.ActiveCfg = Release|Win32 - {65312F30-3B19-A87E-E8D1-491D0F4A6536}.Release|Win32.Build.0 = Release|Win32 - {65312F30-3B19-A87E-E8D1-491D0F4A6536}.Release|x64.ActiveCfg = Release|x64 - {65312F30-3B19-A87E-E8D1-491D0F4A6536}.Release|x64.Build.0 = Release|x64 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libuv", "libuv.vcxproj", "{301FE650-CD34-14E5-6B63-42E383FA02BC}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libuv-test", "libuv-test.vcxproj", "{1D7C3F6C-A4AF-DD73-2D20-B2FC919B3744}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libuv-benchmark", "libuv-benchmark.vcxproj", "{6CCBDAFD-7A11-133D-357B-E2D2F4C621E4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {301FE650-CD34-14E5-6B63-42E383FA02BC}.Debug|Win32.ActiveCfg = Debug|Win32 + {301FE650-CD34-14E5-6B63-42E383FA02BC}.Debug|Win32.Build.0 = Debug|Win32 + {301FE650-CD34-14E5-6B63-42E383FA02BC}.Debug|x64.ActiveCfg = Debug|x64 + {301FE650-CD34-14E5-6B63-42E383FA02BC}.Debug|x64.Build.0 = Debug|x64 + {301FE650-CD34-14E5-6B63-42E383FA02BC}.Release|Win32.ActiveCfg = Release|Win32 + {301FE650-CD34-14E5-6B63-42E383FA02BC}.Release|Win32.Build.0 = Release|Win32 + {301FE650-CD34-14E5-6B63-42E383FA02BC}.Release|x64.ActiveCfg = Release|x64 + {301FE650-CD34-14E5-6B63-42E383FA02BC}.Release|x64.Build.0 = Release|x64 + {1D7C3F6C-A4AF-DD73-2D20-B2FC919B3744}.Debug|Win32.ActiveCfg = Debug|Win32 + {1D7C3F6C-A4AF-DD73-2D20-B2FC919B3744}.Debug|Win32.Build.0 = Debug|Win32 + {1D7C3F6C-A4AF-DD73-2D20-B2FC919B3744}.Debug|x64.ActiveCfg = Debug|x64 + {1D7C3F6C-A4AF-DD73-2D20-B2FC919B3744}.Debug|x64.Build.0 = Debug|x64 + {1D7C3F6C-A4AF-DD73-2D20-B2FC919B3744}.Release|Win32.ActiveCfg = Release|Win32 + {1D7C3F6C-A4AF-DD73-2D20-B2FC919B3744}.Release|Win32.Build.0 = Release|Win32 + {1D7C3F6C-A4AF-DD73-2D20-B2FC919B3744}.Release|x64.ActiveCfg = Release|x64 + {1D7C3F6C-A4AF-DD73-2D20-B2FC919B3744}.Release|x64.Build.0 = Release|x64 + {6CCBDAFD-7A11-133D-357B-E2D2F4C621E4}.Debug|Win32.ActiveCfg = Debug|Win32 + {6CCBDAFD-7A11-133D-357B-E2D2F4C621E4}.Debug|Win32.Build.0 = Debug|Win32 + {6CCBDAFD-7A11-133D-357B-E2D2F4C621E4}.Debug|x64.ActiveCfg = Debug|x64 + {6CCBDAFD-7A11-133D-357B-E2D2F4C621E4}.Debug|x64.Build.0 = Debug|x64 + {6CCBDAFD-7A11-133D-357B-E2D2F4C621E4}.Release|Win32.ActiveCfg = Release|Win32 + {6CCBDAFD-7A11-133D-357B-E2D2F4C621E4}.Release|Win32.Build.0 = Release|Win32 + {6CCBDAFD-7A11-133D-357B-E2D2F4C621E4}.Release|x64.ActiveCfg = Release|x64 + {6CCBDAFD-7A11-133D-357B-E2D2F4C621E4}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/deps/uv/msvs/liboio.vcxproj b/deps/uv/msvs/libuv.vcxproj similarity index 98% rename from deps/uv/msvs/liboio.vcxproj rename to deps/uv/msvs/libuv.vcxproj index 3c7f2e1aa6..7b11f49e37 100644 --- a/deps/uv/msvs/liboio.vcxproj +++ b/deps/uv/msvs/libuv.vcxproj @@ -119,9 +119,12 @@ true + + + diff --git a/deps/uv/test/benchmark-ping-pongs.c b/deps/uv/test/benchmark-ping-pongs.c index 7731c3305d..1bda337779 100644 --- a/deps/uv/test/benchmark-ping-pongs.c +++ b/deps/uv/test/benchmark-ping-pongs.c @@ -39,7 +39,7 @@ typedef struct { } pinger_t; typedef struct buf_s { - uv_buf uv_buf; + uv_buf_t uv_buf_t; struct buf_s* next; } buf_t; @@ -52,26 +52,26 @@ static int completed_pingers = 0; static int64_t start_time; -static uv_buf buf_alloc(uv_handle_t* handle, size_t size) { +static uv_buf_t buf_alloc(uv_handle_t* handle, size_t size) { buf_t* ab; ab = buf_freelist; if (ab != NULL) { buf_freelist = ab->next; - return ab->uv_buf; + return ab->uv_buf_t; } ab = (buf_t*) malloc(size + sizeof *ab); - ab->uv_buf.len = size; - ab->uv_buf.base = ((char*) ab) + sizeof *ab; + ab->uv_buf_t.len = size; + ab->uv_buf_t.base = ((char*) ab) + sizeof *ab; - return ab->uv_buf; + return ab->uv_buf_t; } -static void buf_free(uv_buf uv_buf) { - buf_t* ab = (buf_t*) (uv_buf.base - sizeof *ab); +static void buf_free(uv_buf_t uv_buf_t) { + buf_t* ab = (buf_t*) (uv_buf_t.base - sizeof *ab); ab->next = buf_freelist; buf_freelist = ab; @@ -101,7 +101,7 @@ static void pinger_write_cb(uv_req_t *req, int status) { static void pinger_write_ping(pinger_t* pinger) { uv_req_t *req; - uv_buf buf; + uv_buf_t buf; buf.base = (char*)&PING; buf.len = strlen(PING); @@ -120,7 +120,7 @@ static void pinger_shutdown_cb(uv_handle_t* handle, int status) { } -static void pinger_read_cb(uv_handle_t* handle, int nread, uv_buf buf) { +static void pinger_read_cb(uv_handle_t* handle, int nread, uv_buf_t buf) { unsigned int i; pinger_t* pinger; diff --git a/deps/uv/test/benchmark-pump.c b/deps/uv/test/benchmark-pump.c index 69773e1313..e9b3031ca0 100644 --- a/deps/uv/test/benchmark-pump.c +++ b/deps/uv/test/benchmark-pump.c @@ -41,11 +41,12 @@ static void maybe_connect_some(); static uv_req_t* req_alloc(); static void req_free(uv_req_t* uv_req); -static uv_buf buf_alloc(uv_handle_t* handle, size_t size); -static void buf_free(uv_buf uv_buf); +static uv_buf_t buf_alloc(uv_handle_t* handle, size_t size); +static void buf_free(uv_buf_t uv_buf_t); -static struct sockaddr_in server_addr; +static struct sockaddr_in listen_addr; +static struct sockaddr_in connect_addr; static int64_t start_time; @@ -65,6 +66,8 @@ static char write_buffer[WRITE_BUFFER_SIZE]; static uv_handle_t read_handles[TARGET_CONNECTIONS]; static uv_handle_t write_handles[TARGET_CONNECTIONS]; +static uv_handle_t timer_handle; + static double gbit(int64_t bytes, int64_t passed_ms) { double gbits = ((double)bytes / (1024 * 1024 * 1024)) * 8; @@ -72,21 +75,21 @@ static double gbit(int64_t bytes, int64_t passed_ms) { } -static void show_stats(uv_req_t *req, int64_t skew, int status) { - int64_t msec = STATS_INTERVAL + skew; +static void show_stats(uv_handle_t *handle, int status) { + int64_t diff; #if PRINT_STATS LOGF("connections: %d, read: %.1f gbit/s, write: %.1f gbit/s\n", read_sockets, - gbit(nrecv, msec), - gbit(nsent, msec)); + gbit(nrecv, STATS_INTERVAL), + gbit(nsent, STATS_INTERVAL)); #endif /* Exit if the show is over */ if (!--stats_left) { uv_update_time(); - int64_t diff = uv_now() - start_time; + diff = uv_now() - start_time; LOGF("pump_%d: %.1f gbit/s\n", read_sockets, gbit(nrecv_total, diff)); @@ -97,10 +100,11 @@ static void show_stats(uv_req_t *req, int64_t skew, int status) { /* Reset read and write counters */ nrecv = 0; nsent = 0; +} + - uv_timeout(req, (STATS_INTERVAL - skew > 0) - ? STATS_INTERVAL - skew - : 0); +void close_cb(uv_handle_t* handle, int status) { + ASSERT(status == 0); } @@ -108,20 +112,16 @@ static void start_stats_collection() { uv_req_t* req = req_alloc(); int r; - /* Show-stats timeout */ + /* Show-stats timer */ stats_left = STATS_COUNT; - uv_req_init(req, NULL, (void*)show_stats); - r = uv_timeout(req, STATS_INTERVAL); + r = uv_timer_init(&timer_handle, close_cb, NULL); + ASSERT(r == 0); + r = uv_timer_start(&timer_handle, show_stats, STATS_INTERVAL, STATS_INTERVAL); ASSERT(r == 0); } -void close_cb(uv_handle_t* handle, int status) { - ASSERT(status == 0); -} - - -static void read_cb(uv_handle_t* handle, int bytes, uv_buf buf) { +static void read_cb(uv_handle_t* handle, int bytes, uv_buf_t buf) { ASSERT(bytes >= 0); buf_free(buf); @@ -132,7 +132,7 @@ static void read_cb(uv_handle_t* handle, int bytes, uv_buf buf) { static void write_cb(uv_req_t *req, int status) { - uv_buf* buf = (uv_buf*) req->data; + uv_buf_t* buf = (uv_buf_t*) req->data; ASSERT(status == 0); @@ -147,7 +147,7 @@ static void write_cb(uv_req_t *req, int status) { static void do_write(uv_handle_t* handle) { uv_req_t* req; - uv_buf buf; + uv_buf_t buf; int r; buf.base = (char*) &write_buffer; @@ -207,7 +207,7 @@ static void maybe_connect_some() { while (max_connect_socket < TARGET_CONNECTIONS && max_connect_socket < write_sockets + MAX_SIMULTANEOUS_CONNECTS) { do_connect(&write_handles[max_connect_socket++], - (struct sockaddr*) &server_addr); + (struct sockaddr*) &connect_addr); } } @@ -237,11 +237,13 @@ BENCHMARK_IMPL(pump) { uv_init(buf_alloc); + listen_addr = uv_ip4_addr("0.0.0.0", TEST_PORT); + connect_addr = uv_ip4_addr("127.0.0.1", TEST_PORT); + /* Server */ - server_addr = uv_ip4_addr("127.0.0.1", TEST_PORT); r = uv_tcp_init(&server, close_cb, NULL); ASSERT(r == 0); - r = uv_bind(&server, (struct sockaddr*) &server_addr); + r = uv_bind(&server, (struct sockaddr*) &listen_addr); ASSERT(r == 0); r = uv_listen(&server, TARGET_CONNECTIONS, accept_cb); ASSERT(r == 0); @@ -298,7 +300,7 @@ static void req_free(uv_req_t* uv_req) { */ typedef struct buf_list_s { - uv_buf uv_buf; + uv_buf_t uv_buf_t; struct buf_list_s* next; } buf_list_t; @@ -306,25 +308,25 @@ typedef struct buf_list_s { static buf_list_t* buf_freelist = NULL; -static uv_buf buf_alloc(uv_handle_t* handle, size_t size) { +static uv_buf_t buf_alloc(uv_handle_t* handle, size_t size) { buf_list_t* buf; buf = buf_freelist; if (buf != NULL) { buf_freelist = buf->next; - return buf->uv_buf; + return buf->uv_buf_t; } buf = (buf_list_t*) malloc(size + sizeof *buf); - buf->uv_buf.len = (unsigned int)size; - buf->uv_buf.base = ((char*) buf) + sizeof *buf; + buf->uv_buf_t.len = (unsigned int)size; + buf->uv_buf_t.base = ((char*) buf) + sizeof *buf; - return buf->uv_buf; + return buf->uv_buf_t; } -static void buf_free(uv_buf uv_buf) { - buf_list_t* buf = (buf_list_t*) (uv_buf.base - sizeof *buf); +static void buf_free(uv_buf_t uv_buf_t) { + buf_list_t* buf = (buf_list_t*) (uv_buf_t.base - sizeof *buf); buf->next = buf_freelist; buf_freelist = buf; diff --git a/deps/uv/test/echo-server.c b/deps/uv/test/echo-server.c index 32a415c8c9..0fcc935f36 100644 --- a/deps/uv/test/echo-server.c +++ b/deps/uv/test/echo-server.c @@ -27,7 +27,7 @@ typedef struct { uv_req_t req; - uv_buf buf; + uv_buf_t buf; } write_req_t; @@ -35,7 +35,7 @@ static uv_handle_t server; static void after_write(uv_req_t* req, int status); -static void after_read(uv_handle_t* handle, int nread, uv_buf buf); +static void after_read(uv_handle_t* handle, int nread, uv_buf_t buf); static void on_close(uv_handle_t* peer, int status); static void on_accept(uv_handle_t* handle); @@ -62,7 +62,7 @@ static void after_shutdown(uv_req_t* req, int status) { } -static void after_read(uv_handle_t* handle, int nread, uv_buf buf) { +static void after_read(uv_handle_t* handle, int nread, uv_buf_t buf) { write_req_t *wr; uv_req_t* req; @@ -156,8 +156,8 @@ static int echo_stop() { } -static uv_buf echo_alloc(uv_handle_t* handle, size_t suggested_size) { - uv_buf buf; +static uv_buf_t echo_alloc(uv_handle_t* handle, size_t suggested_size) { + uv_buf_t buf; buf.base = (char*) malloc(suggested_size); buf.len = suggested_size; return buf; diff --git a/deps/uv/test/task.h b/deps/uv/test/task.h index 50c3784032..8d9a1e8e0d 100644 --- a/deps/uv/test/task.h +++ b/deps/uv/test/task.h @@ -27,8 +27,8 @@ #include #include -#define TEST_PORT 8123 -#define TEST_PORT_2 8124 +#define TEST_PORT 9123 +#define TEST_PORT_2 9124 /* Log to stderr. */ diff --git a/deps/uv/test/test-async.c b/deps/uv/test/test-async.c index d43fdcca21..7bedcf4a95 100644 --- a/deps/uv/test/test-async.c +++ b/deps/uv/test/test-async.c @@ -120,8 +120,8 @@ static void close_cb(uv_handle_t* handle, int status) { } -static uv_buf alloc_cb(uv_handle_t* handle, size_t size) { - uv_buf buf = {0, 0}; +static uv_buf_t alloc_cb(uv_handle_t* handle, size_t size) { + uv_buf_t buf = {0, 0}; FATAL("alloc should not be called"); return buf; } diff --git a/deps/uv/test/test-bind-error.c b/deps/uv/test/test-bind-error.c index a29914a9aa..ca9ccc5885 100644 --- a/deps/uv/test/test-bind-error.c +++ b/deps/uv/test/test-bind-error.c @@ -36,8 +36,8 @@ static void close_cb(uv_handle_t* handle, int status) { } -static uv_buf alloc_cb(uv_handle_t* handle, size_t size) { - uv_buf buf = {0, 0}; +static uv_buf_t alloc_cb(uv_handle_t* handle, size_t size) { + uv_buf_t buf = {0, 0}; FATAL("alloc should not be called"); return buf; } diff --git a/deps/uv/test/test-callback-stack.c b/deps/uv/test/test-callback-stack.c index 986f863dc3..d136c9a764 100644 --- a/deps/uv/test/test-callback-stack.c +++ b/deps/uv/test/test-callback-stack.c @@ -30,14 +30,14 @@ static const char MESSAGE[] = "Failure is for the weak. Everyone dies alone."; -static uv_handle_t client; -static uv_req_t connect_req, write_req, timeout_req, shutdown_req; +static uv_handle_t client, timer; +static uv_req_t connect_req, write_req, shutdown_req; static int nested = 0; static int close_cb_called = 0; static int connect_cb_called = 0; static int write_cb_called = 0; -static int timeout_cb_called = 0; +static int timer_cb_called = 0; static int bytes_received = 0; static int shutdown_cb_called = 0; @@ -58,7 +58,7 @@ static void shutdown_cb(uv_req_t* req, int status) { } -static void read_cb(uv_handle_t* handle, int nread, uv_buf buf) { +static void read_cb(uv_handle_t* handle, int nread, uv_buf_t buf) { ASSERT(nested == 0 && "read_cb must be called from a fresh stack"); printf("Read. nread == %d\n", nread); @@ -100,9 +100,12 @@ static void read_cb(uv_handle_t* handle, int nread, uv_buf buf) { } -static void timeout_cb(uv_req_t* req, int64_t skew, int status) { +static void timer_cb(uv_handle_t* handle, int status) { + int r; + + ASSERT(handle == &timer); ASSERT(status == 0); - ASSERT(nested == 0 && "timeout_cb must be called from a fresh stack"); + ASSERT(nested == 0 && "timer_cb must be called from a fresh stack"); puts("Timeout complete. Now read data..."); @@ -112,11 +115,16 @@ static void timeout_cb(uv_req_t* req, int64_t skew, int status) { } nested--; - timeout_cb_called++; + timer_cb_called++; + + r = uv_close(handle); + ASSERT(r == 0); } static void write_cb(uv_req_t* req, int status) { + int r; + ASSERT(status == 0); ASSERT(nested == 0 && "write_cb must be called from a fresh stack"); @@ -127,10 +135,10 @@ static void write_cb(uv_req_t* req, int status) { /* back to our receive buffer when we start reading. This maximizes the */ /* tempation for the backend to use dirty stack for calling read_cb. */ nested++; - uv_req_init(&timeout_req, NULL, timeout_cb); - if (uv_timeout(&timeout_req, 500)) { - FATAL("uv_timeout failed"); - } + r = uv_timer_init(&timer, close_cb, NULL); + ASSERT(r == 0); + r = uv_timer_start(&timer, timer_cb, 500, 0); + ASSERT(r == 0); nested--; write_cb_called++; @@ -138,7 +146,7 @@ static void write_cb(uv_req_t* req, int status) { static void connect_cb(uv_req_t* req, int status) { - uv_buf buf; + uv_buf_t buf; puts("Connected. Write some data to echo server..."); @@ -162,8 +170,8 @@ static void connect_cb(uv_req_t* req, int status) { } -static uv_buf alloc_cb(uv_handle_t* handle, size_t size) { - uv_buf buf; +static uv_buf_t alloc_cb(uv_handle_t* handle, size_t size) { + uv_buf_t buf; buf.len = size; buf.base = (char*) malloc(size); ASSERT(buf.base); @@ -194,10 +202,10 @@ TEST_IMPL(callback_stack) { ASSERT(nested == 0); ASSERT(connect_cb_called == 1 && "connect_cb must be called exactly once"); ASSERT(write_cb_called == 1 && "write_cb must be called exactly once"); - ASSERT(timeout_cb_called == 1 && "timeout_cb must be called exactly once"); + ASSERT(timer_cb_called == 1 && "timer_cb must be called exactly once"); ASSERT(bytes_received == sizeof MESSAGE); ASSERT(shutdown_cb_called == 1 && "shutdown_cb must be called exactly once"); - ASSERT(close_cb_called == 1 && "close_cb must be called exactly once"); + ASSERT(close_cb_called == 2 && "close_cb must be called exactly twice"); return 0; } diff --git a/deps/uv/test/test-connection-fail.c b/deps/uv/test/test-connection-fail.c index ef060d1d25..e28c7c36e6 100644 --- a/deps/uv/test/test-connection-fail.c +++ b/deps/uv/test/test-connection-fail.c @@ -46,8 +46,8 @@ static void on_connect(uv_req_t *req, int status) { } -static uv_buf alloc_cb(uv_handle_t* handle, size_t size) { - uv_buf buf = {0, 0}; +static uv_buf_t alloc_cb(uv_handle_t* handle, size_t size) { + uv_buf_t buf = {0, 0}; FATAL("alloc should not be called"); return buf; } diff --git a/deps/uv/test/test-delayed-accept.c b/deps/uv/test/test-delayed-accept.c index 3c8a55f4ba..e372b955c4 100644 --- a/deps/uv/test/test-delayed-accept.c +++ b/deps/uv/test/test-delayed-accept.c @@ -43,42 +43,49 @@ static void close_cb(uv_handle_t* handle, int status) { } -static void do_accept(uv_req_t* req, int64_t skew, int status) { +static void do_accept(uv_handle_t* timer_handle, int status) { uv_handle_t* server; uv_handle_t* accepted_handle = (uv_handle_t*)malloc(sizeof *accepted_handle); int r; - ASSERT(req != NULL); + ASSERT(timer_handle != NULL); ASSERT(status == 0); ASSERT(accepted_handle != NULL); - server = (uv_handle_t*)req->data; + server = (uv_handle_t*)timer_handle->data; r = uv_accept(server, accepted_handle, close_cb, NULL); ASSERT(r == 0); do_accept_called++; /* Immediately close the accepted handle. */ - uv_close(accepted_handle); + r = uv_close(accepted_handle); + ASSERT(r == 0); /* After accepting the two clients close the server handle */ if (do_accept_called == 2) { - uv_close(server); + r = uv_close(server); + ASSERT(r == 0); } - free(req); + /* Dispose the timer. */ + r = uv_close(timer_handle); + ASSERT(r == 0); } static void accept_cb(uv_handle_t* handle) { - uv_req_t* timeout_req = (uv_req_t*)malloc(sizeof *timeout_req); + int r; + uv_handle_t* timer_handle; - ASSERT(timeout_req != NULL); + timer_handle = (uv_handle_t*)malloc(sizeof *timer_handle); + ASSERT(timer_handle != NULL); /* Accept the client after 1 second */ - uv_req_init(timeout_req, NULL, &do_accept); - timeout_req->data = (void*)handle; - uv_timeout(timeout_req, 1000); + r = uv_timer_init(timer_handle, close_cb, (void*)handle); + ASSERT(r == 0); + r = uv_timer_start(timer_handle, do_accept, 1000, 0); + ASSERT(r == 0); accept_cb_called++; } @@ -102,7 +109,7 @@ static void start_server() { } -static void read_cb(uv_handle_t* handle, int nread, uv_buf buf) { +static void read_cb(uv_handle_t* handle, int nread, uv_buf_t buf) { /* The server will not send anything, it should close gracefully. */ ASSERT(handle != NULL); ASSERT(nread == -1); @@ -151,8 +158,8 @@ static void client_connect() { } -static uv_buf alloc_cb(uv_handle_t* handle, size_t size) { - uv_buf buf; +static uv_buf_t alloc_cb(uv_handle_t* handle, size_t size) { + uv_buf_t buf; buf.base = (char*)malloc(size); buf.len = size; return buf; @@ -173,7 +180,7 @@ TEST_IMPL(delayed_accept) { ASSERT(accept_cb_called == 2); ASSERT(do_accept_called == 2); ASSERT(connect_cb_called == 2); - ASSERT(close_cb_called == 5); + ASSERT(close_cb_called == 7); return 0; } diff --git a/deps/uv/test/test-list.h b/deps/uv/test/test-list.h index 0cf3518b5b..499d6503c7 100644 --- a/deps/uv/test/test-list.h +++ b/deps/uv/test/test-list.h @@ -29,8 +29,14 @@ TEST_DECLARE (bind_error_fault) TEST_DECLARE (bind_error_inval) TEST_DECLARE (connection_fail) TEST_DECLARE (callback_stack) -TEST_DECLARE (timeout) +TEST_DECLARE (timer) +TEST_DECLARE (timer_again) TEST_DECLARE (loop_handles) +TEST_DECLARE (ref) +TEST_DECLARE (idle_ref) +TEST_DECLARE (async_ref) +TEST_DECLARE (prepare_ref) +TEST_DECLARE (check_ref) TEST_DECLARE (async) TEST_DECLARE (fail_always) TEST_DECLARE (pass_always) @@ -60,7 +66,15 @@ TASK_LIST_START TEST_ENTRY (callback_stack) TEST_HELPER (callback_stack, echo_server) - TEST_ENTRY (timeout) + TEST_ENTRY (timer) + + TEST_ENTRY (timer_again) + + TEST_ENTRY (ref) + TEST_ENTRY (idle_ref) + TEST_ENTRY (async_ref) + TEST_ENTRY (prepare_ref) + TEST_ENTRY (check_ref) TEST_ENTRY (loop_handles) @@ -72,3 +86,4 @@ TASK_LIST_START TEST_ENTRY (pass_always) #endif TASK_LIST_END + diff --git a/deps/uv/test/test-loop-handles.c b/deps/uv/test/test-loop-handles.c index 65c84b1b75..77055b43ef 100644 --- a/deps/uv/test/test-loop-handles.c +++ b/deps/uv/test/test-loop-handles.c @@ -58,9 +58,9 @@ * being started by a check_1 watcher. It verifies that a watcher is * implicitly stopped when closed, and that a watcher can close itself * safely. - * - There is a timeout request that reposts itself after every timeout. It - * does not keep te event loop alive (ev_unref) but makes sure that the loop - * keeps polling the system for events. + * - There is a repeating timer. It does not keep te event loop alive + * (ev_unref) but makes sure that the loop keeps polling the system for + * events. */ @@ -83,7 +83,7 @@ static uv_handle_t check_handle; static uv_handle_t idle_1_handles[IDLE_COUNT]; static uv_handle_t idle_2_handle; -static uv_req_t timeout_req; +static uv_handle_t timer_handle; static int loop_iteration = 0; @@ -106,19 +106,19 @@ static int idle_2_close_cb_called = 0; static int idle_2_cb_started = 0; static int idle_2_is_active = 0; -static int timeout_cb_called = 0; +static int timer_cb_called = 0; -static void timeout_cb(uv_req_t *req, int64_t skew, int status) { - int r; - - ASSERT(req == &timeout_req); +static void timer_cb(uv_handle_t* handle, int status) { + ASSERT(handle == &timer_handle); ASSERT(status == 0); - timeout_cb_called++; + timer_cb_called++; +} - r = uv_timeout(req, TIMEOUT); - ASSERT(r == 0); + +static void timer_close_cb(uv_handle_t* handle, int status) { + FATAL("timer_close_cb should not be called"); } @@ -270,7 +270,7 @@ static void prepare_2_cb(uv_handle_t* handle, int status) { } -static void prepare_2_close_cb(uv_handle_t* handle, int status){ +static void prepare_2_close_cb(uv_handle_t* handle, int status) { LOG("PREPARE_2_CLOSE_CB\n"); ASSERT(handle == &prepare_2_handle); ASSERT(status == 0); @@ -313,8 +313,8 @@ static void prepare_1_close_cb(uv_handle_t* handle, int status){ } -static uv_buf alloc_cb(uv_handle_t* handle, size_t size) { - uv_buf rv = { 0, 0 }; +static uv_buf_t alloc_cb(uv_handle_t* handle, size_t size) { + uv_buf_t rv = { 0, 0 }; FATAL("alloc_cb should never be called in this test"); return rv; } @@ -350,8 +350,9 @@ TEST_IMPL(loop_handles) { /* the timer callback is there to keep the event loop polling */ /* unref it as it is not supposed to keep the loop alive */ - uv_req_init(&timeout_req, NULL, timeout_cb); - r = uv_timeout(&timeout_req, TIMEOUT); + r = uv_timer_init(&timer_handle, timer_close_cb, NULL); + ASSERT(r == 0); + r = uv_timer_start(&timer_handle, timer_cb, TIMEOUT, TIMEOUT); ASSERT(r == 0); uv_unref(); @@ -379,7 +380,57 @@ TEST_IMPL(loop_handles) { ASSERT(idle_2_close_cb_called == idle_2_cb_started); ASSERT(idle_2_is_active == 0); - ASSERT(timeout_cb_called > 0); + ASSERT(timer_cb_called > 0); + + return 0; +} + + +TEST_IMPL(ref) { + uv_init(alloc_cb); + uv_run(); + return 0; +} + +TEST_IMPL(idle_ref) { + uv_handle_t h; + uv_init(alloc_cb); + uv_idle_init(&h, NULL, NULL); + uv_idle_start(&h, NULL); + uv_unref(&h); + uv_run(); + return 0; +} + + +TEST_IMPL(async_ref) { + uv_handle_t h; + uv_init(alloc_cb); + uv_async_init(&h, NULL, NULL, NULL); + uv_unref(&h); + uv_run(); + return 0; +} + + +TEST_IMPL(prepare_ref) { + uv_handle_t h; + uv_init(alloc_cb); + uv_prepare_init(&h, NULL, NULL); + uv_prepare_start(&h, NULL); + uv_unref(&h); + uv_run(); + return 0; +} + + +TEST_IMPL(check_ref) { + uv_handle_t h; + uv_init(alloc_cb); + uv_check_init(&h, NULL, NULL); + uv_check_start(&h, NULL); + uv_unref(&h); + uv_run(); return 0; } diff --git a/deps/uv/test/test-ping-pong.c b/deps/uv/test/test-ping-pong.c index 56ea1db18c..13d114e32d 100644 --- a/deps/uv/test/test-ping-pong.c +++ b/deps/uv/test/test-ping-pong.c @@ -69,7 +69,7 @@ static void pinger_after_write(uv_req_t *req, int status) { static void pinger_write_ping(pinger_t* pinger) { uv_req_t *req; - uv_buf buf; + uv_buf_t buf; buf.base = (char*)&PING; buf.len = strlen(PING); @@ -85,7 +85,7 @@ static void pinger_write_ping(pinger_t* pinger) { } -static void pinger_read_cb(uv_handle_t* handle, int nread, uv_buf buf) { +static void pinger_read_cb(uv_handle_t* handle, int nread, uv_buf_t buf) { unsigned int i; pinger_t* pinger; @@ -156,8 +156,8 @@ static void pinger_new() { } -static uv_buf alloc_cb(uv_handle_t* handle, size_t size) { - uv_buf buf; +static uv_buf_t alloc_cb(uv_handle_t* handle, size_t size) { + uv_buf_t buf; buf.base = (char*)malloc(size); buf.len = size; return buf; diff --git a/deps/uv/test/test-tcp-writealot.c b/deps/uv/test/test-tcp-writealot.c index 996599972a..15cc2d5b6f 100644 --- a/deps/uv/test/test-tcp-writealot.c +++ b/deps/uv/test/test-tcp-writealot.c @@ -72,7 +72,7 @@ static void shutdown_cb(uv_req_t* req, int status) { } -static void read_cb(uv_handle_t* handle, int nread, uv_buf buf) { +static void read_cb(uv_handle_t* handle, int nread, uv_buf_t buf) { ASSERT(handle != NULL); if (nread < 0) { @@ -110,7 +110,7 @@ static void write_cb(uv_req_t* req, int status) { static void connect_cb(uv_req_t* req, int status) { - uv_buf send_bufs[CHUNKS_PER_WRITE]; + uv_buf_t send_bufs[CHUNKS_PER_WRITE]; uv_handle_t* handle; int i, j, r; @@ -134,7 +134,7 @@ static void connect_cb(uv_req_t* req, int status) { ASSERT(req != NULL); uv_req_init(req, handle, write_cb); - r = uv_write(req, (uv_buf*)&send_bufs, CHUNKS_PER_WRITE); + r = uv_write(req, (uv_buf_t*)&send_bufs, CHUNKS_PER_WRITE); ASSERT(r == 0); } @@ -155,8 +155,8 @@ static void connect_cb(uv_req_t* req, int status) { } -static uv_buf alloc_cb(uv_handle_t* handle, size_t size) { - uv_buf buf; +static uv_buf_t alloc_cb(uv_handle_t* handle, size_t size) { + uv_buf_t buf; buf.base = (char*)malloc(size); buf.len = size; return buf; diff --git a/deps/uv/test/test-timeout.c b/deps/uv/test/test-timeout.c deleted file mode 100644 index ea984eb6fd..0000000000 --- a/deps/uv/test/test-timeout.c +++ /dev/null @@ -1,105 +0,0 @@ -/* 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 int expected = 0; -static int timeouts = 0; - -static int64_t start_time; - -static void timeout_cb(uv_req_t *req, int64_t skew, int status) { - ASSERT(req != NULL); - ASSERT(status == 0); - - free(req); - timeouts++; - - /* Just call this randomly for the code coverage. */ - uv_update_time(); -} - -static void exit_timeout_cb(uv_req_t *req, int64_t skew, int status) { - int64_t now = uv_now(); - ASSERT(req != NULL); - ASSERT(status == 0); - ASSERT(timeouts == expected); - ASSERT(start_time < now); - exit(0); -} - -static void dummy_timeout_cb(uv_req_t *req, int64_t skew, int status) { - /* Should never be called */ - FATAL("dummy_timer_cb should never be called"); -} - - -static uv_buf alloc_cb(uv_handle_t* handle, size_t size) { - uv_buf buf = {0, 0}; - FATAL("alloc should not be called"); - return buf; -} - - -TEST_IMPL(timeout) { - uv_req_t *req; - uv_req_t exit_req; - uv_req_t dummy_req; - int i; - - uv_init(alloc_cb); - - start_time = uv_now(); - ASSERT(0 < start_time); - - /* Let 10 timers time out in 500 ms total. */ - for (i = 0; i < 10; i++) { - req = (uv_req_t*)malloc(sizeof(*req)); - ASSERT(req != NULL); - - uv_req_init(req, NULL, timeout_cb); - - if (uv_timeout(req, i * 50) < 0) { - FATAL("uv_timeout failed"); - } - - expected++; - } - - /* The 11th timer exits the test and runs after 1 s. */ - uv_req_init(&exit_req, NULL, exit_timeout_cb); - if (uv_timeout(&exit_req, 1000) < 0) { - FATAL("uv_timeout failed"); - } - - /* The 12th timer should never run. */ - uv_req_init(&dummy_req, NULL, dummy_timeout_cb); - if (uv_timeout(&dummy_req, 2000)) { - FATAL("uv_timeout failed"); - } - - uv_run(); - - FATAL("should never get here"); - return 2; -} diff --git a/deps/uv/test/test-timer-again.c b/deps/uv/test/test-timer-again.c new file mode 100644 index 0000000000..3d568e542b --- /dev/null +++ b/deps/uv/test/test-timer-again.c @@ -0,0 +1,153 @@ +/* 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 int close_cb_called = 0; +static int repeat_1_cb_called = 0; +static int repeat_2_cb_called = 0; + +static int repeat_2_cb_allowed = 0; + +static uv_handle_t dummy, repeat_1, repeat_2; + +static int64_t start_time; + + +static void close_cb(uv_handle_t* handle, int status) { + ASSERT(handle != NULL); + ASSERT(status == 0); + + close_cb_called++; +} + + +static void repeat_1_cb(uv_handle_t* handle, int status) { + int r; + + ASSERT(handle == &repeat_1); + ASSERT(status == 0); + + ASSERT(uv_timer_get_repeat(handle) == 50); + + LOGF("repeat_1_cb called after %ld ms\n", (long int)(uv_now() - start_time)); + + repeat_1_cb_called++; + + r = uv_timer_again(&repeat_2); + ASSERT(r == 0); + + if (uv_now() >= start_time + 500) { + uv_close(handle); + /* We're not calling uv_timer_again on repeat_2 any more, so after this */ + /* timer_2_cb is expected. */ + repeat_2_cb_allowed = 1; + return; + } +} + + +static void repeat_2_cb(uv_handle_t* handle, int status) { + ASSERT(handle == &repeat_2); + ASSERT(status == 0); + ASSERT(repeat_2_cb_allowed); + + LOGF("repeat_2_cb called after %ld ms\n", (long int)(uv_now() - start_time)); + + repeat_2_cb_called++; + + if (uv_timer_get_repeat(handle) == 0) { + /* XXX Libev does considers the timer active here. + * I'm not saying it must be this way, but we should consider what + * exactly the semantics of uv_is_active() should be. Is a timer that's + * initialized but stopped active? + */ + ASSERT(uv_is_active(handle)); + uv_close(handle); + return; + } + + LOGF("uv_timer_get_repeat %ld ms\n", (long int)uv_timer_get_repeat(handle)); + ASSERT(uv_timer_get_repeat(handle) == 100); + + /* This shouldn't take effect immediately. */ + uv_timer_set_repeat(&repeat_2, 0); +} + + +static uv_buf_t alloc_cb(uv_handle_t* handle, size_t size) { + uv_buf_t buf = {0, 0}; + FATAL("alloc should not be called"); + return buf; +} + + +TEST_IMPL(timer_again) { + int r; + + uv_init(alloc_cb); + + start_time = uv_now(); + ASSERT(0 < start_time); + + /* Verify that it is not possible to uv_timer_again a never-started timer. */ + r = uv_timer_init(&dummy, NULL, NULL); + ASSERT(r == 0); + r = uv_timer_again(&dummy); + ASSERT(r == -1); + ASSERT(uv_last_error().code == UV_EINVAL); + uv_unref(); + + /* Start timer repeat_1. */ + r = uv_timer_init(&repeat_1, close_cb, NULL); + ASSERT(r == 0); + r = uv_timer_start(&repeat_1, repeat_1_cb, 50, 0); + ASSERT(r == 0); + ASSERT(uv_timer_get_repeat(&repeat_1) == 0); + + /* Actually make repeat_1 repeating. */ + uv_timer_set_repeat(&repeat_1, 50); + ASSERT(uv_timer_get_repeat(&repeat_1) == 50); + + /* + * Start another repeating timer. It'll be again()ed by the repeat_1 so + * it should not time out until repeat_1 stops. + */ + r = uv_timer_init(&repeat_2, close_cb, NULL); + ASSERT(r == 0); + r = uv_timer_start(&repeat_2, repeat_2_cb, 100, 100); + ASSERT(r == 0); + ASSERT(uv_timer_get_repeat(&repeat_2) == 100); + + uv_run(); + + ASSERT(repeat_1_cb_called == 10); + ASSERT(repeat_2_cb_called == 2); + ASSERT(close_cb_called == 2); + + LOGF("Test took %ld ms (expected ~700 ms)\n", + (long int)(uv_now() - start_time)); + ASSERT(700 <= uv_now() - start_time); + + return 0; +} diff --git a/deps/uv/test/test-timer.c b/deps/uv/test/test-timer.c new file mode 100644 index 0000000000..15c80def2b --- /dev/null +++ b/deps/uv/test/test-timer.c @@ -0,0 +1,148 @@ +/* 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 int once_cb_called = 0; +static int once_close_cb_called = 0; +static int repeat_cb_called = 0; +static int repeat_close_cb_called = 0; + +static int64_t start_time; + + +static void once_close_cb(uv_handle_t* handle, int status) { + printf("ONCE_CLOSE_CB\n"); + + ASSERT(handle != NULL); + ASSERT(status == 0); + + once_close_cb_called++; + + free(handle); +} + + +static void once_cb(uv_handle_t* handle, int status) { + printf("ONCE_CB %d\n", once_cb_called); + + ASSERT(handle != NULL); + ASSERT(status == 0); + + once_cb_called++; + + uv_close(handle); + + /* Just call this randomly for the code coverage. */ + uv_update_time(); +} + + +static void repeat_close_cb(uv_handle_t* handle, int status) { + printf("REPEAT_CLOSE_CB\n"); + + ASSERT(handle != NULL); + ASSERT(status == 0); + + repeat_close_cb_called++; +} + + +static void repeat_cb(uv_handle_t* handle, int status) { + printf("REPEAT_CB\n"); + + ASSERT(handle != NULL); + ASSERT(status == 0); + + repeat_cb_called++; + + if (repeat_cb_called == 5) { + uv_close(handle); + } +} + + +static void never_close_cb(uv_handle_t* handle, int status) { + FATAL("never_close_cb should never be called"); +} + + +static void never_cb(uv_handle_t* handle, int status) { + FATAL("never_cb should never be called"); +} + + +static uv_buf_t alloc_cb(uv_handle_t* handle, size_t size) { + uv_buf_t buf = {0, 0}; + FATAL("alloc should not be called"); + return buf; +} + + +TEST_IMPL(timer) { + uv_handle_t *once; + uv_handle_t repeat, never; + int i, r; + + uv_init(alloc_cb); + + start_time = uv_now(); + ASSERT(0 < start_time); + + /* Let 10 timers time out in 500 ms total. */ + for (i = 0; i < 10; i++) { + once = (uv_handle_t*)malloc(sizeof(*once)); + ASSERT(once != NULL); + r = uv_timer_init(once, once_close_cb, NULL); + ASSERT(r == 0); + r = uv_timer_start(once, once_cb, i * 50, 0); + ASSERT(r == 0); + } + + /* The 11th timer is a repeating timer that runs 4 times */ + r = uv_timer_init(&repeat, repeat_close_cb, NULL); + ASSERT(r == 0); + r = uv_timer_start(&repeat, repeat_cb, 100, 100); + ASSERT(r == 0); + + /* The 12th timer should not do anything. */ + r = uv_timer_init(&never, never_close_cb, NULL); + ASSERT(r == 0); + r = uv_timer_start(&never, never_cb, 100, 100); + ASSERT(r == 0); + r = uv_timer_stop(&never); + ASSERT(r == 0); + uv_unref(); + + uv_run(); + + ASSERT(once_cb_called == 10); + ASSERT(once_close_cb_called == 10); + printf("repeat_cb_called %d\n", repeat_cb_called); + ASSERT(repeat_cb_called == 5); + ASSERT(repeat_close_cb_called == 1); + + ASSERT(500 <= uv_now() - start_time); + + return 0; +} diff --git a/deps/uv/uv-common.c b/deps/uv/uv-common.c new file mode 100644 index 0000000000..dd1b00c560 --- /dev/null +++ b/deps/uv/uv-common.c @@ -0,0 +1,69 @@ +/* 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 +#include /* NULL */ + + +const char* uv_err_name(uv_err_t err) { + switch (err.code) { + case UV_UNKNOWN: return "UNKNOWN"; + case UV_OK: return "OK"; + case UV_EOF: return "EOF"; + case UV_EACCESS: return "EACCESS"; + case UV_EAGAIN: return "EAGAIN"; + case UV_EADDRINUSE: return "EADDRINUSE"; + case UV_EADDRNOTAVAIL: return "EADDRNOTAVAIL"; + case UV_EAFNOSUPPORT: return "EAFNOSUPPORT"; + case UV_EALREADY: return "EALREADY"; + case UV_EBADF: return "EBADF"; + case UV_EBUSY: return "EBUSY"; + case UV_ECONNABORTED: return "ECONNABORTED"; + case UV_ECONNREFUSED: return "ECONNREFUSED"; + case UV_ECONNRESET: return "ECONNRESET"; + case UV_EDESTADDRREQ: return "EDESTADDRREQ"; + case UV_EFAULT: return "EFAULT"; + case UV_EHOSTUNREACH: return "EHOSTUNREACH"; + case UV_EINTR: return "EINTR"; + case UV_EINVAL: return "EINVAL"; + case UV_EISCONN: return "EISCONN"; + case UV_EMFILE: return "EMFILE"; + case UV_ENETDOWN: return "ENETDOWN"; + case UV_ENETUNREACH: return "ENETUNREACH"; + case UV_ENFILE: return "ENFILE"; + case UV_ENOBUFS: return "ENOBUFS"; + case UV_ENOMEM: return "ENOMEM"; + case UV_ENONET: return "ENONET"; + case UV_ENOPROTOOPT: return "ENOPROTOOPT"; + case UV_ENOTCONN: return "ENOTCONN"; + case UV_ENOTSOCK: return "ENOTSOCK"; + case UV_ENOTSUP: return "ENOTSUP"; + case UV_EPROTO: return "EPROTO"; + case UV_EPROTONOSUPPORT: return "EPROTONOSUPPORT"; + case UV_EPROTOTYPE: return "EPROTOTYPE"; + case UV_ETIMEDOUT: return "ETIMEDOUT"; + default: + assert(0); + return NULL; + } +} diff --git a/deps/uv/uv-unix.c b/deps/uv/uv-unix.c index 873f643441..d0511b1306 100644 --- a/deps/uv/uv-unix.c +++ b/deps/uv/uv-unix.c @@ -1,5 +1,4 @@ /* 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 @@ -134,19 +133,27 @@ int uv_close(uv_handle_t* handle) { break; case UV_PREPARE: - ev_prepare_stop(EV_DEFAULT_ &handle->prepare_watcher); + uv_prepare_stop(handle); break; case UV_CHECK: - ev_check_stop(EV_DEFAULT_ &handle->check_watcher); + uv_check_stop(handle); break; case UV_IDLE: - ev_idle_stop(EV_DEFAULT_ &handle->idle_watcher); + uv_idle_stop(handle); break; case UV_ASYNC: ev_async_stop(EV_DEFAULT_ &handle->async_watcher); + ev_ref(EV_DEFAULT_UC); + break; + + case UV_TIMER: + if (ev_is_active(&handle->timer_watcher)) { + ev_ref(EV_DEFAULT_UC); + } + ev_timer_stop(EV_DEFAULT_ &handle->timer_watcher); break; default: @@ -168,7 +175,13 @@ int uv_close(uv_handle_t* handle) { void uv_init(uv_alloc_cb cb) { assert(cb); alloc_cb = cb; - ev_default_loop(0); + + // Initialize the default ev loop. +#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 + ev_default_loop(EVBACKEND_KQUEUE); +#else + ev_default_loop(EVFLAG_AUTO); +#endif } @@ -187,6 +200,9 @@ static void uv__handle_init(uv_handle_t* handle, uv_handle_type type, ev_init(&handle->next_watcher, uv__next); handle->next_watcher.data = handle; + + /* Ref the loop until this handle is closed. See uv__finish_close. */ + ev_ref(EV_DEFAULT_UC); } @@ -425,6 +441,14 @@ void uv__finish_close(uv_handle_t* handle) { case UV_ASYNC: assert(!ev_is_active(&handle->async_watcher)); break; + + case UV_TIMER: + assert(!ev_is_active(&handle->timer_watcher)); + break; + + default: + assert(0); + break; } ev_idle_stop(EV_DEFAULT_ &handle->next_watcher); @@ -432,6 +456,8 @@ void uv__finish_close(uv_handle_t* handle) { if (handle->close_cb) { handle->close_cb(handle, 0); } + + ev_unref(EV_DEFAULT_UC); } @@ -509,10 +535,10 @@ void uv__write(uv_handle_t* handle) { assert(req->handle == handle); - /* Cast to iovec. We had to have our own uv_buf instead of iovec + /* Cast to iovec. We had to have our own uv_buf_t instead of iovec * because Windows's WSABUF is not an iovec. */ - assert(sizeof(uv_buf) == sizeof(struct iovec)); + assert(sizeof(uv_buf_t) == sizeof(struct iovec)); struct iovec* iov = (struct iovec*) &(req->bufs[req->write_index]); int iovcnt = req->bufcnt - req->write_index; @@ -541,7 +567,7 @@ void uv__write(uv_handle_t* handle) { /* The loop updates the counters. */ while (n > 0) { - uv_buf* buf = &(req->bufs[req->write_index]); + uv_buf_t* buf = &(req->bufs[req->write_index]); size_t len = buf->len; assert(req->write_index < req->bufcnt); @@ -607,7 +633,7 @@ void uv__read(uv_handle_t* handle) { */ while (handle->read_cb && uv_flag_is_set(handle, UV_READING)) { assert(alloc_cb); - uv_buf buf = alloc_cb(handle, 64 * 1024); + uv_buf_t buf = alloc_cb(handle, 64 * 1024); assert(buf.len > 0); assert(buf.base); @@ -813,7 +839,7 @@ int uv_connect(uv_req_t* req, struct sockaddr* addr) { } -static size_t uv__buf_count(uv_buf bufs[], int bufcnt) { +static size_t uv__buf_count(uv_buf_t bufs[], int bufcnt) { size_t total = 0; int i; @@ -826,9 +852,9 @@ static size_t uv__buf_count(uv_buf bufs[], int bufcnt) { /* The buffers to be written must remain valid until the callback is called. - * This is not required for the uv_buf array. + * This is not required for the uv_buf_t array. */ -int uv_write(uv_req_t* req, uv_buf bufs[], int bufcnt) { +int uv_write(uv_req_t* req, uv_buf_t bufs[], int bufcnt) { uv_handle_t* handle = req->handle; assert(handle->fd >= 0); @@ -836,8 +862,8 @@ int uv_write(uv_req_t* req, uv_buf bufs[], int bufcnt) { req->type = UV_WRITE; /* TODO: Don't malloc for each write... */ - req->bufs = malloc(sizeof(uv_buf) * bufcnt); - memcpy(req->bufs, bufs, bufcnt * sizeof(uv_buf)); + req->bufs = malloc(sizeof(uv_buf_t) * bufcnt); + memcpy(req->bufs, bufs, bufcnt * sizeof(uv_buf_t)); req->bufcnt = bufcnt; req->write_index = 0; @@ -867,23 +893,6 @@ void uv_unref() { } -void uv__timeout(EV_P_ ev_timer* watcher, int revents) { - uv_req_t* req = watcher->data; - assert(watcher == &req->timer); - assert(EV_TIMER & revents); - - /* This watcher is not repeating. */ - assert(!ev_is_active(watcher)); - assert(!ev_is_pending(watcher)); - - if (req->cb) { - uv_timer_cb cb = req->cb; - /* TODO skew */ - cb(req, 0, 0); - } -} - - void uv_update_time() { ev_now_update(EV_DEFAULT_UC); } @@ -894,14 +903,6 @@ int64_t uv_now() { } -int uv_timeout(uv_req_t* req, int64_t timeout) { - ev_timer_init(&req->timer, uv__timeout, timeout / 1000.0, 0.0); - ev_timer_start(EV_DEFAULT_UC_ &req->timer); - req->timer.data = req; - return 0; -} - - int uv_read_start(uv_handle_t* handle, uv_read_cb cb) { /* The UV_READING flag is irrelevant of the state of the handle - it just * expresses the desired state of the user. @@ -968,14 +969,28 @@ int uv_prepare_init(uv_handle_t* handle, uv_close_cb close_cb, void* data) { int uv_prepare_start(uv_handle_t* handle, uv_loop_cb cb) { + int was_active = ev_is_active(&handle->prepare_watcher); + handle->prepare_cb = cb; + ev_prepare_start(EV_DEFAULT_UC_ &handle->prepare_watcher); + + if (!was_active) { + ev_unref(EV_DEFAULT_UC); + } + return 0; } int uv_prepare_stop(uv_handle_t* handle) { + int was_active = ev_is_active(&handle->prepare_watcher); + ev_prepare_stop(EV_DEFAULT_UC_ &handle->prepare_watcher); + + if (was_active) { + ev_ref(EV_DEFAULT_UC); + } return 0; } @@ -1001,14 +1016,29 @@ int uv_check_init(uv_handle_t* handle, uv_close_cb close_cb, void* data) { int uv_check_start(uv_handle_t* handle, uv_loop_cb cb) { + int was_active = ev_is_active(&handle->prepare_watcher); + handle->check_cb = cb; + ev_check_start(EV_DEFAULT_UC_ &handle->check_watcher); + + if (!was_active) { + ev_unref(EV_DEFAULT_UC); + } + return 0; } int uv_check_stop(uv_handle_t* handle) { - ev_prepare_stop(EV_DEFAULT_UC_ &handle->prepare_watcher); + int was_active = ev_is_active(&handle->check_watcher); + + ev_check_stop(EV_DEFAULT_UC_ &handle->check_watcher); + + if (was_active) { + ev_ref(EV_DEFAULT_UC); + } + return 0; } @@ -1034,18 +1064,45 @@ int uv_idle_init(uv_handle_t* handle, uv_close_cb close_cb, void* data) { int uv_idle_start(uv_handle_t* handle, uv_loop_cb cb) { + int was_active = ev_is_active(&handle->idle_watcher); + handle->idle_cb = cb; ev_idle_start(EV_DEFAULT_UC_ &handle->idle_watcher); + + if (!was_active) { + ev_unref(EV_DEFAULT_UC); + } + return 0; } int uv_idle_stop(uv_handle_t* handle) { + int was_active = ev_is_active(&handle->idle_watcher); + ev_idle_stop(EV_DEFAULT_UC_ &handle->idle_watcher); + + if (was_active) { + ev_ref(EV_DEFAULT_UC); + } + return 0; } +int uv_is_active(uv_handle_t* handle) { + switch (handle->type) { + case UV_PREPARE: + case UV_CHECK: + case UV_IDLE: + return ev_is_active(handle); + + default: + return 1; + } +} + + static void uv__async(EV_P_ ev_async* w, int revents) { uv_handle_t* handle = (uv_handle_t*)(w->data); @@ -1064,6 +1121,7 @@ int uv_async_init(uv_handle_t* handle, uv_async_cb async_cb, /* Note: This does not have symmetry with the other libev wrappers. */ ev_async_start(EV_DEFAULT_UC_ &handle->async_watcher); + ev_unref(EV_DEFAULT_UC); return 0; } @@ -1072,3 +1130,70 @@ int uv_async_init(uv_handle_t* handle, uv_async_cb async_cb, int uv_async_send(uv_handle_t* handle) { ev_async_send(EV_DEFAULT_UC_ &handle->async_watcher); } + + +static void uv__timer_cb(EV_P_ ev_timer* w, int revents) { + uv_handle_t* handle = (uv_handle_t*)(w->data); + + if (!ev_is_active(w)) { + ev_ref(EV_DEFAULT_UC); + } + + if (handle->timer_cb) handle->timer_cb(handle, 0); +} + + +int uv_timer_init(uv_handle_t* handle, uv_close_cb close_cb, void* data) { + uv__handle_init(handle, UV_TIMER, close_cb, data); + + ev_init(&handle->timer_watcher, uv__timer_cb); + handle->timer_watcher.data = handle; + + return 0; +} + + +int uv_timer_start(uv_handle_t* handle, uv_loop_cb cb, int64_t timeout, + int64_t repeat) { + if (ev_is_active(&handle->timer_watcher)) { + return -1; + } + + handle->timer_cb = cb; + ev_timer_set(&handle->timer_watcher, timeout / 1000.0, repeat / 1000.0); + ev_timer_start(EV_DEFAULT_UC_ &handle->timer_watcher); + ev_unref(EV_DEFAULT_UC); + return 0; +} + + +int uv_timer_stop(uv_handle_t* handle) { + if (ev_is_active(&handle->timer_watcher)) { + ev_ref(EV_DEFAULT_UC); + } + + ev_timer_stop(EV_DEFAULT_UC_ &handle->timer_watcher); + return 0; +} + + +int uv_timer_again(uv_handle_t* handle) { + if (!ev_is_active(&handle->timer_watcher)) { + uv_err_new(handle, EINVAL); + return -1; + } + + ev_timer_again(EV_DEFAULT_UC_ &handle->timer_watcher); + return 0; +} + +void uv_timer_set_repeat(uv_handle_t* handle, int64_t repeat) { + assert(handle->type == UV_TIMER); + handle->timer_watcher.repeat = repeat / 1000.0; +} + +int64_t uv_timer_get_repeat(uv_handle_t* handle) { + assert(handle->type == UV_TIMER); + return (int64_t)(1000 * handle->timer_watcher.repeat); +} + diff --git a/deps/uv/uv-unix.h b/deps/uv/uv-unix.h index b247e58363..6301ac3f3d 100644 --- a/deps/uv/uv-unix.h +++ b/deps/uv/uv-unix.h @@ -35,14 +35,14 @@ typedef struct { char* base; size_t len; -} uv_buf; +} uv_buf_t; #define uv_req_private_fields \ int write_index; \ ev_timer timer; \ ngx_queue_t queue; \ - uv_buf* bufs; \ + uv_buf_t* bufs; \ int bufcnt; @@ -72,7 +72,10 @@ typedef struct { uv_loop_cb idle_cb; \ /* UV_ASYNC */ \ ev_async async_watcher; \ - uv_loop_cb async_cb; + uv_loop_cb async_cb; \ +/* UV_TIMER */ \ + ev_timer timer_watcher; \ + uv_loop_cb timer_cb; #endif /* UV_UNIX_H */ diff --git a/deps/uv/uv-win.c b/deps/uv/uv-win.c index fc40651776..c25bb7063a 100644 --- a/deps/uv/uv-win.c +++ b/deps/uv/uv-win.c @@ -141,9 +141,9 @@ static LPFN_TRANSMITFILE pTransmitFile; /* Binary tree used to keep the list of timers sorted. */ -static int uv_timer_compare(uv_req_t* t1, uv_req_t* t2); -RB_HEAD(uv_timer_s, uv_req_s); -RB_PROTOTYPE_STATIC(uv_timer_s, uv_req_s, tree_entry, uv_timer_compare); +static int uv_timer_compare(uv_handle_t* handle1, uv_handle_t* handle2); +RB_HEAD(uv_timer_s, uv_handle_s); +RB_PROTOTYPE_STATIC(uv_timer_s, uv_handle_s, tree_entry, uv_timer_compare); /* The head of the timers tree */ static struct uv_timer_s uv_timers_ = RB_INITIALIZER(uv_timers_); @@ -296,6 +296,7 @@ static uv_err_code uv_translate_sys_error(int sys_errno) { case ERROR_CONNECTION_REFUSED: return UV_ECONNREFUSED; case WSAECONNREFUSED: return UV_ECONNREFUSED; case WSAEFAULT: return UV_EFAULT; + case ERROR_INVALID_DATA: return UV_EINVAL; case WSAEINVAL: return UV_EINVAL; case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE; case WSAEMFILE: return UV_EMFILE; @@ -339,7 +340,7 @@ static void uv_get_extension_function(SOCKET socket, GUID guid, if (result == SOCKET_ERROR) { *target = NULL; uv_fatal_error(WSAGetLastError(), - "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER)"); + "WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER)"); } } @@ -374,20 +375,20 @@ void uv_init(uv_alloc_cb alloc_cb) { } uv_get_extension_function(dummy, - wsaid_connectex, - (void**)&pConnectEx); + wsaid_connectex, + (void**)&pConnectEx); uv_get_extension_function(dummy, - wsaid_acceptex, - (void**)&pAcceptEx); + wsaid_acceptex, + (void**)&pAcceptEx); uv_get_extension_function(dummy, - wsaid_getacceptexsockaddrs, - (void**)&pGetAcceptExSockAddrs); + wsaid_getacceptexsockaddrs, + (void**)&pGetAcceptExSockAddrs); uv_get_extension_function(dummy, - wsaid_disconnectex, - (void**)&pDisconnectEx); + wsaid_disconnectex, + (void**)&pDisconnectEx); uv_get_extension_function(dummy, - wsaid_transmitfile, - (void**)&pTransmitFile); + wsaid_transmitfile, + (void**)&pTransmitFile); if (closesocket(dummy) == SOCKET_ERROR) { uv_fatal_error(WSAGetLastError(), "closesocket"); @@ -538,6 +539,20 @@ static void uv_tcp_endgame(uv_handle_t* handle) { } +static void uv_timer_endgame(uv_handle_t* handle) { + if (handle->flags & UV_HANDLE_CLOSING) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + handle->flags |= UV_HANDLE_CLOSED; + + if (handle->close_cb) { + handle->close_cb(handle, 0); + } + + uv_refs_--; + } +} + + static void uv_loop_endgame(uv_handle_t* handle) { if (handle->flags & UV_HANDLE_CLOSING) { assert(!(handle->flags & UV_HANDLE_CLOSED)); @@ -581,6 +596,10 @@ static void uv_call_endgames() { uv_tcp_endgame(handle); break; + case UV_TIMER: + uv_timer_endgame(handle); + break; + case UV_PREPARE: case UV_CHECK: case UV_IDLE: @@ -626,6 +645,11 @@ static int uv_close_error(uv_handle_t* handle, uv_err_t e) { } return 0; + case UV_TIMER: + uv_timer_stop(handle); + uv_want_endgame(handle); + return 0; + case UV_PREPARE: uv_prepare_stop(handle); uv_want_endgame(handle); @@ -751,7 +775,7 @@ static void uv_queue_accept(uv_handle_t* handle) { static void uv_queue_read(uv_handle_t* handle) { uv_req_t *req; - uv_buf buf; + uv_buf_t buf; int result; DWORD bytes, flags; @@ -926,7 +950,7 @@ int uv_connect(uv_req_t* req, struct sockaddr* addr) { } -static size_t uv_count_bufs(uv_buf bufs[], int count) { +static size_t uv_count_bufs(uv_buf_t bufs[], int count) { size_t bytes = 0; int i; @@ -938,7 +962,7 @@ static size_t uv_count_bufs(uv_buf bufs[], int count) { } -int uv_write(uv_req_t* req, uv_buf bufs[], int bufcnt) { +int uv_write(uv_req_t* req, uv_buf_t bufs[], int bufcnt) { int result; DWORD bytes, err; uv_handle_t* handle = req->handle; @@ -1021,7 +1045,7 @@ int uv_shutdown(uv_req_t* req) { static void uv_tcp_return_req(uv_handle_t* handle, uv_req_t* req) { BOOL success; DWORD bytes, flags, err; - uv_buf buf; + uv_buf_t buf; assert(handle->type == UV_TCP); @@ -1108,10 +1132,10 @@ static void uv_tcp_return_req(uv_handle_t* handle, uv_req_t* req) { success = GetOverlappedResult(handle->handle, &req->overlapped, &bytes, FALSE); success = success && (setsockopt(handle->accept_socket, - SOL_SOCKET, - SO_UPDATE_ACCEPT_CONTEXT, - (char*)&handle->socket, - sizeof(handle->socket)) == 0); + SOL_SOCKET, + SO_UPDATE_ACCEPT_CONTEXT, + (char*)&handle->socket, + sizeof(handle->socket)) == 0); if (success) { if (handle->accept_cb) { @@ -1134,10 +1158,10 @@ static void uv_tcp_return_req(uv_handle_t* handle, uv_req_t* req) { FALSE); if (success) { if (setsockopt(handle->socket, - SOL_SOCKET, - SO_UPDATE_CONNECT_CONTEXT, - NULL, - 0) == 0) { + SOL_SOCKET, + SO_UPDATE_CONNECT_CONTEXT, + NULL, + 0) == 0) { uv_tcp_init_connection(handle); ((uv_connect_cb)req->cb)(req, 0); } else { @@ -1167,7 +1191,7 @@ static void uv_tcp_return_req(uv_handle_t* handle, uv_req_t* req) { } -static int uv_timer_compare(uv_req_t* a, uv_req_t* b) { +static int uv_timer_compare(uv_handle_t* a, uv_handle_t* b) { if (a->due < b->due) return -1; if (a->due > b->due) @@ -1180,26 +1204,92 @@ static int uv_timer_compare(uv_req_t* a, uv_req_t* b) { } -RB_GENERATE_STATIC(uv_timer_s, uv_req_s, tree_entry, uv_timer_compare); +RB_GENERATE_STATIC(uv_timer_s, uv_handle_s, tree_entry, uv_timer_compare); -int uv_timeout(uv_req_t* req, int64_t timeout) { - assert(!(req->flags & UV_REQ_PENDING)); +int uv_timer_init(uv_handle_t* handle, uv_close_cb close_cb, void* data) { + handle->type = UV_TIMER; + handle->close_cb = (void*) close_cb; + handle->data = data; + handle->flags = 0; + handle->error = uv_ok_; + handle->timer_cb = NULL; + handle->repeat = 0; + + uv_refs_++; + + return 0; +} + + +int uv_timer_start(uv_handle_t* handle, uv_loop_cb timer_cb, int64_t timeout, int64_t repeat) { + if (handle->flags & UV_HANDLE_ACTIVE) { + RB_REMOVE(uv_timer_s, &uv_timers_, handle); + } + + handle->timer_cb = (void*) timer_cb; + handle->due = uv_now_ + timeout; + handle->repeat = repeat; + handle->flags |= UV_HANDLE_ACTIVE; + + if (RB_INSERT(uv_timer_s, &uv_timers_, handle) != NULL) { + uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT"); + } + + return 0; +} - req->type = UV_TIMEOUT; - req->due = uv_now_ + timeout; - if (RB_INSERT(uv_timer_s, &uv_timers_, req) != NULL) { +int uv_timer_stop(uv_handle_t* handle) { + if (!(handle->flags & UV_HANDLE_ACTIVE)) + return 0; + + RB_REMOVE(uv_timer_s, &uv_timers_, handle); + + handle->flags &= ~UV_HANDLE_ACTIVE; + + return 0; +} + + +int uv_timer_again(uv_handle_t* handle) { + /* If timer_cb is NULL that means that the timer was never started. */ + if (!handle->timer_cb) { uv_set_sys_error(ERROR_INVALID_DATA); return -1; } - uv_refs_++; - req->flags |= UV_REQ_PENDING; + if (handle->flags & UV_HANDLE_ACTIVE) { + RB_REMOVE(uv_timer_s, &uv_timers_, handle); + handle->flags &= ~UV_HANDLE_ACTIVE; + } + + if (handle->repeat) { + handle->due = uv_now_ + handle->repeat; + + if (RB_INSERT(uv_timer_s, &uv_timers_, handle) != NULL) { + uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT"); + } + + handle->flags |= UV_HANDLE_ACTIVE; + } + return 0; } +void uv_timer_set_repeat(uv_handle_t* handle, int64_t repeat) { + assert(handle->type == UV_TIMER); + handle->repeat = repeat; +} + + +int64_t uv_timer_get_repeat(uv_handle_t* handle) { + assert(handle->type == UV_TIMER); + return handle->repeat; +} + + void uv_update_time() { LARGE_INTEGER counter; @@ -1347,6 +1437,20 @@ int uv_idle_stop(uv_handle_t* handle) { } +int uv_is_active(uv_handle_t* handle) { + switch (handle->type) { + case UV_TIMER: + case UV_IDLE: + case UV_PREPARE: + case UV_CHECK: + return (handle->flags & UV_HANDLE_ACTIVE) ? 1 : 0; + + default: + return 1; + } +} + + int uv_async_init(uv_handle_t* handle, uv_async_cb async_cb, uv_close_cb close_cb, void* data) { uv_req_t* req; @@ -1426,9 +1530,9 @@ static void uv_poll() { uv_update_time(); /* Check if there are any running timers */ - req = RB_MIN(uv_timer_s, &uv_timers_); - if (req) { - delta = req->due - uv_now_; + handle = RB_MIN(uv_timer_s, &uv_timers_); + if (handle) { + delta = handle->due - uv_now_; if (delta >= UINT_MAX) { /* Can't have a timeout greater than UINT_MAX, and a timeout value of */ /* UINT_MAX means infinite, so that's no good either. */ @@ -1456,13 +1560,26 @@ static void uv_poll() { uv_loop_invoke(uv_check_handles_); /* Call timer callbacks */ - for (req = RB_MIN(uv_timer_s, &uv_timers_); - req != NULL && req->due <= uv_now_; - req = RB_MIN(uv_timer_s, &uv_timers_)) { - RB_REMOVE(uv_timer_s, &uv_timers_, req); - req->flags &= ~UV_REQ_PENDING; - uv_refs_--; - ((uv_timer_cb)req->cb)(req, req->due - uv_now_, 0); + for (handle = RB_MIN(uv_timer_s, &uv_timers_); + handle != NULL && handle->due <= uv_now_; + handle = RB_MIN(uv_timer_s, &uv_timers_)) { + RB_REMOVE(uv_timer_s, &uv_timers_, handle); + + if (handle->repeat != 0) { + /* If it is a repeating timer, reschedule with repeat timeout. */ + handle->due += handle->repeat; + if (handle->due < uv_now_) { + handle->due = uv_now_; + } + if (RB_INSERT(uv_timer_s, &uv_timers_, handle) != NULL) { + uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT"); + } + } else { + /* If non-repeating, mark the timer as inactive. */ + handle->flags &= ~UV_HANDLE_ACTIVE; + } + + ((uv_loop_cb) handle->timer_cb)(handle, 0); } /* Only if a iocp package was dequeued... */ diff --git a/deps/uv/uv-win.h b/deps/uv/uv-win.h index 2f16197eeb..83b73630b0 100644 --- a/deps/uv/uv-win.h +++ b/deps/uv/uv-win.h @@ -33,68 +33,70 @@ /** - * It should be possible to cast uv_buf[] to WSABUF[] + * It should be possible to cast uv_buf_t[] to WSABUF[] * see http://msdn.microsoft.com/en-us/library/ms741542(v=vs.85).aspx */ -typedef struct uv_buf { +typedef struct uv_buf_t { ULONG len; char* base; -} uv_buf; +} uv_buf_t; -#define uv_req_private_fields \ +#define uv_req_private_fields \ union { \ /* Used by I/O operations */ \ struct { \ OVERLAPPED overlapped; \ size_t queued_bytes; \ }; \ - /* Used by timers */ \ - struct { \ - RB_ENTRY(uv_req_s) tree_entry; \ - int64_t due; \ - }; \ }; \ int flags; -#define uv_tcp_connection_fields \ +#define uv_tcp_connection_fields \ void* read_cb; \ - struct uv_req_s read_req; \ + struct uv_req_s read_req; \ unsigned int write_reqs_pending; \ uv_req_t* shutdown_req; -#define uv_tcp_server_fields \ +#define uv_tcp_server_fields \ void *accept_cb; \ SOCKET accept_socket; \ - struct uv_req_s accept_req; \ + struct uv_req_s accept_req; \ char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32]; -#define uv_tcp_fields \ +#define uv_tcp_fields \ unsigned int reqs_pending; \ union { \ SOCKET socket; \ HANDLE handle; \ }; \ union { \ - struct { uv_tcp_connection_fields }; \ - struct { uv_tcp_server_fields }; \ + struct { uv_tcp_connection_fields }; \ + struct { uv_tcp_server_fields }; \ }; -#define uv_loop_fields \ - uv_handle_t* loop_prev; \ - uv_handle_t* loop_next; \ +#define uv_timer_fields \ + RB_ENTRY(uv_handle_s) tree_entry; \ + int64_t due; \ + int64_t repeat; \ + void* timer_cb; + +#define uv_loop_fields \ + uv_handle_t* loop_prev; \ + uv_handle_t* loop_next; \ void* loop_cb; -#define uv_async_fields \ - struct uv_req_s async_req; \ +#define uv_async_fields \ + struct uv_req_s async_req; \ /* char to avoid alignment issues */ \ char volatile async_sent; -#define uv_handle_private_fields \ - uv_handle_t* endgame_next; \ +#define uv_handle_private_fields \ + uv_handle_t* endgame_next; \ unsigned int flags; \ - uv_err_t error; \ + uv_err_t error; \ union { \ - struct { uv_tcp_fields }; \ - struct { uv_loop_fields }; \ - struct { uv_async_fields }; \ + struct { uv_tcp_fields }; \ + struct { uv_timer_fields }; \ + struct { uv_loop_fields }; \ + struct { uv_async_fields }; \ }; diff --git a/deps/uv/uv.h b/deps/uv/uv.h index 93f865a7c2..0b4984bf54 100644 --- a/deps/uv/uv.h +++ b/deps/uv/uv.h @@ -48,17 +48,16 @@ typedef struct uv_req_s uv_req_t; * For uv_close_cb, -1 means that the handle was closed due to an error. * Error details can be obtained by calling uv_last_error(). * - * In the case of uv_read_cb the uv_buf returned should be freed by the + * In the case of uv_read_cb the uv_buf_t returned should be freed by the * user. */ -typedef uv_buf (*uv_alloc_cb)(uv_handle_t* handle, size_t suggested_size); -typedef void (*uv_read_cb)(uv_handle_t *handle, int nread, uv_buf buf); +typedef uv_buf_t (*uv_alloc_cb)(uv_handle_t* handle, size_t suggested_size); +typedef void (*uv_read_cb)(uv_handle_t *handle, int nread, uv_buf_t buf); typedef void (*uv_write_cb)(uv_req_t* req, int status); typedef void (*uv_connect_cb)(uv_req_t* req, int status); typedef void (*uv_shutdown_cb)(uv_req_t* req, int status); typedef void (*uv_accept_cb)(uv_handle_t* handle); typedef void (*uv_close_cb)(uv_handle_t* handle, int status); -typedef void (*uv_timer_cb)(uv_req_t* req, int64_t skew, int status); /* TODO: do loop_cb and async_cb really need a status argument? */ typedef void (*uv_loop_cb)(uv_handle_t* handle, int status); typedef void (*uv_async_cb)(uv_handle_t* handle, int stats); @@ -109,6 +108,7 @@ typedef enum { UV_NAMED_PIPE, UV_TTY, UV_FILE, + UV_TIMER, UV_PREPARE, UV_CHECK, UV_IDLE, @@ -122,7 +122,6 @@ typedef enum { UV_READ, UV_WRITE, UV_SHUTDOWN, - UV_TIMEOUT, UV_WAKEUP } uv_req_type; @@ -166,7 +165,7 @@ struct uv_handle_s { */ uv_err_t uv_last_error(); char* uv_strerror(uv_err_t err); - +const char* uv_err_name(uv_err_t err); void uv_init(uv_alloc_cb alloc); int uv_run(); @@ -219,10 +218,26 @@ int uv_accept(uv_handle_t* server, uv_handle_t* client, int uv_read_start(uv_handle_t* handle, uv_read_cb cb); int uv_read_stop(uv_handle_t* handle); -int uv_write(uv_req_t* req, uv_buf bufs[], int bufcnt); +int uv_write(uv_req_t* req, uv_buf_t bufs[], int bufcnt); /* Timer methods */ -int uv_timeout(uv_req_t* req, int64_t timeout); +int uv_timer_init(uv_handle_t* handle, uv_close_cb close_cb, void* data); +int uv_timer_start(uv_handle_t* handle, uv_loop_cb cb, int64_t timeout, int64_t repeat); +int uv_timer_stop(uv_handle_t* handle); +/* + * Stop the timer, and if it is repeating restart it using the repeat value + * as the timeout. If the timer has never been started before it returns -1 and + * sets the error to UV_EINVAL. + */ +int uv_timer_again(uv_handle_t* handle); +/* + * Set the repeat value. Note that if the repeat value is set from a timer + * callback it does not immediately take effect. If the timer was nonrepeating + * before, it will have been stopped. If it was repeating, then the old repeat + * value will have been used to schedule the next timeout. + */ +void uv_timer_set_repeat(uv_handle_t* handle, int64_t repeat); +int64_t uv_timer_get_repeat(uv_handle_t* handle); /* libev wrapper. Every active prepare handle gets its callback called * exactly once per loop iteration, just before the system blocks to wait @@ -248,6 +263,11 @@ int uv_idle_init(uv_handle_t* handle, uv_close_cb close_cb, void* data); int uv_idle_start(uv_handle_t* handle, uv_loop_cb cb); int uv_idle_stop(uv_handle_t* handle); +/* Returns 1 if the prepare/check/idle handle has been started, 0 otherwise. + * For other handle types this always returns 1. + */ +int uv_is_active(uv_handle_t* handle); + /* libev wrapper. uv_async_send wakes up the event loop and calls the async * handle's callback There is no guarantee that every uv_async_send call * leads to exactly one invocation of the callback; The only guarantee is diff --git a/src/node.cc b/src/node.cc index 0e576198da..d47ea41af0 100644 --- a/src/node.cc +++ b/src/node.cc @@ -217,6 +217,7 @@ static Handle NeedTickCallback(const Arguments& args) { // ev_prepare callback isn't called before exiting. Thus we start this // tick_spinner to keep the event loop alive long enough to handle it. uv_idle_start(&tick_spinner, Spin); + uv_ref(); return Undefined(); } @@ -227,6 +228,7 @@ static void Tick(void) { need_tick_cb = false; uv_idle_stop(&tick_spinner); + uv_unref(); HandleScope scope; @@ -2357,6 +2359,7 @@ char** Init(int argc, char *argv[]) { uv_unref(); uv_idle_init(&node::tick_spinner, NULL, NULL); + uv_unref(); ev_check_init(&node::gc_check, node::Check); ev_check_start(EV_DEFAULT_UC_ &node::gc_check); @@ -2431,9 +2434,9 @@ void EmitExit(v8::Handle process) { } -uv_buf UVAlloc(uv_handle_t* handle, size_t suggested_size) { +uv_buf_t UVAlloc(uv_handle_t* handle, size_t suggested_size) { char* base = (char*)malloc(suggested_size); - uv_buf buf; + uv_buf_t buf; buf.base = base; buf.len = suggested_size; return buf;