diff --git a/config-mingw.mk b/config-mingw.mk index 48c6325a..89bf2df3 100644 --- a/config-mingw.mk +++ b/config-mingw.mk @@ -37,15 +37,15 @@ RUNNER_LINKFLAGS=$(LINKFLAGS) RUNNER_LIBS=-lws2_32 -lpsapi -liphlpapi RUNNER_SRC=test/runner-win.c -uv.a: $(WIN_OBJS) src/uv-common.o $(CARES_OBJS) - $(AR) rcs uv.a src/win/*.o src/uv-common.o $(CARES_OBJS) +uv.a: $(WIN_OBJS) src/cares.o src/uv-common.o $(CARES_OBJS) + $(AR) rcs uv.a $(WIN_OBJS) src/cares.o src/uv-common.o $(CARES_OBJS) -src/win/%.o: src/win/%.c src/win/internal.h +src/%.o: src/%.c include/uv.h include/uv-private/uv-win.h + $(CC) $(CFLAGS) -c $< -o $@ + +src/win/%.o: src/win/%.c include/uv.h include/uv-private/uv-win.h src/win/internal.h $(CC) $(CFLAGS) -o $@ -c $< -src/uv-common.o: src/uv-common.c include/uv.h include/uv-private/uv-win.h - $(CC) $(CFLAGS) -c src/uv-common.c -o src/uv-common.o - EIO_CPPFLAGS += $(CPPFLAGS) EIO_CPPFLAGS += -DEIO_STACKSIZE=65536 EIO_CPPFLAGS += -D_GNU_SOURCE diff --git a/config-unix.mk b/config-unix.mk index 860059e4..ce98c1f0 100644 --- a/config-unix.mk +++ b/config-unix.mk @@ -21,14 +21,13 @@ E= CSTDFLAG=--std=c89 -pedantic -Wall -Wextra -Wno-unused-parameter CFLAGS += -g -CPPFLAGS += -Isrc/unix/ev +CPPFLAGS += -Isrc -Isrc/unix/ev LINKFLAGS=-lm CPPFLAGS += -D_LARGEFILE_SOURCE CPPFLAGS += -D_FILE_OFFSET_BITS=64 OBJS += src/unix/async.o -OBJS += src/unix/cares.o OBJS += src/unix/core.o OBJS += src/unix/dl.o OBJS += src/unix/error.o @@ -129,14 +128,14 @@ endif RUNNER_LIBS= RUNNER_SRC=test/runner-unix.c -uv.a: $(OBJS) src/uv-common.o src/unix/ev/ev.o src/unix/uv-eio.o src/unix/eio/eio.o $(CARES_OBJS) - $(AR) rcs uv.a $(OBJS) src/uv-common.o src/unix/uv-eio.o src/unix/ev/ev.o src/unix/eio/eio.o $(CARES_OBJS) +uv.a: $(OBJS) src/cares.o src/uv-common.o src/unix/ev/ev.o src/unix/uv-eio.o src/unix/eio/eio.o $(CARES_OBJS) + $(AR) rcs uv.a $(OBJS) src/cares.o src/uv-common.o src/unix/uv-eio.o src/unix/ev/ev.o src/unix/eio/eio.o $(CARES_OBJS) + +src/%.o: src/%.c include/uv.h include/uv-private/uv-unix.h + $(CC) $(CSTDFLAG) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ src/unix/%.o: src/unix/%.c include/uv.h include/uv-private/uv-unix.h src/unix/internal.h - $(CC) $(CSTDFLAG) $(CPPFLAGS) -Isrc $(CFLAGS) -c $< -o $@ - -src/uv-common.o: src/uv-common.c include/uv.h include/uv-private/uv-unix.h - $(CC) $(CSTDFLAG) $(CPPFLAGS) $(CFLAGS) -c src/uv-common.c -o src/uv-common.o + $(CC) $(CSTDFLAG) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ src/unix/ev/ev.o: src/unix/ev/ev.c $(CC) $(CPPFLAGS) $(CFLAGS) -c src/unix/ev/ev.c -o src/unix/ev/ev.o -DEV_CONFIG_H=\"$(EV_CONFIG)\" diff --git a/include/uv-private/uv-unix.h b/include/uv-private/uv-unix.h index efd57f07..f1a55d6f 100644 --- a/include/uv-private/uv-unix.h +++ b/include/uv-private/uv-unix.h @@ -90,13 +90,6 @@ typedef struct { #endif #define UV_LOOP_PRIVATE_FIELDS \ - ares_channel channel; \ - /* \ - * While the channel is active this timer is called once per second to be \ - * sure that we're always calling ares_process. See the warning above the \ - * definition of ares_timeout(). \ - */ \ - uv_timer_t timer; \ /* Poll result queue */ \ eio_channel uv_eio_channel; \ struct ev_loop* ev; \ diff --git a/include/uv-private/uv-win.h b/include/uv-private/uv-win.h index da76e52b..e0b84555 100644 --- a/include/uv-private/uv-win.h +++ b/include/uv-private/uv-win.h @@ -231,23 +231,17 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); uv_idle_t* next_idle_handle; \ /* This handle holds the peer sockets for the fast variant of uv_poll_t */ \ SOCKET poll_peer_sockets[UV_MSAFD_PROVIDER_COUNT]; \ - /* State used by uv_ares. */ \ - ares_channel ares_chan; \ - int ares_active_sockets; \ - uv_timer_t ares_polling_timer; \ /* Counter to keep track of active tcp streams */ \ unsigned int active_tcp_streams; \ /* Counter to keep track of active udp streams */ \ unsigned int active_udp_streams; #define UV_HANDLE_TYPE_PRIVATE \ - UV_ARES_EVENT, + /* empty */ #define UV_REQ_TYPE_PRIVATE \ /* TODO: remove the req suffix */ \ UV_ACCEPT, \ - UV_ARES_EVENT_REQ, \ - UV_ARES_CLEANUP_REQ, \ UV_FS_EVENT_REQ, \ UV_POLL_REQ, \ UV_PROCESS_EXIT, \ diff --git a/include/uv.h b/include/uv.h index a9e895e8..0214e635 100644 --- a/include/uv.h +++ b/include/uv.h @@ -1645,8 +1645,13 @@ struct uv_counters_s { struct uv_loop_s { UV_LOOP_PRIVATE_FIELDS + ares_channel channel; + /* While the channel is active this timer is called once per second to be */ + /* sure that we're always calling ares_process. See the warning above the */ + /* definition of ares_timeout(). */ + uv_timer_t ares_timer; \ /* RB_HEAD(uv__ares_tasks, uv_ares_task_t) */ - struct uv__ares_tasks { uv_ares_task_t* rbh_root; } uv_ares_handles_; + struct uv__ares_tasks { uv_ares_task_t* rbh_root; } ares_handles; /* Diagnostic counters */ uv_counters_t counters; /* The last error */ diff --git a/src/cares.c b/src/cares.c new file mode 100644 index 00000000..3ef799e6 --- /dev/null +++ b/src/cares.c @@ -0,0 +1,179 @@ +/* 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 "uv-common.h" + +#include +#include +#include +#include + + +/* This is called once per second by loop->timer. It is used to constantly */ +/* call back into c-ares for possibly processing timeouts. */ +static void uv__ares_timeout(uv_timer_t* handle, int status) { + assert(!uv_ares_handles_empty(handle->loop)); + ares_process_fd(handle->loop->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); +} + + +static void uv__ares_poll_cb(uv_poll_t* watcher, int status, int events) { + uv_loop_t* loop = watcher->loop; + uv_ares_task_t* task = container_of(watcher, uv_ares_task_t, poll_watcher); + + /* Reset the idle timer */ + uv_timer_again(&loop->ares_timer); + + if (status < 0) { + /* An error happened. Just pretend that the socket is both readable and */ + /* writable. */ + ares_process_fd(loop->channel, task->sock, task->sock); + return; + } + + /* Process DNS responses */ + ares_process_fd(loop->channel, + events & UV_READABLE ? task->sock : ARES_SOCKET_BAD, + events & UV_WRITABLE ? task->sock : ARES_SOCKET_BAD); +} + + +static void uv__ares_poll_close_cb(uv_handle_t* watcher) { + uv_ares_task_t* task = container_of(watcher, uv_ares_task_t, poll_watcher); + free(task); +} + + +/* Allocates and returns a new uv_ares_task_t */ +static uv_ares_task_t* uv__ares_task_create(uv_loop_t* loop, ares_socket_t sock) { + uv_ares_task_t* task = (uv_ares_task_t*) malloc(sizeof *task); + + if (task == NULL) { + /* Out of memory. */ + return NULL; + } + + task->loop = loop; + task->sock = sock; + + if (uv_poll_init_socket(loop, &task->poll_watcher, sock) < 0) { + /* This should never happen. */ + free(task); + return NULL; + } + + return task; +} + + +/* Callback from ares when socket operation is started */ +static void uv__ares_sockstate_cb(void* data, ares_socket_t sock, + int read, int write) { + uv_loop_t* loop = (uv_loop_t*) data; + uv_ares_task_t* task; + + task = uv_find_ares_handle(loop, sock); + + if (read || write) { + if (!task) { + /* New socket */ + + /* If this is the first socket then start the timer. */ + if (!uv_is_active((uv_handle_t*) &loop->ares_timer)) { + assert(uv_ares_handles_empty(loop)); + uv_timer_start(&loop->ares_timer, uv__ares_timeout, 1000, 1000); + } + + task = uv__ares_task_create(loop, sock); + if (task == NULL) { + /* This should never happen unless we're out of memory or something */ + /* is seriously wrong. The socket won't be polled, but the the query */ + /* will eventually time out. */ + return; + } + + uv_add_ares_handle(loop, task); + } + + /* This should never fail. If it fails anyway, the query will eventually */ + /* time out. */ + uv_poll_start(&task->poll_watcher, + (read ? UV_READABLE : 0) | (write ? UV_WRITABLE : 0), + uv__ares_poll_cb); + + } else { + /* read == 0 and write == 0 this is c-ares's way of notifying us that */ + /* the socket is now closed. We must free the data associated with */ + /* socket. */ + assert(task && + "When an ares socket is closed we should have a handle for it"); + + uv_remove_ares_handle(task); + uv_close((uv_handle_t*) &task->poll_watcher, uv__ares_poll_close_cb); + + if (uv_ares_handles_empty(loop)) { + uv_timer_stop(&loop->ares_timer); + } + } +} + + +/* C-ares integration initialize and terminate */ +int uv_ares_init_options(uv_loop_t* loop, ares_channel *channelptr, + struct ares_options *options, int optmask) { + int rc; + + /* only allow single init at a time */ + if (loop->channel != NULL) { + uv__set_artificial_error(loop, UV_EALREADY); + return -1; + } + + /* set our callback as an option */ + options->sock_state_cb = uv__ares_sockstate_cb; + options->sock_state_cb_data = loop; + optmask |= ARES_OPT_SOCK_STATE_CB; + + /* We do the call to ares_init_option for caller. */ + rc = ares_init_options(channelptr, options, optmask); + + /* if success, save channel */ + if (rc == ARES_SUCCESS) { + loop->channel = *channelptr; + } + + /* Initialize the timeout timer. The timer won't be started until the */ + /* first socket is opened. */ + uv_timer_init(loop, &loop->ares_timer); + + return rc; +} + + +void uv_ares_destroy(uv_loop_t* loop, ares_channel channel) { + /* Only allow destroy if did init. */ + if (loop->channel) { + uv_timer_stop(&loop->ares_timer); + ares_destroy(channel); + loop->channel = NULL; + } +} diff --git a/src/unix/cares.c b/src/unix/cares.c deleted file mode 100644 index a579eaa1..00000000 --- a/src/unix/cares.c +++ /dev/null @@ -1,179 +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 "internal.h" - -#include -#include -#include - - -/* - * This is called once per second by loop->timer. It is used to - * constantly callback into c-ares for possibly processing timeouts. - */ -static void uv__ares_timeout(uv_timer_t* handle, int status) { - assert(!uv_ares_handles_empty(handle->loop)); - ares_process_fd(handle->loop->channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD); -} - - -static void uv__ares_io(struct ev_loop* ev, struct ev_io* watcher, - int revents) { - uv_loop_t* loop = ev_userdata(ev); - - assert(ev == loop->ev); - - /* Reset the idle timer */ - uv_timer_again(&loop->timer); - - /* Process DNS responses */ - ares_process_fd(loop->channel, - revents & EV_READ ? watcher->fd : ARES_SOCKET_BAD, - revents & EV_WRITE ? watcher->fd : ARES_SOCKET_BAD); -} - - -/* Allocates and returns a new uv_ares_task_t */ -static uv_ares_task_t* uv__ares_task_create(uv_loop_t* loop, int fd) { - uv_ares_task_t* h = malloc(sizeof(uv_ares_task_t)); - - if (h == NULL) { - uv_fatal_error(ENOMEM, "malloc"); - return NULL; - } - - h->loop = loop; - h->sock = fd; - - ev_io_init(&h->read_watcher, uv__ares_io, fd, EV_READ); - ev_io_init(&h->write_watcher, uv__ares_io, fd, EV_WRITE); - - h->read_watcher.data = h; - h->write_watcher.data = h; - - return h; -} - - -/* Callback from ares when socket operation is started */ -static void uv__ares_sockstate_cb(void* data, ares_socket_t sock, - int read, int write) { - uv_loop_t* loop = data; - uv_ares_task_t* h; - - assert((uv_loop_t*)loop->timer.data == loop); - - h = uv_find_ares_handle(loop, sock); - - if (read || write) { - if (!h) { - /* New socket */ - - /* If this is the first socket then start the timer. */ - if (!uv__is_active(&loop->timer)) { - assert(uv_ares_handles_empty(loop)); - uv_timer_start(&loop->timer, uv__ares_timeout, 1000, 1000); - } - - h = uv__ares_task_create(loop, sock); - uv_add_ares_handle(loop, h); - } - - if (read) { - ev_io_start(loop->ev, &h->read_watcher); - } else { - ev_io_stop(loop->ev, &h->read_watcher); - } - - if (write) { - ev_io_start(loop->ev, &h->write_watcher); - } else { - ev_io_stop(loop->ev, &h->write_watcher); - } - - } else { - /* - * read == 0 and write == 0 this is c-ares's way of notifying us that - * the socket is now closed. We must free the data associated with - * socket. - */ - assert(h && "When an ares socket is closed we should have a handle for it"); - - ev_io_stop(loop->ev, &h->read_watcher); - ev_io_stop(loop->ev, &h->write_watcher); - - uv_remove_ares_handle(h); - free(h); - - if (uv_ares_handles_empty(loop)) { - uv_timer_stop(&loop->timer); - } - } -} - - -/* c-ares integration initialize and terminate */ -/* TODO: share this with windows? */ -int uv_ares_init_options(uv_loop_t* loop, ares_channel *channelptr, - struct ares_options *options, int optmask) { - int rc; - - /* only allow single init at a time */ - if (loop->channel != NULL) { - uv__set_artificial_error(loop, UV_EALREADY); - return -1; - } - - /* set our callback as an option */ - options->sock_state_cb = uv__ares_sockstate_cb; - options->sock_state_cb_data = loop; - optmask |= ARES_OPT_SOCK_STATE_CB; - - /* We do the call to ares_init_option for caller. */ - rc = ares_init_options(channelptr, options, optmask); - - /* if success, save channel */ - if (rc == ARES_SUCCESS) { - loop->channel = *channelptr; - } - - /* - * Initialize the timeout timer. The timer won't be started until the - * first socket is opened. - */ - uv_timer_init(loop, &loop->timer); - loop->timer.data = loop; - - return rc; -} - - -/* TODO share this with windows? */ -void uv_ares_destroy(uv_loop_t* loop, ares_channel channel) { - /* only allow destroy if did init */ - if (loop->channel) { - uv_timer_stop(&loop->timer); - ares_destroy(channel); - loop->channel = NULL; - } -} diff --git a/src/unix/internal.h b/src/unix/internal.h index eca88f8e..25213cc4 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -27,7 +27,6 @@ #include #include /* abort */ -#include /* offsetof */ #if __STRICT_ANSI__ # define inline __inline @@ -64,9 +63,6 @@ # define HAVE_KQUEUE 1 #endif -#define container_of(ptr, type, member) \ - ((type *) ((char *) (ptr) - offsetof(type, member))) - #define UNREACHABLE() \ do { \ assert(0 && "unreachable code"); \ diff --git a/src/unix/loop.c b/src/unix/loop.c index aca2a889..1373db02 100644 --- a/src/unix/loop.c +++ b/src/unix/loop.c @@ -41,7 +41,7 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) { ngx_queue_init(&loop->active_reqs); #endif - RB_INIT(&loop->uv_ares_handles_); + RB_INIT(&loop->ares_handles); ngx_queue_init(&loop->idle_handles); ngx_queue_init(&loop->check_handles); ngx_queue_init(&loop->prepare_handles); diff --git a/src/uv-common.c b/src/uv-common.c index 08aaebf3..0c6a8198 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -212,7 +212,7 @@ RB_GENERATE_STATIC(uv__ares_tasks, uv_ares_task_s, node, cmp_ares_tasks) /* add ares handle to list */ void uv_add_ares_handle(uv_loop_t* loop, uv_ares_task_t* handle) { assert(loop == handle->loop); - RB_INSERT(uv__ares_tasks, &loop->uv_ares_handles_, handle); + RB_INSERT(uv__ares_tasks, &loop->ares_handles, handle); } @@ -220,19 +220,19 @@ void uv_add_ares_handle(uv_loop_t* loop, uv_ares_task_t* handle) { uv_ares_task_t* uv_find_ares_handle(uv_loop_t* loop, ares_socket_t sock) { uv_ares_task_t handle; handle.sock = sock; - return RB_FIND(uv__ares_tasks, &loop->uv_ares_handles_, &handle); + return RB_FIND(uv__ares_tasks, &loop->ares_handles, &handle); } /* remove ares handle in list */ void uv_remove_ares_handle(uv_ares_task_t* handle) { - RB_REMOVE(uv__ares_tasks, &handle->loop->uv_ares_handles_, handle); + RB_REMOVE(uv__ares_tasks, &handle->loop->ares_handles, handle); } -/* Returns 1 if the uv_ares_handles_ list is empty. 0 otherwise. */ +/* Returns 1 if the ares_handles list is empty. 0 otherwise. */ int uv_ares_handles_empty(uv_loop_t* loop) { - return RB_EMPTY(&loop->uv_ares_handles_); + return RB_EMPTY(&loop->ares_handles); } diff --git a/src/uv-common.h b/src/uv-common.h index efc07601..d9c44896 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -28,6 +28,8 @@ #define UV_COMMON_H_ #include +#include +#include #include "uv.h" #include "tree.h" @@ -35,6 +37,9 @@ #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#define container_of(ptr, type, member) \ + ((type *) ((char *) (ptr) - offsetof(type, member))) + #ifdef _MSC_VER # define UNUSED /* empty */ #else @@ -54,17 +59,8 @@ enum { struct uv_ares_task_s { UV_HANDLE_FIELDS -#if _WIN32 - struct uv_req_s ares_req; - SOCKET sock; - HANDLE h_wait; - WSAEVENT h_event; - HANDLE h_close_event; -#else - int sock; - ev_io read_watcher; - ev_io write_watcher; -#endif + ares_socket_t sock; + uv_poll_t poll_watcher; RB_ENTRY(uv_ares_task_s) node; }; diff --git a/src/win/cares.c b/src/win/cares.c deleted file mode 100644 index 359bc213..00000000 --- a/src/win/cares.c +++ /dev/null @@ -1,288 +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 - -#include "uv.h" -#include "internal.h" - - -/* - * Subclass of uv_handle_t. Used for integration of c-ares. - */ -struct uv_ares_action_s { - UV_HANDLE_FIELDS - struct uv_req_s ares_req; - SOCKET sock; - int read; - int write; -}; - - -/* default timeout per socket request if ares does not specify value */ -/* use 20 sec */ -#define ARES_TIMEOUT_MS 20000 - - -/* thread pool callback when socket is signalled */ -static void CALLBACK uv_ares_socksignal_tp(void* parameter, - BOOLEAN timerfired) { - WSANETWORKEVENTS network_events; - uv_ares_task_t* sockhandle; - uv_ares_action_t* selhandle; - uv_req_t* uv_ares_req; - uv_loop_t* loop; - - assert(parameter != NULL); - - if (parameter != NULL) { - sockhandle = (uv_ares_task_t*) parameter; - loop = sockhandle->loop; - - /* clear socket status for this event */ - /* do not fail if error, thread may run after socket close */ - /* The code assumes that c-ares will write all pending data in the */ - /* callback, unless the socket would block. We can clear the state here */ - /* to avoid unnecessary signals. */ - WSAEnumNetworkEvents(sockhandle->sock, - sockhandle->h_event, - &network_events); - - /* setup new handle */ - selhandle = (uv_ares_action_t*)malloc(sizeof(uv_ares_action_t)); - if (selhandle == NULL) { - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); - } - selhandle->type = UV_ARES_EVENT; - selhandle->close_cb = NULL; - selhandle->data = sockhandle->data; - selhandle->sock = sockhandle->sock; - selhandle->read = - (network_events.lNetworkEvents & (FD_READ | FD_CONNECT)) ? 1 : 0; - selhandle->write = - (network_events.lNetworkEvents & (FD_WRITE | FD_CONNECT)) ? 1 : 0; - - uv_ares_req = &selhandle->ares_req; - uv_req_init(loop, uv_ares_req); - uv_ares_req->type = UV_ARES_EVENT_REQ; - uv_ares_req->data = selhandle; - - /* post ares needs to called */ - POST_COMPLETION_FOR_REQ(loop, uv_ares_req); - } -} - - -/* periodically call ares to check for timeouts */ -static void uv_ares_poll(uv_timer_t* handle, int status) { - uv_loop_t* loop = handle->loop; - if (loop->ares_chan != NULL && loop->ares_active_sockets > 0) { - ares_process_fd(loop->ares_chan, ARES_SOCKET_BAD, ARES_SOCKET_BAD); - } -} - - -/* callback from ares when socket operation is started */ -static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read, - int write) { - /* look to see if we have a handle for this socket in our list */ - uv_loop_t* loop = (uv_loop_t*) data; - uv_ares_task_t* uv_handle_ares = uv_find_ares_handle(loop, sock); - - if (read == 0 && write == 0) { - /* if read and write are 0, cleanup existing data */ - /* The code assumes that c-ares does a callback with read = 0 and */ - /* write = 0 when the socket is closed. After we receive this we stop */ - /* monitoring the socket. */ - if (uv_handle_ares != NULL) { - uv_req_t* uv_ares_req; - - uv_handle_ares->h_close_event = CreateEvent(NULL, FALSE, FALSE, NULL); - /* remove Wait */ - if (uv_handle_ares->h_wait) { - UnregisterWaitEx(uv_handle_ares->h_wait, - uv_handle_ares->h_close_event); - uv_handle_ares->h_wait = NULL; - } - - /* detach socket from the event */ - WSAEventSelect(sock, NULL, 0); - if (uv_handle_ares->h_event != WSA_INVALID_EVENT) { - WSACloseEvent(uv_handle_ares->h_event); - uv_handle_ares->h_event = WSA_INVALID_EVENT; - } - /* remove handle from list */ - uv_remove_ares_handle(uv_handle_ares); - uv__handle_stop(uv_handle_ares); - - /* Post request to cleanup the Task */ - uv_ares_req = &uv_handle_ares->ares_req; - uv_req_init(loop, uv_ares_req); - uv_ares_req->type = UV_ARES_CLEANUP_REQ; - uv_ares_req->data = uv_handle_ares; - - /* post ares done with socket - finish cleanup when all threads done. */ - POST_COMPLETION_FOR_REQ(loop, uv_ares_req); - } else { - assert(0); - uv_fatal_error(ERROR_INVALID_DATA, "ares_SockStateCB"); - } - } else { - if (uv_handle_ares == NULL) { - /* setup new handle */ - /* The code assumes that c-ares will call us when it has an open socket. - We need to call into c-ares when there is something to read, - or when it becomes writable. */ - uv_handle_ares = (uv_ares_task_t*)malloc(sizeof(uv_ares_task_t)); - if (uv_handle_ares == NULL) { - uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); - } - uv_handle_ares->type = UV_ARES_TASK; - uv_handle_ares->close_cb = NULL; - uv_handle_ares->loop = loop; - uv_handle_ares->data = loop; - uv_handle_ares->sock = sock; - uv_handle_ares->h_wait = NULL; - uv_handle_ares->flags = 0; - - /* create an event to wait on socket signal */ - uv_handle_ares->h_event = WSACreateEvent(); - if (uv_handle_ares->h_event == WSA_INVALID_EVENT) { - uv_fatal_error(WSAGetLastError(), "WSACreateEvent"); - } - - /* tie event to socket */ - if (SOCKET_ERROR == WSAEventSelect(sock, - uv_handle_ares->h_event, - FD_READ | FD_WRITE | FD_CONNECT)) { - uv_fatal_error(WSAGetLastError(), "WSAEventSelect"); - } - - /* add handle to list */ - uv_add_ares_handle(loop, uv_handle_ares); - uv__handle_start(uv_handle_ares); - - /* - * we have a single polling timer for all ares sockets. - * This is preferred to using ares_timeout. See ares_timeout.c warning. - * if timer is not running start it, and keep socket count - */ - if (loop->ares_active_sockets == 0) { - uv_timer_init(loop, &loop->ares_polling_timer); - uv_timer_start(&loop->ares_polling_timer, uv_ares_poll, 1000L, 1000L); - } - loop->ares_active_sockets++; - - /* specify thread pool function to call when event is signaled */ - if (RegisterWaitForSingleObject(&uv_handle_ares->h_wait, - uv_handle_ares->h_event, - uv_ares_socksignal_tp, - (void*)uv_handle_ares, - INFINITE, - WT_EXECUTEINWAITTHREAD) == 0) { - uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject"); - } - } else { - /* found existing handle. */ - assert(uv_handle_ares->type == UV_ARES_TASK); - assert(uv_handle_ares->data != NULL); - assert(uv_handle_ares->h_event != WSA_INVALID_EVENT); - } - } -} - - -/* called via uv_poll when ares completion port signaled */ -void uv_process_ares_event_req(uv_loop_t* loop, uv_ares_action_t* handle, - uv_req_t* req) { - ares_process_fd(loop->ares_chan, - handle->read ? handle->sock : INVALID_SOCKET, - handle->write ? handle->sock : INVALID_SOCKET); - - /* release handle for select here */ - free(handle); -} - - -/* called via uv_poll when ares is finished with socket */ -void uv_process_ares_cleanup_req(uv_loop_t* loop, uv_ares_task_t* handle, - uv_req_t* req) { - /* check for event complete without waiting */ - unsigned int signaled = WaitForSingleObject(handle->h_close_event, 0); - - if (signaled != WAIT_TIMEOUT) { - uv__handle_stop(loop); - - /* close event handle and free uv handle memory */ - CloseHandle(handle->h_close_event); - free(handle); - - /* decrement active count. if it becomes 0 stop polling */ - if (loop->ares_active_sockets > 0) { - loop->ares_active_sockets--; - if (loop->ares_active_sockets == 0) { - uv_close((uv_handle_t*) &loop->ares_polling_timer, NULL); - } - } - } else { - /* still busy - repost and try again */ - POST_COMPLETION_FOR_REQ(loop, req); - } -} - - -/* set ares SOCK_STATE callback to our handler */ -int uv_ares_init_options(uv_loop_t* loop, - ares_channel *channelptr, - struct ares_options *options, - int optmask) { - int rc; - - /* only allow single init at a time */ - if (loop->ares_chan != NULL) { - return UV_EALREADY; - } - - /* set our callback as an option */ - options->sock_state_cb = uv_ares_sockstate_cb; - options->sock_state_cb_data = loop; - optmask |= ARES_OPT_SOCK_STATE_CB; - - /* We do the call to ares_init_option for caller. */ - rc = ares_init_options(channelptr, options, optmask); - - /* if success, save channel */ - if (rc == ARES_SUCCESS) { - loop->ares_chan = *channelptr; - } - - return rc; -} - - -/* release memory */ -void uv_ares_destroy(uv_loop_t* loop, ares_channel channel) { - /* only allow destroy if did init */ - if (loop->ares_chan != NULL) { - ares_destroy(channel); - loop->ares_chan = NULL; - } -} diff --git a/src/win/core.c b/src/win/core.c index 27f3438b..c24cfc3b 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -79,7 +79,6 @@ static void uv_loop_init(uv_loop_t* loop) { loop->endgame_handles = NULL; RB_INIT(&loop->timers); - RB_INIT(&loop->uv_ares_handles_); loop->check_handles = NULL; loop->prepare_handles = NULL; @@ -91,8 +90,8 @@ static void uv_loop_init(uv_loop_t* loop) { memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets); - loop->ares_active_sockets = 0; - loop->ares_chan = NULL; + loop->channel = NULL; + RB_INIT(&loop->ares_handles); loop->active_tcp_streams = 0; loop->active_udp_streams = 0; diff --git a/src/win/internal.h b/src/win/internal.h index 362e23f2..f594ddd3 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -312,16 +312,6 @@ void uv_process_close(uv_loop_t* loop, uv_process_t* handle); void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle); -/* - * C-ares integration - */ -typedef struct uv_ares_action_s uv_ares_action_t; - -void uv_process_ares_event_req(uv_loop_t* loop, uv_ares_action_t* handle, - uv_req_t* req); -void uv_process_ares_cleanup_req(uv_loop_t* loop, uv_ares_task_t* handle, - uv_req_t* req); - /* * Getaddrinfo */ diff --git a/src/win/req.c b/src/win/req.c index 1aae7091..ada4eb1b 100644 --- a/src/win/req.c +++ b/src/win/req.c @@ -138,14 +138,6 @@ void uv_process_reqs(uv_loop_t* loop) { uv_process_poll_req(loop, (uv_poll_t*) req->data, req); break; - case UV_ARES_EVENT_REQ: - uv_process_ares_event_req(loop, (uv_ares_action_t*) req->data, req); - break; - - case UV_ARES_CLEANUP_REQ: - uv_process_ares_cleanup_req(loop, (uv_ares_task_t*) req->data, req); - break; - case UV_GETADDRINFO: uv_process_getaddrinfo_req(loop, (uv_getaddrinfo_t*) req); break; diff --git a/uv.gyp b/uv.gyp index 24da3e2d..28f99948 100644 --- a/uv.gyp +++ b/uv.gyp @@ -49,6 +49,7 @@ 'include/uv.h', 'include/uv-private/ngx-queue.h', 'include/uv-private/tree.h', + 'src/cares.c', 'src/uv-common.c', 'src/uv-common.h', 'src/ares/ares_cancel.c', @@ -134,7 +135,6 @@ 'src/ares/ares_iphlpapi.h', 'src/ares/ares_platform.c', 'src/win/async.c', - 'src/win/cares.c', 'src/win/core.c', 'src/win/dl.c', 'src/win/error.c', @@ -182,7 +182,6 @@ 'include/uv-private/ev.h', 'include/uv-private/uv-unix.h', 'src/unix/async.c', - 'src/unix/cares.c', 'src/unix/core.c', 'src/unix/dl.c', 'src/unix/eio/ecb.h',