diff --git a/config-unix.mk b/config-unix.mk index 8d26fc44..860059e4 100644 --- a/config-unix.mk +++ b/config-unix.mk @@ -29,16 +29,13 @@ CPPFLAGS += -D_FILE_OFFSET_BITS=64 OBJS += src/unix/async.o OBJS += src/unix/cares.o -OBJS += src/unix/check.o OBJS += src/unix/core.o OBJS += src/unix/dl.o OBJS += src/unix/error.o OBJS += src/unix/fs.o -OBJS += src/unix/idle.o OBJS += src/unix/loop.o OBJS += src/unix/pipe.o OBJS += src/unix/poll.o -OBJS += src/unix/prepare.o OBJS += src/unix/process.o OBJS += src/unix/stream.o OBJS += src/unix/tcp.o diff --git a/include/uv-private/uv-unix.h b/include/uv-private/uv-unix.h index 245cb5ef..5f94ca58 100644 --- a/include/uv-private/uv-unix.h +++ b/include/uv-private/uv-unix.h @@ -104,7 +104,10 @@ typedef struct { uv_async_t uv_eio_want_poll_notifier; \ uv_async_t uv_eio_done_poll_notifier; \ uv_idle_t uv_eio_poller; \ - uv_handle_t* endgame_handles; \ + uv_handle_t* pending_handles; \ + ngx_queue_t prepare_handles; \ + ngx_queue_t check_handles; \ + ngx_queue_t idle_handles; \ UV_LOOP_PRIVATE_PLATFORM_FIELDS #define UV_REQ_BUFSML_SIZE (4) @@ -141,7 +144,7 @@ typedef struct { #define UV_HANDLE_PRIVATE_FIELDS \ int fd; \ int flags; \ - uv_handle_t* endgame_next; /* that's what uv-win calls it */ \ + uv_handle_t* next_pending; \ #define UV_STREAM_PRIVATE_FIELDS \ @@ -183,20 +186,20 @@ typedef struct { /* UV_PREPARE */ \ #define UV_PREPARE_PRIVATE_FIELDS \ - ev_prepare prepare_watcher; \ - uv_prepare_cb prepare_cb; + uv_prepare_cb prepare_cb; \ + ngx_queue_t queue; /* UV_CHECK */ #define UV_CHECK_PRIVATE_FIELDS \ - ev_check check_watcher; \ - uv_check_cb check_cb; + uv_check_cb check_cb; \ + ngx_queue_t queue; /* UV_IDLE */ #define UV_IDLE_PRIVATE_FIELDS \ - ev_idle idle_watcher; \ - uv_idle_cb idle_cb; + uv_idle_cb idle_cb; \ + ngx_queue_t queue; /* UV_ASYNC */ diff --git a/include/uv-private/uv-win.h b/include/uv-private/uv-win.h index 4c71e4ac..c1d16e84 100644 --- a/include/uv-private/uv-win.h +++ b/include/uv-private/uv-win.h @@ -32,6 +32,7 @@ #include #include "tree.h" +#include "ngx-queue.h" #define MAX_PIPENAME_LEN 256 @@ -203,8 +204,6 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); #define UV_LOOP_PRIVATE_FIELDS \ /* The loop's I/O completion port */ \ HANDLE iocp; \ - /* Reference count that keeps the event loop alive */ \ - int refs; \ /* The current time according to the event loop. in msecs. */ \ int64_t time; \ /* Tail of a single-linked circular queue of pending reqs. If the queue */ \ @@ -246,7 +245,6 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); UV_ARES_EVENT_REQ, \ UV_ARES_CLEANUP_REQ, \ UV_FS_EVENT_REQ, \ - UV_GETADDRINFO_REQ, \ UV_POLL_REQ, \ UV_PROCESS_EXIT, \ UV_PROCESS_CLOSE, \ @@ -310,6 +308,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); #define UV_STREAM_PRIVATE_FIELDS \ unsigned int reqs_pending; \ + int activecnt; \ uv_read_t read_req; \ union { \ struct { uv_stream_connection_fields }; \ @@ -337,6 +336,7 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); #define UV_UDP_PRIVATE_FIELDS \ SOCKET socket; \ unsigned int reqs_pending; \ + int activecnt; \ uv_req_t recv_req; \ uv_buf_t recv_buffer; \ struct sockaddr_storage recv_from; \ @@ -444,7 +444,6 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s); unsigned int flags; #define UV_GETADDRINFO_PRIVATE_FIELDS \ - struct uv_req_s getadddrinfo_req; \ uv_getaddrinfo_cb getaddrinfo_cb; \ void* alloc; \ wchar_t* node; \ diff --git a/include/uv.h b/include/uv.h index 44bf0fc3..29c84e0b 100644 --- a/include/uv.h +++ b/include/uv.h @@ -224,10 +224,6 @@ typedef struct uv_work_s uv_work_t; UV_EXTERN uv_loop_t* uv_loop_new(void); UV_EXTERN void uv_loop_delete(uv_loop_t*); -/* This is a debugging tool. It's NOT part of the official API. */ -UV_EXTERN int uv_loop_refcount(const uv_loop_t*); - - /* * Returns the default loop. */ @@ -248,8 +244,8 @@ UV_EXTERN int uv_run_once (uv_loop_t*); * Manually modify the event loop's reference count. Useful if the user wants * to have a handle or timeout that doesn't keep the loop alive. */ -UV_EXTERN void uv_ref(uv_loop_t*); -UV_EXTERN void uv_unref(uv_loop_t*); +UV_EXTERN void uv_ref(uv_handle_t*); +UV_EXTERN void uv_unref(uv_handle_t*); UV_EXTERN void uv_update_time(uv_loop_t*); UV_EXTERN int64_t uv_now(uv_loop_t*); @@ -336,12 +332,18 @@ UV_EXTERN uv_err_t uv_last_error(uv_loop_t*); UV_EXTERN const char* uv_strerror(uv_err_t err); UV_EXTERN const char* uv_err_name(uv_err_t err); +#ifndef UV_LEAN_AND_MEAN +# define UV_REQ_EXTRA_FIELDS ngx_queue_t active_queue; +#else +# define UV_REQ_EXTRA_FIELDS +#endif #define UV_REQ_FIELDS \ /* read-only */ \ uv_req_type type; \ /* public */ \ void* data; \ + UV_REQ_EXTRA_FIELDS \ /* private */ \ UV_REQ_PRIVATE_FIELDS @@ -374,6 +376,12 @@ struct uv_shutdown_s { }; +#ifndef UV_LEAN_AND_MEAN +# define UV_HANDLE_EXTRA_FIELDS ngx_queue_t active_queue; +#else +# define UV_HANDLE_EXTRA_FIELDS +#endif + #define UV_HANDLE_FIELDS \ /* read-only */ \ uv_loop_t* loop; \ @@ -381,6 +389,7 @@ struct uv_shutdown_s { /* public */ \ uv_close_cb close_cb; \ void* data; \ + UV_HANDLE_EXTRA_FIELDS \ /* private */ \ UV_HANDLE_PRIVATE_FIELDS @@ -1638,6 +1647,13 @@ struct uv_loop_s { uv_err_t last_err; /* User data - use this for whatever. */ void* data; +#ifndef UV_LEAN_AND_MEAN + ngx_queue_t active_reqs; + ngx_queue_t active_handles; +#else + unsigned int active_reqs; + unsigned int active_handles; +#endif }; diff --git a/src/unix/async.c b/src/unix/async.c index 638774c6..db9ce188 100644 --- a/src/unix/async.c +++ b/src/unix/async.c @@ -40,7 +40,8 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* async, uv_async_cb async_cb) { /* Note: This does not have symmetry with the other libev wrappers. */ ev_async_start(loop->ev, &async->async_watcher); - ev_unref(loop->ev); + uv__handle_unref(async); + uv__handle_start(async); return 0; } @@ -54,5 +55,6 @@ int uv_async_send(uv_async_t* async) { void uv__async_close(uv_async_t* handle) { ev_async_stop(handle->loop->ev, &handle->async_watcher); - ev_ref(handle->loop->ev); + uv__handle_ref(handle); + uv__handle_stop(handle); } diff --git a/src/unix/cares.c b/src/unix/cares.c index 03667fda..a579eaa1 100644 --- a/src/unix/cares.c +++ b/src/unix/cares.c @@ -37,20 +37,6 @@ static void uv__ares_timeout(uv_timer_t* handle, int status) { } -static void uv__ares_timer_start(uv_loop_t* loop) { - if (uv_is_active((uv_handle_t*)&loop->timer)) return; - uv_timer_start(&loop->timer, uv__ares_timeout, 1000, 1000); - uv_ref(loop); -} - - -static void uv__ares_timer_stop(uv_loop_t* loop) { - if (!uv_is_active((uv_handle_t*)&loop->timer)) return; - uv_timer_stop(&loop->timer); - uv_unref(loop); -} - - static void uv__ares_io(struct ev_loop* ev, struct ev_io* watcher, int revents) { uv_loop_t* loop = ev_userdata(ev); @@ -104,9 +90,9 @@ static void uv__ares_sockstate_cb(void* data, ares_socket_t sock, /* New socket */ /* If this is the first socket then start the timer. */ - if (!uv_is_active((uv_handle_t*)&loop->timer)) { + if (!uv__is_active(&loop->timer)) { assert(uv_ares_handles_empty(loop)); - uv__ares_timer_start(loop); + uv_timer_start(&loop->timer, uv__ares_timeout, 1000, 1000); } h = uv__ares_task_create(loop, sock); @@ -140,7 +126,7 @@ static void uv__ares_sockstate_cb(void* data, ares_socket_t sock, free(h); if (uv_ares_handles_empty(loop)) { - uv__ares_timer_stop(loop); + uv_timer_stop(&loop->timer); } } } @@ -176,7 +162,6 @@ int uv_ares_init_options(uv_loop_t* loop, ares_channel *channelptr, * first socket is opened. */ uv_timer_init(loop, &loop->timer); - uv_unref(loop); loop->timer.data = loop; return rc; @@ -187,7 +172,7 @@ int uv_ares_init_options(uv_loop_t* loop, ares_channel *channelptr, void uv_ares_destroy(uv_loop_t* loop, ares_channel channel) { /* only allow destroy if did init */ if (loop->channel) { - uv__ares_timer_stop(loop); + uv_timer_stop(&loop->timer); ares_destroy(channel); loop->channel = NULL; } diff --git a/src/unix/check.c b/src/unix/check.c deleted file mode 100644 index a9752100..00000000 --- a/src/unix/check.c +++ /dev/null @@ -1,80 +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" - - -static void uv__check(EV_P_ ev_check* w, int revents) { - uv_check_t* check = container_of(w, uv_check_t, check_watcher); - - if (check->check_cb) { - check->check_cb(check, 0); - } -} - - -int uv_check_init(uv_loop_t* loop, uv_check_t* check) { - uv__handle_init(loop, (uv_handle_t*)check, UV_CHECK); - loop->counters.check_init++; - - ev_check_init(&check->check_watcher, uv__check); - check->check_cb = NULL; - - return 0; -} - - -int uv_check_start(uv_check_t* check, uv_check_cb cb) { - int was_active = ev_is_active(&check->check_watcher); - - check->check_cb = cb; - - ev_check_start(check->loop->ev, &check->check_watcher); - - if (!was_active) { - ev_unref(check->loop->ev); - } - - return 0; -} - - -int uv_check_stop(uv_check_t* check) { - int was_active = ev_is_active(&check->check_watcher); - - ev_check_stop(check->loop->ev, &check->check_watcher); - - if (was_active) { - ev_ref(check->loop->ev); - } - - return 0; -} - - -int uv__check_active(const uv_check_t* handle) { - return ev_is_active(&handle->check_watcher); -} - - -void uv__check_close(uv_check_t* handle) { - uv_check_stop(handle); -} diff --git a/src/unix/core.c b/src/unix/core.c index 3e862fad..72bc7957 100644 --- a/src/unix/core.c +++ b/src/unix/core.c @@ -19,7 +19,7 @@ */ #include "uv.h" -#include "unix/internal.h" +#include "internal.h" #include /* NULL */ #include /* printf */ @@ -116,9 +116,7 @@ void uv_close(uv_handle_t* handle, uv_close_cb close_cb) { } handle->flags |= UV_CLOSING; - handle->endgame_next = handle->loop->endgame_handles; - handle->loop->endgame_handles = handle; - uv_unref(handle->loop); + uv__make_pending(handle); } @@ -165,24 +163,66 @@ void uv_loop_delete(uv_loop_t* loop) { } -int uv_loop_refcount(const uv_loop_t* loop) { - return ev_loop_refcount(loop->ev); +static void uv__run_pending(uv_loop_t* loop) { + uv_handle_t* p; + uv_handle_t* q; + + if (!loop->pending_handles) + return; + + for (p = loop->pending_handles, loop->pending_handles = NULL; p; p = q) { + q = p->next_pending; + p->next_pending = NULL; + p->flags &= ~UV__PENDING; + + if (p->flags & UV_CLOSING) { + uv__finish_close(p); + continue; + } + + switch (p->type) { + case UV_NAMED_PIPE: + case UV_TCP: + case UV_TTY: + uv__stream_pending((uv_stream_t*)p); + break; + default: + abort(); + } + } } -void uv__run(uv_loop_t* loop) { - ev_run(loop->ev, EVRUN_ONCE); +static void uv__poll(uv_loop_t* loop, int block) { + /* bump the loop's refcount, otherwise libev does + * a zero timeout poll and we end up busy looping + */ + ev_ref(loop->ev); + ev_run(loop->ev, block ? EVRUN_ONCE : EVRUN_NOWAIT); + ev_unref(loop->ev); +} - while (loop->endgame_handles) - uv__finish_close(loop->endgame_handles); + +static int uv__run(uv_loop_t* loop) { + if (!uv__has_pending_handles(loop) && !uv__has_active_reqs(loop)) + uv__run_idle(loop); + + uv__run_pending(loop); + uv__run_prepare(loop); + + if (uv__has_active_handles(loop) || uv__has_active_reqs(loop)) + uv__poll(loop, 0); + + uv__run_check(loop); + + return uv__has_pending_handles(loop) + || uv__has_active_handles(loop) + || uv__has_active_reqs(loop); } int uv_run(uv_loop_t* loop) { - do - uv__run(loop); - while (uv_loop_refcount(loop) > 0); - + while (uv__run(loop)); return 0; } @@ -199,38 +239,24 @@ void uv__handle_init(uv_loop_t* loop, uv_handle_t* handle, handle->loop = loop; handle->type = type; - handle->flags = 0; - handle->endgame_next = NULL; - uv_ref(loop); /* unref'd in uv_close() */ + handle->flags = UV__REF; /* ref the loop when active */ + handle->next_pending = NULL; } void uv__finish_close(uv_handle_t* handle) { - uv_loop_t* loop = handle->loop; - + assert(!uv__is_active(handle)); assert(handle->flags & UV_CLOSING); assert(!(handle->flags & UV_CLOSED)); handle->flags |= UV_CLOSED; switch (handle->type) { case UV_PREPARE: - assert(!ev_is_active(&((uv_prepare_t*)handle)->prepare_watcher)); - break; - case UV_CHECK: - assert(!ev_is_active(&((uv_check_t*)handle)->check_watcher)); - break; - case UV_IDLE: - assert(!ev_is_active(&((uv_idle_t*)handle)->idle_watcher)); - break; - case UV_ASYNC: - assert(!ev_is_active(&((uv_async_t*)handle)->async_watcher)); - break; - case UV_TIMER: - assert(!ev_is_active(&((uv_timer_t*)handle)->timer_watcher)); + case UV_PROCESS: break; case UV_NAMED_PIPE: @@ -246,10 +272,6 @@ void uv__finish_close(uv_handle_t* handle) { uv__udp_finish_close((uv_udp_t*)handle); break; - case UV_PROCESS: - assert(!ev_is_active(&((uv_process_t*)handle)->child_watcher)); - break; - case UV_FS_EVENT: break; @@ -262,21 +284,11 @@ void uv__finish_close(uv_handle_t* handle) { } - loop->endgame_handles = handle->endgame_next; - if (handle->close_cb) { handle->close_cb(handle); } -} - -void uv_ref(uv_loop_t* loop) { - ev_ref(loop->ev); -} - - -void uv_unref(uv_loop_t* loop) { - ev_unref(loop->ev); + uv__handle_unref(handle); } @@ -291,56 +303,43 @@ int64_t uv_now(uv_loop_t* loop) { int uv_is_active(const uv_handle_t* handle) { - switch (handle->type) { - case UV_POLL: - return uv__poll_active((const uv_poll_t*)handle); - case UV_CHECK: - return uv__check_active((const uv_check_t*)handle); - case UV_IDLE: - return uv__idle_active((const uv_idle_t*)handle); - case UV_PREPARE: - return uv__prepare_active((const uv_prepare_t*)handle); - case UV_TIMER: - return uv__timer_active((const uv_timer_t*)handle); - default: - return 1; - } + return uv__is_active(handle); } -static int uv_getaddrinfo_done(eio_req* req) { - uv_getaddrinfo_t* handle = req->data; - struct addrinfo *res = handle->res; +static int uv_getaddrinfo_done(eio_req* req_) { + uv_getaddrinfo_t* req = req_->data; + struct addrinfo *res = req->res; #if __sun size_t hostlen = strlen(handle->hostname); #endif - handle->res = NULL; + req->res = NULL; - uv_unref(handle->loop); + uv__req_unregister(req->loop, req); - free(handle->hints); - free(handle->service); - free(handle->hostname); + free(req->hints); + free(req->service); + free(req->hostname); - if (handle->retcode == 0) { + if (req->retcode == 0) { /* OK */ #if EAI_NODATA /* FreeBSD deprecated EAI_NODATA */ - } else if (handle->retcode == EAI_NONAME || handle->retcode == EAI_NODATA) { + } else if (req->retcode == EAI_NONAME || req->retcode == EAI_NODATA) { #else - } else if (handle->retcode == EAI_NONAME) { + } else if (req->retcode == EAI_NONAME) { #endif - uv__set_sys_error(handle->loop, ENOENT); /* FIXME compatibility hack */ + uv__set_sys_error(req->loop, ENOENT); /* FIXME compatibility hack */ #if __sun - } else if (handle->retcode == EAI_MEMORY && hostlen >= MAXHOSTNAMELEN) { - uv__set_sys_error(handle->loop, ENOENT); + } else if (req->retcode == EAI_MEMORY && hostlen >= MAXHOSTNAMELEN) { + uv__set_sys_error(req->loop, ENOENT); #endif } else { - handle->loop->last_err.code = UV_EADDRINFO; - handle->loop->last_err.sys_errno_ = handle->retcode; + req->loop->last_err.code = UV_EADDRINFO; + req->loop->last_err.sys_errno_ = req->retcode; } - handle->cb(handle, handle->retcode, res); + req->cb(req, req->retcode, res); return 0; } @@ -396,8 +395,6 @@ int uv_getaddrinfo(uv_loop_t* loop, /* TODO check handle->hostname == NULL */ /* TODO check handle->service == NULL */ - uv_ref(loop); - req = eio_custom(getaddrinfo_thread_proc, EIO_PRI_DEFAULT, uv_getaddrinfo_done, handle, &loop->uv_eio_channel); assert(req); @@ -480,7 +477,7 @@ int uv__accept(int sockfd, struct sockaddr* saddr, socklen_t slen) { int uv__nonblock(int fd, int set) { -#ifdef FIONBIO +#if FIONBIO return ioctl(fd, FIONBIO, &set); #else int flags; diff --git a/src/unix/fs.c b/src/unix/fs.c index 3417fa62..e62832db 100644 --- a/src/unix/fs.c +++ b/src/unix/fs.c @@ -49,7 +49,6 @@ uv__set_sys_error(loop, ENOMEM); \ return -1; \ } \ - uv_ref(loop); \ } else { \ /* sync */ \ req->result = func(args); \ @@ -75,10 +74,17 @@ static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req, uv_fs_type fs_type, req->path = path ? strdup(path) : NULL; req->errorno = 0; req->eio = NULL; + + /* synchronous requests don't increase the reference count */ + if (!req->cb) + uv__req_unregister(req->loop, req); } void uv_fs_req_cleanup(uv_fs_t* req) { + if (req->cb) + uv__req_unregister(req->loop, req); + free(req->path); req->path = NULL; @@ -169,10 +175,9 @@ static int uv__fs_after(eio_req* eio) { break; } - uv_unref(req->loop); req->eio = NULL; /* Freed by libeio */ - req->cb(req); + return 0; } @@ -189,7 +194,6 @@ int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, if (cb) { /* async */ - uv_ref(loop); req->eio = eio_open(path, flags, mode, EIO_PRI_DEFAULT, uv__fs_after, req, &loop->uv_eio_channel); if (!req->eio) { uv__set_sys_error(loop, ENOMEM); @@ -219,7 +223,6 @@ int uv_fs_read(uv_loop_t* loop, uv_fs_t* req, uv_file fd, void* buf, if (cb) { /* async */ - uv_ref(loop); req->eio = eio_read(fd, buf, length, offset, EIO_PRI_DEFAULT, uv__fs_after, req, &loop->uv_eio_channel); @@ -257,7 +260,6 @@ int uv_fs_write(uv_loop_t* loop, uv_fs_t* req, uv_file file, void* buf, if (cb) { /* async */ - uv_ref(loop); req->eio = eio_write(file, buf, length, offset, EIO_PRI_DEFAULT, uv__fs_after, req, &loop->uv_eio_channel); if (!req->eio) { @@ -305,7 +307,6 @@ int uv_fs_readdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags, if (cb) { /* async */ - uv_ref(loop); req->eio = eio_readdir(path, flags, EIO_PRI_DEFAULT, uv__fs_after, req, &loop->uv_eio_channel); if (!req->eio) { uv__set_sys_error(loop, ENOMEM); @@ -375,7 +376,6 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { if (cb) { /* async */ - uv_ref(loop); req->eio = eio_stat(pathdup, EIO_PRI_DEFAULT, uv__fs_after, req, &loop->uv_eio_channel); free(pathdup); @@ -409,7 +409,6 @@ int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) { if (cb) { /* async */ - uv_ref(loop); req->eio = eio_fstat(file, EIO_PRI_DEFAULT, uv__fs_after, req, &loop->uv_eio_channel); if (!req->eio) { @@ -495,7 +494,6 @@ int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime, } -#if HAVE_FUTIMES static int _futime(const uv_file fd, double atime, double mtime) { #if __linux__ /* utimesat() has nanosecond resolution but we stick to microseconds @@ -507,30 +505,24 @@ static int _futime(const uv_file fd, double atime, double mtime) { ts[1].tv_sec = mtime; ts[1].tv_nsec = (unsigned long)(mtime * 1000000) % 1000000 * 1000; return uv__utimesat(fd, NULL, ts, 0); -#else +#elif HAVE_FUTIMES struct timeval tv[2]; tv[0].tv_sec = atime; tv[0].tv_usec = (unsigned long)(atime * 1000000) % 1000000; tv[1].tv_sec = mtime; tv[1].tv_usec = (unsigned long)(mtime * 1000000) % 1000000; return futimes(fd, tv); -#endif /* __linux__ */ +#else /* !HAVE_FUTIMES */ + errno = ENOSYS; + return -1; +#endif } -#endif /* HAVE_FUTIMES */ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime, double mtime, uv_fs_cb cb) { const char* path = NULL; - - uv_fs_req_init(loop, req, UV_FS_FUTIME, path, cb); - -#if HAVE_FUTIMES WRAP_EIO(UV_FS_FUTIME, eio_futime, _futime, ARGS3(file, atime, mtime)) -#else - uv__set_sys_error(loop, ENOSYS); - return -1; -#endif } @@ -552,7 +544,6 @@ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { if (cb) { /* async */ - uv_ref(loop); req->eio = eio_lstat(pathdup, EIO_PRI_DEFAULT, uv__fs_after, req, &loop->uv_eio_channel); free(pathdup); @@ -602,7 +593,6 @@ int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path, if (cb) { if ((req->eio = eio_readlink(path, EIO_PRI_DEFAULT, uv__fs_after, req, &loop->uv_eio_channel))) { - uv_ref(loop); return 0; } else { uv__set_sys_error(loop, ENOMEM); @@ -674,7 +664,7 @@ static void uv__work(eio_req* eio) { static int uv__after_work(eio_req *eio) { uv_work_t* req = eio->data; - uv_unref(req->loop); + uv__req_unregister(req->loop, req); if (req->after_work_cb) { req->after_work_cb(req); } @@ -689,13 +679,16 @@ int uv_queue_work(uv_loop_t* loop, uv_work_t* req, uv_work_cb work_cb, uv_eio_init(loop); uv__req_init(loop, req, UV_WORK); - uv_ref(loop); req->loop = loop; req->data = data; req->work_cb = work_cb; req->after_work_cb = after_work_cb; - req->eio = eio_custom(uv__work, EIO_PRI_DEFAULT, uv__after_work, req, &loop->uv_eio_channel); + req->eio = eio_custom(uv__work, + EIO_PRI_DEFAULT, + uv__after_work, + req, + &loop->uv_eio_channel); if (!req->eio) { uv__set_sys_error(loop, ENOMEM); diff --git a/src/unix/idle.c b/src/unix/idle.c deleted file mode 100644 index 5b4cf577..00000000 --- a/src/unix/idle.c +++ /dev/null @@ -1,79 +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" - - -static void uv__idle(EV_P_ ev_idle* w, int revents) { - uv_idle_t* idle = container_of(w, uv_idle_t, idle_watcher); - - if (idle->idle_cb) { - idle->idle_cb(idle, 0); - } -} - - -int uv_idle_init(uv_loop_t* loop, uv_idle_t* idle) { - uv__handle_init(loop, (uv_handle_t*)idle, UV_IDLE); - loop->counters.idle_init++; - - ev_idle_init(&idle->idle_watcher, uv__idle); - idle->idle_cb = NULL; - - return 0; -} - - -int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb) { - int was_active = ev_is_active(&idle->idle_watcher); - - idle->idle_cb = cb; - ev_idle_start(idle->loop->ev, &idle->idle_watcher); - - if (!was_active) { - ev_unref(idle->loop->ev); - } - - return 0; -} - - -int uv_idle_stop(uv_idle_t* idle) { - int was_active = ev_is_active(&idle->idle_watcher); - - ev_idle_stop(idle->loop->ev, &idle->idle_watcher); - - if (was_active) { - ev_ref(idle->loop->ev); - } - - return 0; -} - - -int uv__idle_active(const uv_idle_t* handle) { - return ev_is_active(&handle->idle_watcher); -} - - -void uv__idle_close(uv_idle_t* handle) { - uv_idle_stop(handle); -} diff --git a/src/unix/internal.h b/src/unix/internal.h index 724120d4..eca88f8e 100644 --- a/src/unix/internal.h +++ b/src/unix/internal.h @@ -84,24 +84,41 @@ /* flags */ enum { - UV_CLOSING = 0x01, /* uv_close() called but not finished. */ - UV_CLOSED = 0x02, /* close(2) finished. */ + UV_CLOSING = 0x01, /* uv_close() called but not finished. */ + UV_CLOSED = 0x02, /* close(2) finished. */ UV_STREAM_READING = 0x04, /* uv_read_start() called. */ UV_STREAM_SHUTTING = 0x08, /* uv_shutdown() called but not complete. */ UV_STREAM_SHUT = 0x10, /* Write side closed. */ UV_STREAM_READABLE = 0x20, /* The stream is readable */ UV_STREAM_WRITABLE = 0x40, /* The stream is writable */ - UV_TCP_NODELAY = 0x080, /* Disable Nagle. */ - UV_TCP_KEEPALIVE = 0x100, /* Turn on keep-alive. */ - UV_TIMER_ACTIVE = 0x080, - UV_TIMER_REPEAT = 0x100 + UV_TCP_NODELAY = 0x080, /* Disable Nagle. */ + UV_TCP_KEEPALIVE = 0x100, /* Turn on keep-alive. */ + UV_TIMER_REPEAT = 0x100, + UV__PENDING = 0x800 }; +inline static int uv__has_pending_handles(const uv_loop_t* loop) { + return loop->pending_handles != NULL; +} + +inline static void uv__make_pending(uv_handle_t* h) { + if (h->flags & UV__PENDING) return; + h->next_pending = h->loop->pending_handles; + h->loop->pending_handles = h; + h->flags |= UV__PENDING; +} +#define uv__make_pending(h) uv__make_pending((uv_handle_t*)(h)) + inline static void uv__req_init(uv_loop_t* loop, uv_req_t* req, uv_req_type type) { loop->counters.req_init++; req->type = type; +#ifndef UV_LEAN_AND_MEAN + ngx_queue_insert_tail(&loop->active_reqs, &req->active_queue); +#else + loop->active_reqs++; +#endif } #define uv__req_init(loop, req, type) \ uv__req_init((loop), (uv_req_t*)(req), (type)) @@ -112,10 +129,14 @@ int uv__nonblock(int fd, int set) __attribute__((unused)); int uv__cloexec(int fd, int set) __attribute__((unused)); int uv__socket(int domain, int type, int protocol); int uv__dup(int fd); +int uv_async_stop(uv_async_t* handle); /* loop */ int uv__loop_init(uv_loop_t* loop, int default_loop); void uv__loop_delete(uv_loop_t* loop); +void uv__run_idle(uv_loop_t* loop); +void uv__run_check(uv_loop_t* loop); +void uv__run_prepare(uv_loop_t* loop); /* error */ uv_err_code uv_translate_sys_error(int sys_errno); @@ -146,11 +167,6 @@ void uv__poll_close(uv_poll_t* handle); int uv__poll_active(const uv_poll_t* handle); /* various */ -int uv__check_active(const uv_check_t* handle); -int uv__idle_active(const uv_idle_t* handle); -int uv__prepare_active(const uv_prepare_t* handle); -int uv__timer_active(const uv_timer_t* handle); - void uv__async_close(uv_async_t* handle); void uv__check_close(uv_check_t* handle); void uv__fs_event_close(uv_fs_event_t* handle); @@ -163,6 +179,8 @@ void uv__timer_close(uv_timer_t* handle); void uv__udp_close(uv_udp_t* handle); void uv__udp_finish_close(uv_udp_t* handle); +void uv__stream_pending(uv_stream_t* handle); + #define UV__F_IPC (1 << 0) #define UV__F_NONBLOCK (1 << 1) int uv__make_socketpair(int fds[2], int flags); diff --git a/src/unix/kqueue.c b/src/unix/kqueue.c index 40463232..ee1bbd17 100644 --- a/src/unix/kqueue.c +++ b/src/unix/kqueue.c @@ -42,12 +42,10 @@ static void uv__fs_event_start(uv_fs_event_t* handle) { handle->fd, EV_LIBUV_KQUEUE_HACK); ev_io_start(handle->loop->ev, &handle->event_watcher); - ev_unref(handle->loop->ev); } static void uv__fs_event_stop(uv_fs_event_t* handle) { - ev_ref(handle->loop->ev); ev_io_stop(handle->loop->ev, &handle->event_watcher); } @@ -104,6 +102,7 @@ int uv_fs_event_init(uv_loop_t* loop, } uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + uv__handle_start(handle); /* FIXME shouldn't start automatically */ handle->filename = strdup(filename); handle->fflags = 0; handle->cb = cb; @@ -116,6 +115,7 @@ int uv_fs_event_init(uv_loop_t* loop, void uv__fs_event_close(uv_fs_event_t* handle) { uv__fs_event_stop(handle); + uv__handle_stop(handle); free(handle->filename); close(handle->fd); handle->fd = -1; diff --git a/src/unix/linux/inotify.c b/src/unix/linux/inotify.c index 24ddbcbc..564e47a5 100644 --- a/src/unix/linux/inotify.c +++ b/src/unix/linux/inotify.c @@ -90,7 +90,6 @@ static int init_inotify(uv_loop_t* loop) { loop->inotify_fd, EV_READ); ev_io_start(loop->ev, &loop->inotify_read_watcher); - ev_unref(loop->ev); return 0; } @@ -193,6 +192,7 @@ int uv_fs_event_init(uv_loop_t* loop, if (wd == -1) return uv__set_sys_error(loop, errno); uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + uv__handle_start(handle); /* FIXME shouldn't start automatically */ handle->filename = strdup(filename); handle->cb = cb; handle->fd = wd; @@ -209,4 +209,5 @@ void uv__fs_event_close(uv_fs_event_t* handle) { free(handle->filename); handle->filename = NULL; + uv__handle_stop(handle); } diff --git a/src/unix/loop.c b/src/unix/loop.c index b62b9205..aca2a889 100644 --- a/src/unix/loop.c +++ b/src/unix/loop.c @@ -33,13 +33,24 @@ int uv__loop_init(uv_loop_t* loop, int default_loop) { #else int flags = EVFLAG_AUTO; #endif + memset(loop, 0, sizeof(*loop)); + +#ifndef UV_LEAN_AND_MEAN + ngx_queue_init(&loop->active_handles); + ngx_queue_init(&loop->active_reqs); +#endif + RB_INIT(&loop->uv_ares_handles_); - loop->endgame_handles = NULL; + ngx_queue_init(&loop->idle_handles); + ngx_queue_init(&loop->check_handles); + ngx_queue_init(&loop->prepare_handles); + loop->pending_handles = NULL; loop->channel = NULL; loop->ev = (default_loop ? ev_default_loop : ev_loop_new)(flags); ev_set_userdata(loop->ev, loop); eio_channel_init(&loop->uv_eio_channel, loop); + #if __linux__ RB_INIT(&loop->inotify_watchers); loop->inotify_fd = -1; @@ -65,3 +76,40 @@ void uv__loop_delete(uv_loop_t* loop) { close(loop->fs_fd); #endif } + + +#define X(name, type) \ + int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \ + uv__handle_init(loop, (uv_handle_t*)handle, type); \ + loop->counters.name##_init++; \ + handle->name##_cb = NULL; \ + return 0; \ + } \ + int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \ + if (uv__is_active(handle)) return 0; \ + ngx_queue_insert_head(&handle->loop->name##_handles, &handle->queue); \ + handle->name##_cb = cb; \ + uv__handle_start(handle); \ + return 0; \ + } \ + int uv_##name##_stop(uv_##name##_t* handle) { \ + if (!uv__is_active(handle)) return 0; \ + ngx_queue_remove(&handle->queue); \ + uv__handle_stop(handle); \ + return 0; \ + } \ + void uv__run_##name(uv_loop_t* loop) { \ + uv_##name##_t* h; \ + ngx_queue_t* q; \ + ngx_queue_foreach(q, &loop->name##_handles) { \ + h = ngx_queue_data(q, uv_##name##_t, queue); \ + if (h->name##_cb) h->name##_cb(h, 0); \ + } \ + } \ + void uv__##name##_close(uv_##name##_t* handle) { \ + uv_##name##_stop(handle); \ + } +X(idle, UV_IDLE) +X(check, UV_CHECK) +X(prepare, UV_PREPARE) +#undef X diff --git a/src/unix/pipe.c b/src/unix/pipe.c index a5a626e3..91afb081 100644 --- a/src/unix/pipe.c +++ b/src/unix/pipe.c @@ -33,6 +33,8 @@ int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) { uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE); loop->counters.pipe_init++; + handle->shutdown_req = NULL; + handle->connect_req = NULL; handle->pipe_fname = NULL; handle->ipc = ipc; return 0; @@ -209,23 +211,21 @@ void uv_pipe_connect(uv_connect_t* req, uv__stream_open((uv_stream_t*)handle, sockfd, UV_STREAM_READABLE | UV_STREAM_WRITABLE); - ev_io_start(handle->loop->ev, &handle->read_watcher); ev_io_start(handle->loop->ev, &handle->write_watcher); - status = 0; out: handle->delayed_error = status; /* Passed to callback. */ handle->connect_req = req; + + uv__req_init(handle->loop, req, UV_CONNECT); req->handle = (uv_stream_t*)handle; - req->type = UV_CONNECT; req->cb = cb; ngx_queue_init(&req->queue); /* Run callback on next tick. */ - ev_feed_event(handle->loop->ev, &handle->read_watcher, EV_CUSTOM); - assert(ev_is_pending(&handle->read_watcher)); + uv__make_pending(handle); /* Mimic the Windows pipe implementation, always * return 0 and let the callback handle errors. diff --git a/src/unix/poll.c b/src/unix/poll.c index 74a2cb51..2c921278 100644 --- a/src/unix/poll.c +++ b/src/unix/poll.c @@ -34,7 +34,7 @@ static void uv__poll_io(EV_P_ ev_io* watcher, int ev_events) { if (ev_events & EV_ERROR) { /* An error happened. Libev has implicitly stopped the watcher, but we */ /* need to fix the refcount. */ - uv_ref(handle->loop); + uv__handle_stop(handle); uv__set_sys_error(handle->loop, EBADF); handle->poll_cb(handle, -1, 0); return; @@ -74,10 +74,8 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, static void uv__poll_stop(uv_poll_t* handle) { - if (ev_is_active(&handle->io_watcher)) { - ev_io_stop(handle->loop->ev, &handle->io_watcher); - uv_ref(handle->loop); - } + ev_io_stop(handle->loop->ev, &handle->io_watcher); + uv__handle_stop(handle); } @@ -111,10 +109,8 @@ int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb poll_cb) { ev_io_set(&handle->io_watcher, handle->fd, ev_events); ev_io_start(handle->loop->ev, &handle->io_watcher); - if (!was_active) - uv_unref(handle->loop); - handle->poll_cb = poll_cb; + uv__handle_start(handle); return 0; } diff --git a/src/unix/prepare.c b/src/unix/prepare.c deleted file mode 100644 index 6c18fbd7..00000000 --- a/src/unix/prepare.c +++ /dev/null @@ -1,79 +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" - - -static void uv__prepare(EV_P_ ev_prepare* w, int revents) { - uv_prepare_t* prepare = container_of(w, uv_prepare_t, prepare_watcher); - - if (prepare->prepare_cb) { - prepare->prepare_cb(prepare, 0); - } -} - - -int uv_prepare_init(uv_loop_t* loop, uv_prepare_t* prepare) { - uv__handle_init(loop, (uv_handle_t*)prepare, UV_PREPARE); - loop->counters.prepare_init++; - - ev_prepare_init(&prepare->prepare_watcher, uv__prepare); - prepare->prepare_cb = NULL; - - return 0; -} - - -int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb) { - int was_active = ev_is_active(&prepare->prepare_watcher); - - prepare->prepare_cb = cb; - - ev_prepare_start(prepare->loop->ev, &prepare->prepare_watcher); - - if (!was_active) { - ev_unref(prepare->loop->ev); - } - - return 0; -} - - -int uv_prepare_stop(uv_prepare_t* prepare) { - int was_active = ev_is_active(&prepare->prepare_watcher); - - ev_prepare_stop(prepare->loop->ev, &prepare->prepare_watcher); - - if (was_active) { - ev_ref(prepare->loop->ev); - } - return 0; -} - - -int uv__prepare_active(const uv_prepare_t* handle) { - return ev_is_active(&handle->prepare_watcher); -} - - -void uv__prepare_close(uv_prepare_t* handle) { - uv_prepare_stop(handle); -} diff --git a/src/unix/process.c b/src/unix/process.c index 64dc136d..bccaf171 100644 --- a/src/unix/process.c +++ b/src/unix/process.c @@ -181,6 +181,7 @@ int uv_spawn(uv_loop_t* loop, uv_process_t* process, uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS); loop->counters.process_init++; + uv__handle_start(process); process->exit_cb = options.exit_cb; @@ -384,4 +385,5 @@ uv_err_t uv_kill(int pid, int signum) { void uv__process_close(uv_process_t* handle) { ev_child_stop(handle->loop->ev, &handle->child_watcher); + uv__handle_stop(handle); } diff --git a/src/unix/stream.c b/src/unix/stream.c index 4de6a52b..e5cd133d 100644 --- a/src/unix/stream.c +++ b/src/unix/stream.c @@ -123,6 +123,7 @@ int uv__stream_open(uv_stream_t* stream, int fd, int flags) { void uv__stream_destroy(uv_stream_t* stream) { + uv_shutdown_t* shutdown_req; uv_write_t* req; ngx_queue_t* q; @@ -133,6 +134,8 @@ void uv__stream_destroy(uv_stream_t* stream) { ngx_queue_remove(q); req = ngx_queue_data(q, uv_write_t, queue); + uv__req_unregister(stream->loop, req); + if (req->bufs != req->bufsml) free(req->bufs); @@ -147,18 +150,27 @@ void uv__stream_destroy(uv_stream_t* stream) { ngx_queue_remove(q); req = ngx_queue_data(q, uv_write_t, queue); + uv__req_unregister(stream->loop, req); + if (req->cb) { uv__set_sys_error(stream->loop, req->error); req->cb(req, req->error ? -1 : 0); } } - if (stream->flags & UV_STREAM_SHUTTING) { - uv_shutdown_t* req = stream->shutdown_req; - if (req && req->cb) { - uv__set_artificial_error(stream->loop, UV_EINTR); - req->cb(req, -1); - } + if (!(stream->flags & UV_STREAM_SHUTTING)) + return; + + if (!stream->shutdown_req) + return; + + shutdown_req = stream->shutdown_req; + stream->shutdown_req = NULL; + uv__req_unregister(stream->loop, shutdown_req); + + if (shutdown_req->cb) { + uv__set_artificial_error(stream->loop, UV_EINTR); + shutdown_req->cb(shutdown_req, -1); } } @@ -252,15 +264,26 @@ out: int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) { + int r; + switch (stream->type) { case UV_TCP: - return uv_tcp_listen((uv_tcp_t*)stream, backlog, cb); + r = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb); + break; + case UV_NAMED_PIPE: - return uv_pipe_listen((uv_pipe_t*)stream, backlog, cb); + r = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb); + break; + default: assert(0); return -1; } + + if (r == 0) + uv__handle_start(stream); + + return r; } @@ -300,6 +323,7 @@ static void uv__drain(uv_stream_t* stream) { req = stream->shutdown_req; stream->shutdown_req = NULL; + uv__req_unregister(stream->loop, req); if (shutdown(stream->fd, SHUT_WR)) { /* Error. Report it. User should call uv_close(). */ @@ -499,24 +523,21 @@ start: static void uv__write_callbacks(uv_stream_t* stream) { - int callbacks_made = 0; - ngx_queue_t* q; uv_write_t* req; + ngx_queue_t* q; while (!ngx_queue_empty(&stream->write_completed_queue)) { /* Pop a req off write_completed_queue. */ q = ngx_queue_head(&stream->write_completed_queue); - assert(q); - req = ngx_queue_data(q, struct uv_write_s, queue); + req = ngx_queue_data(q, uv_write_t, queue); ngx_queue_remove(q); + uv__req_unregister(stream->loop, req); /* NOTE: call callback AFTER freeing the request data. */ if (req->cb) { uv__set_sys_error(stream->loop, req->error); req->cb(req, req->error ? -1 : 0); } - - callbacks_made++; } assert(ngx_queue_empty(&stream->write_completed_queue)); @@ -628,6 +649,8 @@ static void uv__read(uv_stream_t* stream) { /* EOF */ uv__set_artificial_error(stream->loop, UV_EOF); ev_io_stop(ev, &stream->read_watcher); + if (!ev_is_active(&stream->write_watcher)) + uv__handle_stop(stream); if (stream->read_cb) { stream->read_cb(stream, -1, buf); @@ -704,9 +727,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { req->handle = stream; req->cb = cb; stream->shutdown_req = req; - - ((uv_handle_t*)stream)->flags |= UV_STREAM_SHUTTING; - + stream->flags |= UV_STREAM_SHUTTING; ev_io_start(stream->loop->ev, &stream->write_watcher); @@ -714,6 +735,11 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) { } +void uv__stream_pending(uv_stream_t* handle) { + uv__stream_io(handle->loop->ev, &handle->write_watcher, EV_WRITE); +} + + void uv__stream_io(EV_P_ ev_io* watcher, int revents) { uv_stream_t* stream = watcher->data; @@ -767,26 +793,18 @@ static void uv__stream_connect(uv_stream_t* stream) { getsockopt(stream->fd, SOL_SOCKET, SO_ERROR, &error, &errorsize); } - if (!error) { + if (error == EINPROGRESS) + return; + + if (error == 0) ev_io_start(stream->loop->ev, &stream->read_watcher); - /* Successful connection */ - stream->connect_req = NULL; - if (req->cb) { - req->cb(req, 0); - } + stream->connect_req = NULL; + uv__req_unregister(stream->loop, req); - } else if (error == EINPROGRESS) { - /* Still connecting. */ - return; - } else { - /* Error */ + if (req->cb) { uv__set_sys_error(stream->loop, error); - - stream->connect_req = NULL; - if (req->cb) { - req->cb(req, -1); - } + req->cb(req, error ? -1 : 0); } } @@ -855,9 +873,8 @@ int uv__connect(uv_connect_t* req, uv_stream_t* stream, struct sockaddr* addr, assert(stream->write_watcher.data == stream); ev_io_start(stream->loop->ev, &stream->write_watcher); - if (stream->delayed_error) { - ev_feed_event(stream->loop->ev, &stream->write_watcher, EV_WRITE); - } + if (stream->delayed_error) + uv__make_pending(stream); return 0; } @@ -961,7 +978,7 @@ int uv__read_start_common(uv_stream_t* stream, uv_alloc_cb alloc_cb, /* The UV_STREAM_READING flag is irrelevant of the state of the tcp - it just * expresses the desired state of the user. */ - ((uv_handle_t*)stream)->flags |= UV_STREAM_READING; + stream->flags |= UV_STREAM_READING; /* TODO: try to do the read inline? */ /* TODO: keep track of tcp state. If we've gotten a EOF then we should @@ -978,6 +995,8 @@ int uv__read_start_common(uv_stream_t* stream, uv_alloc_cb alloc_cb, assert(stream->read_watcher.cb == uv__stream_io); ev_io_start(stream->loop->ev, &stream->read_watcher); + uv__handle_start(stream); + return 0; } @@ -996,6 +1015,7 @@ int uv_read2_start(uv_stream_t* stream, uv_alloc_cb alloc_cb, int uv_read_stop(uv_stream_t* stream) { ev_io_stop(stream->loop->ev, &stream->read_watcher); + uv__handle_stop(stream); stream->flags &= ~UV_STREAM_READING; stream->read_cb = NULL; stream->read2_cb = NULL; diff --git a/src/unix/sunos.c b/src/unix/sunos.c index 176f418b..f341297b 100644 --- a/src/unix/sunos.c +++ b/src/unix/sunos.c @@ -180,15 +180,16 @@ int uv_fs_event_init(uv_loop_t* loop, /* We don't support any flags yet. */ assert(!flags); if (loop->fs_fd == -1) { - if ((portfd = port_create()) == -1) { - uv__set_sys_error(loop, errno); - return -1; - } + if ((portfd = port_create()) == -1) { + uv__set_sys_error(loop, errno); + return -1; + } loop->fs_fd = portfd; first_run = 1; } uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT); + uv__handle_start(handle); /* FIXME shouldn't start automatically */ handle->filename = strdup(filename); handle->fd = PORT_UNUSED; handle->cb = cb; @@ -200,7 +201,6 @@ int uv_fs_event_init(uv_loop_t* loop, if (first_run) { ev_io_init(&loop->fs_event_watcher, uv__fs_event_read, portfd, EV_READ); ev_io_start(loop->ev, &loop->fs_event_watcher); - ev_unref(loop->ev); } return 0; diff --git a/src/unix/timer.c b/src/unix/timer.c index 6a002294..8463088a 100644 --- a/src/unix/timer.c +++ b/src/unix/timer.c @@ -31,16 +31,14 @@ static int uv__timer_repeating(const uv_timer_t* timer) { static void uv__timer_cb(EV_P_ ev_timer* w, int revents) { uv_timer_t* timer = container_of(w, uv_timer_t, timer_watcher); - assert(uv__timer_active(timer)); + if (!uv__is_active(timer)) + return; - if (!uv__timer_repeating(timer)) { - timer->flags &= ~UV_TIMER_ACTIVE; - ev_ref(EV_A); - } + if (!uv__timer_repeating(timer)) + uv__handle_stop(timer); - if (timer->timer_cb) { + if (timer->timer_cb) timer->timer_cb(timer, 0); - } } @@ -56,12 +54,11 @@ int uv_timer_init(uv_loop_t* loop, uv_timer_t* timer) { int uv_timer_start(uv_timer_t* timer, uv_timer_cb cb, int64_t timeout, int64_t repeat) { - if (uv__timer_active(timer)) { + if (uv__is_active(timer)) { return -1; } timer->timer_cb = cb; - timer->flags |= UV_TIMER_ACTIVE; if (repeat) timer->flags |= UV_TIMER_REPEAT; @@ -70,26 +67,22 @@ int uv_timer_start(uv_timer_t* timer, uv_timer_cb cb, int64_t timeout, ev_timer_set(&timer->timer_watcher, timeout / 1000.0, repeat / 1000.0); ev_timer_start(timer->loop->ev, &timer->timer_watcher); - ev_unref(timer->loop->ev); + uv__handle_start(timer); return 0; } int uv_timer_stop(uv_timer_t* timer) { - if (uv__timer_active(timer)) { - ev_ref(timer->loop->ev); - } - - timer->flags &= ~(UV_TIMER_ACTIVE | UV_TIMER_REPEAT); + timer->flags &= ~UV_TIMER_REPEAT; ev_timer_stop(timer->loop->ev, &timer->timer_watcher); - + uv__handle_stop(timer); return 0; } int uv_timer_again(uv_timer_t* timer) { - if (!uv__timer_active(timer)) { + if (!uv__is_active(timer)) { uv__set_artificial_error(timer->loop, UV_EINVAL); return -1; } @@ -117,11 +110,6 @@ int64_t uv_timer_get_repeat(uv_timer_t* timer) { } -int uv__timer_active(const uv_timer_t* timer) { - return timer->flags & UV_TIMER_ACTIVE; -} - - void uv__timer_close(uv_timer_t* handle) { uv_timer_stop(handle); } diff --git a/src/unix/udp.c b/src/unix/udp.c index 105bdc04..c67dcc2c 100644 --- a/src/unix/udp.c +++ b/src/unix/udp.c @@ -46,16 +46,20 @@ static void uv__udp_start_watcher(uv_udp_t* handle, ev_set_cb(w, cb); ev_io_set(w, handle->fd, flags); ev_io_start(handle->loop->ev, w); - ev_unref(handle->loop->ev); + uv__handle_start(handle); } static void uv__udp_stop_watcher(uv_udp_t* handle, ev_io* w) { if (!ev_is_active(w)) return; - ev_ref(handle->loop->ev); ev_io_stop(handle->loop->ev, w); ev_io_set(w, -1, 0); ev_set_cb(w, NULL); + + if (!ev_is_active(&handle->read_watcher) && + !ev_is_active(&handle->write_watcher)) { + uv__handle_stop(handle); + } } @@ -108,6 +112,8 @@ void uv__udp_finish_close(uv_udp_t* handle) { ngx_queue_remove(q); req = ngx_queue_data(q, uv_udp_send_t, queue); + uv__req_unregister(handle->loop, req); + if (req->send_cb) { /* FIXME proper error code like UV_EABORTED */ uv__set_artificial_error(handle->loop, UV_EINTR); @@ -185,12 +191,10 @@ static void uv__udp_run_completed(uv_udp_t* handle) { while (!ngx_queue_empty(&handle->write_completed_queue)) { q = ngx_queue_head(&handle->write_completed_queue); - assert(q != NULL); - ngx_queue_remove(q); req = ngx_queue_data(q, uv_udp_send_t, queue); - assert(req != NULL); + uv__req_unregister(handle->loop, req); if (req->bufs != req->bufsml) free(req->bufs); diff --git a/src/unix/uv-eio.c b/src/unix/uv-eio.c index 517d1191..f9c0f75d 100644 --- a/src/unix/uv-eio.c +++ b/src/unix/uv-eio.c @@ -27,47 +27,31 @@ #include +static uv_once_t uv__eio_init_once_guard = UV_ONCE_INIT; + + static void uv_eio_do_poll(uv_idle_t* watcher, int status) { - assert(watcher == &(watcher->loop->uv_eio_poller)); - - /* printf("uv_eio_poller\n"); */ - - if (eio_poll(&watcher->loop->uv_eio_channel) != -1 && uv_is_active((uv_handle_t*) watcher)) { - /* printf("uv_eio_poller stop\n"); */ + uv_loop_t* loop = watcher->loop; + assert(watcher == &loop->uv_eio_poller); + if (eio_poll(&loop->uv_eio_channel) != -1) uv_idle_stop(watcher); - uv_unref(watcher->loop); - } } /* Called from the main thread. */ static void uv_eio_want_poll_notifier_cb(uv_async_t* watcher, int status) { uv_loop_t* loop = watcher->loop; - assert(watcher == &loop->uv_eio_want_poll_notifier); - - /* printf("want poll notifier\n"); */ - - if (eio_poll(&watcher->loop->uv_eio_channel) == -1 && !uv_is_active((uv_handle_t*) &loop->uv_eio_poller)) { - /* printf("uv_eio_poller start\n"); */ + if (eio_poll(&loop->uv_eio_channel) == -1) uv_idle_start(&loop->uv_eio_poller, uv_eio_do_poll); - uv_ref(loop); - } } static void uv_eio_done_poll_notifier_cb(uv_async_t* watcher, int revents) { uv_loop_t* loop = watcher->loop; - assert(watcher == &loop->uv_eio_done_poll_notifier); - - /* printf("done poll notifier\n"); */ - - if (eio_poll(&watcher->loop->uv_eio_channel) != -1 && uv_is_active((uv_handle_t*) &loop->uv_eio_poller)) { - /* printf("uv_eio_poller stop\n"); */ + if (eio_poll(&loop->uv_eio_channel) != -1) uv_idle_stop(&loop->uv_eio_poller); - uv_unref(loop); - } } @@ -100,25 +84,20 @@ static void uv__eio_init(void) { eio_init(uv_eio_want_poll, uv_eio_done_poll); } -static uv_once_t uv__eio_init_once_guard = UV_ONCE_INIT; - void uv_eio_init(uv_loop_t* loop) { - if (loop->counters.eio_init == 0) { - loop->counters.eio_init++; + if (loop->counters.eio_init) return; + loop->counters.eio_init = 1; - uv_idle_init(loop, &loop->uv_eio_poller); - uv_idle_start(&loop->uv_eio_poller, uv_eio_do_poll); + uv_idle_init(loop, &loop->uv_eio_poller); + uv_idle_start(&loop->uv_eio_poller, uv_eio_do_poll); - loop->uv_eio_want_poll_notifier.data = loop; - uv_async_init(loop, &loop->uv_eio_want_poll_notifier, - uv_eio_want_poll_notifier_cb); - uv_unref(loop); + loop->uv_eio_want_poll_notifier.data = loop; + uv_async_init(loop, &loop->uv_eio_want_poll_notifier, + uv_eio_want_poll_notifier_cb); - uv_async_init(loop, &loop->uv_eio_done_poll_notifier, - uv_eio_done_poll_notifier_cb); - uv_unref(loop); + uv_async_init(loop, &loop->uv_eio_done_poll_notifier, + uv_eio_done_poll_notifier_cb); - uv_once(&uv__eio_init_once_guard, uv__eio_init); - } + uv_once(&uv__eio_init_once_guard, uv__eio_init); } diff --git a/src/uv-common.c b/src/uv-common.c index c8192bd7..08aaebf3 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -352,3 +352,13 @@ int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { return 0; } + + +void uv_ref(uv_handle_t* handle) { + uv__handle_ref(handle); +} + + +void uv_unref(uv_handle_t* handle) { + uv__handle_unref(handle); +} diff --git a/src/uv-common.h b/src/uv-common.h index e82f5842..efc07601 100644 --- a/src/uv-common.h +++ b/src/uv-common.h @@ -27,11 +27,30 @@ #ifndef UV_COMMON_H_ #define UV_COMMON_H_ +#include + #include "uv.h" #include "tree.h" + #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +#ifdef _MSC_VER +# define UNUSED /* empty */ +#else +# define UNUSED __attribute__((unused)) +#endif + + +#ifndef _WIN32 +enum { + UV__ACTIVE = 0x4000, + UV__REF = 0x8000 +}; +#else +# define UV__REF 0x00000020 +# define UV__ACTIVE 0x00000040 +#endif struct uv_ares_task_s { UV_HANDLE_FIELDS @@ -83,5 +102,105 @@ int uv__tcp_connect6(uv_connect_t* req, struct sockaddr_in6 address, uv_connect_cb cb); +#ifndef UV_LEAN_AND_MEAN + +UNUSED static int uv__has_active_handles(const uv_loop_t* loop) { + return !ngx_queue_empty(&loop->active_handles); +} + +UNUSED static int uv__has_active_reqs(const uv_loop_t* loop) { + return !ngx_queue_empty(&loop->active_reqs); +} + +UNUSED static void uv__active_handle_add(uv_handle_t* h) { + ngx_queue_insert_tail(&h->loop->active_handles, &h->active_queue); +} + +UNUSED static void uv__active_handle_rm(uv_handle_t* h) { + assert(uv__has_active_handles(h->loop)); + ngx_queue_remove(&h->active_queue); +} + +UNUSED static void uv__req_register(uv_loop_t* loop, uv_req_t* req) { + ngx_queue_insert_tail(&loop->active_reqs, &req->active_queue); +} + +UNUSED static void uv__req_unregister(uv_loop_t* loop, uv_req_t* req) { + assert(uv__has_active_reqs(loop)); + ngx_queue_remove(&req->active_queue); +} + +#else /* UV_LEAN_AND_MEAN */ + +UNUSED static int uv__has_active_handles(const uv_loop_t* loop) { + return loop->active_handles > 0; +} + +UNUSED static int uv__has_active_reqs(const uv_loop_t* loop) { + return loop->active_reqs > 0; +} + +UNUSED static void uv__active_handle_add(uv_handle_t* h) { + h->loop->active_handles++; +} + +UNUSED static void uv__active_handle_rm(uv_handle_t* h) { + assert(h->loop->active_handles > 0); + h->loop->active_handles--; +} + +UNUSED static void uv__req_register(uv_loop_t* loop, uv_req_t* req) { + loop->active_reqs++; + (void) req; +} + +UNUSED static void uv__req_unregister(uv_loop_t* loop, uv_req_t* req) { + assert(loop->active_reqs > 0); + loop->active_reqs--; + (void) req; +} + +#endif /* UV_LEAN_AND_MEAN */ + +#define uv__active_handle_add(h) uv__active_handle_add((uv_handle_t*)(h)) +#define uv__active_handle_rm(h) uv__active_handle_rm((uv_handle_t*)(h)) + +#define uv__req_register(loop, req) uv__req_register((loop), (uv_req_t*)(req)) +#define uv__req_unregister(loop, req) uv__req_unregister((loop), (uv_req_t*)(req)) + +UNUSED static int uv__is_active(const uv_handle_t* h) { + return !!(h->flags & UV__ACTIVE); +} +#define uv__is_active(h) uv__is_active((const uv_handle_t*)(h)) + +UNUSED static void uv__handle_start(uv_handle_t* h) { + if (h->flags & UV__ACTIVE) return; + if (!(h->flags & UV__REF)) return; + h->flags |= UV__ACTIVE; + uv__active_handle_add(h); +} +#define uv__handle_start(h) uv__handle_start((uv_handle_t*)(h)) + +UNUSED static void uv__handle_stop(uv_handle_t* h) { + if (!(h->flags & UV__ACTIVE)) return; + if (!(h->flags & UV__REF)) return; + uv__active_handle_rm(h); + h->flags &= ~UV__ACTIVE; +} +#define uv__handle_stop(h) uv__handle_stop((uv_handle_t*)(h)) + +UNUSED static void uv__handle_ref(uv_handle_t* h) { + if (h->flags & UV__REF) return; + if (h->flags & UV__ACTIVE) uv__active_handle_add(h); + h->flags |= UV__REF; +} +#define uv__handle_ref(h) uv__handle_ref((uv_handle_t*)(h)) + +UNUSED static void uv__handle_unref(uv_handle_t* h) { + if (!(h->flags & UV__REF)) return; + if (h->flags & UV__ACTIVE) uv__active_handle_rm(h); + h->flags &= ~UV__REF; +} +#define uv__handle_unref(h) uv__handle_unref((uv_handle_t*)(h)) #endif /* UV_COMMON_H_ */ diff --git a/src/win/async.c b/src/win/async.c index b68a8680..9df75e08 100644 --- a/src/win/async.c +++ b/src/win/async.c @@ -59,12 +59,11 @@ void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) { !handle->async_sent) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } - - uv_unref(loop); } } @@ -72,12 +71,8 @@ void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) { int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { uv_req_t* req; - loop->counters.handle_init++; - loop->counters.async_init++; - + uv_handle_init(loop, (uv_handle_t*) handle); handle->type = UV_ASYNC; - handle->loop = loop; - handle->flags = 0; handle->async_sent = 0; handle->async_cb = async_cb; @@ -86,12 +81,23 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { req->type = UV_WAKEUP; req->data = handle; - uv_ref(loop); + loop->counters.async_init++; + + uv__handle_start(handle); return 0; } +void uv_async_close(uv_loop_t* loop, uv_async_t* handle) { + if (!((uv_async_t*)handle)->async_sent) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } + + uv__handle_start(handle); +} + + int uv_async_send(uv_async_t* handle) { uv_loop_t* loop = handle->loop; diff --git a/src/win/cares.c b/src/win/cares.c index d86cb325..359bc213 100644 --- a/src/win/cares.c +++ b/src/win/cares.c @@ -22,7 +22,6 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -132,6 +131,7 @@ static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read, } /* 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; @@ -178,7 +178,7 @@ static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read, /* add handle to list */ uv_add_ares_handle(loop, uv_handle_ares); - uv_ref(loop); + uv__handle_start(uv_handle_ares); /* * we have a single polling timer for all ares sockets. @@ -229,7 +229,7 @@ void uv_process_ares_cleanup_req(uv_loop_t* loop, uv_ares_task_t* handle, unsigned int signaled = WaitForSingleObject(handle->h_close_event, 0); if (signaled != WAIT_TIMEOUT) { - uv_unref(loop); + uv__handle_stop(loop); /* close event handle and free uv handle memory */ CloseHandle(handle->h_close_event); diff --git a/src/win/core.c b/src/win/core.c index e698d75c..27f3438b 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -27,7 +27,6 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -65,10 +64,16 @@ static void uv_loop_init(uv_loop_t* loop) { uv_fatal_error(GetLastError(), "CreateIoCompletionPort"); } - loop->refs = 0; - uv_update_time(loop); +#ifndef UV_LEAN_AND_MEAN + ngx_queue_init(&loop->active_handles); + ngx_queue_init(&loop->active_reqs); +#else + loop->active_handles = 0; + loop->active_reqs = 0; +#endif + loop->pending_reqs_tail = NULL; loop->endgame_handles = NULL; @@ -145,21 +150,6 @@ void uv_loop_delete(uv_loop_t* loop) { } -int uv_loop_refcount(const uv_loop_t* loop) { - return loop->refs; -} - - -void uv_ref(uv_loop_t* loop) { - loop->refs++; -} - - -void uv_unref(uv_loop_t* loop) { - loop->refs--; -} - - static void uv_poll(uv_loop_t* loop, int block) { BOOL success; DWORD bytes, timeout; @@ -226,6 +216,19 @@ static void uv_poll_ex(uv_loop_t* loop, int block) { } } +#ifndef UV_LEAN_AND_MEAN +# define UV_LOOP_ALIVE(loop) \ + (!ngx_queue_empty(&(loop)->active_handles) || \ + !ngx_queue_empty(&(loop)->active_reqs) || \ + (loop)->endgame_handles != NULL) +#else +# define UV_LOOP_ALIVE(loop) \ + ((loop)->active_handles > 0 && \ + (loop)->active_reqs > 0 && \ + (loop)->endgame_handles != NULL) +#endif + + #define UV_LOOP_ONCE(loop, poll) \ do { \ uv_update_time((loop)); \ @@ -240,7 +243,7 @@ static void uv_poll_ex(uv_loop_t* loop, int block) { uv_process_reqs((loop)); \ uv_process_endgames((loop)); \ \ - if ((loop)->refs <= 0) { \ + if (!UV_LOOP_ALIVE((loop))) { \ break; \ } \ \ @@ -249,13 +252,13 @@ static void uv_poll_ex(uv_loop_t* loop, int block) { poll((loop), (loop)->idle_handles == NULL && \ (loop)->pending_reqs_tail == NULL && \ (loop)->endgame_handles == NULL && \ - (loop)->refs > 0); \ + UV_LOOP_ALIVE((loop))); \ \ uv_check_invoke((loop)); \ } while (0); #define UV_LOOP(loop, poll) \ - while ((loop)->refs > 0) { \ + while (UV_LOOP_ALIVE((loop))) { \ UV_LOOP_ONCE(loop, poll) \ } @@ -277,6 +280,6 @@ int uv_run(uv_loop_t* loop) { UV_LOOP(loop, uv_poll); } - assert(loop->refs == 0); + assert(!UV_LOOP_ALIVE((loop))); return 0; } diff --git a/src/win/error.c b/src/win/error.c index 29404126..bdbb3b29 100644 --- a/src/win/error.c +++ b/src/win/error.c @@ -26,7 +26,6 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" diff --git a/src/win/fs-event.c b/src/win/fs-event.c index 1003201f..61f9de23 100644 --- a/src/win/fs-event.c +++ b/src/win/fs-event.c @@ -19,13 +19,14 @@ * IN THE SOFTWARE. */ +#include "uv.h" +#include "internal.h" + #include #include #include #include #include -#include "uv.h" -#include "internal.h" const unsigned int uv_directory_watcher_buffer_size = 4096; @@ -33,9 +34,8 @@ const unsigned int uv_directory_watcher_buffer_size = 4096; static void uv_fs_event_init_handle(uv_loop_t* loop, uv_fs_event_t* handle, const char* filename, uv_fs_event_cb cb) { + uv_handle_init(loop, (uv_handle_t*) handle); handle->type = UV_FS_EVENT; - handle->loop = loop; - handle->flags = 0; handle->cb = cb; handle->dir_handle = INVALID_HANDLE_VALUE; handle->buffer = NULL; @@ -53,10 +53,9 @@ static void uv_fs_event_init_handle(uv_loop_t* loop, uv_fs_event_t* handle, uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } - loop->counters.handle_init++; - loop->counters.fs_event_init++; + uv__handle_start(handle); - uv_ref(loop); + loop->counters.fs_event_init++; } @@ -109,7 +108,7 @@ static int uv_split_path(const wchar_t* filename, wchar_t** dir, return -1; } } - + *file = wcsdup(filename); } else { if (dir) { @@ -152,7 +151,7 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle, uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } - if (!uv_utf8_to_utf16(filename, filenamew, + if (!uv_utf8_to_utf16(filename, filenamew, name_size / sizeof(wchar_t))) { uv__set_sys_error(loop, GetLastError()); return -1; @@ -172,11 +171,11 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle, handle->dirw = filenamew; dir_to_watch = filenamew; } else { - /* + /* * filename is a file. So we split filename into dir & file parts, and * watch the dir directory. */ - + /* Convert to short path. */ if (!GetShortPathNameW(filenamew, short_path, ARRAY_SIZE(short_path))) { last_error = GetLastError(); @@ -226,7 +225,7 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle, goto error; } - handle->buffer = (char*)_aligned_malloc(uv_directory_watcher_buffer_size, + handle->buffer = (char*)_aligned_malloc(uv_directory_watcher_buffer_size, sizeof(DWORD)); if (!handle->buffer) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); @@ -317,7 +316,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, assert(!filename); assert(!long_filenamew); - /* + /* * Fire the event only if we were asked to watch a directory, * or if the filename filter matches. */ @@ -328,8 +327,8 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, file_info->FileNameLength / sizeof(wchar_t)) == 0) { if (handle->dirw) { - /* - * We attempt to convert the file name to its long form for + /* + * We attempt to convert the file name to its long form for * events that still point to valid files on disk. * For removed and renamed events, we do not provide the file name. */ @@ -382,7 +381,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, } } - /* + /* * If we couldn't get the long name - just use the name * provided by ReadDirectoryChangesW. */ @@ -471,6 +470,8 @@ void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) { if (!handle->req_pending) { uv_want_endgame(loop, (uv_handle_t*)handle); } + + uv__handle_start(handle); } @@ -479,6 +480,7 @@ void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) { !handle->req_pending) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->buffer) { _aligned_free(handle->buffer); @@ -508,7 +510,5 @@ void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) { if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } - - uv_unref(loop); } } diff --git a/src/win/fs.c b/src/win/fs.c index 71f4fabc..dbef665f 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -59,7 +59,7 @@ return -1; \ } \ req->flags |= UV_FS_ASYNC_QUEUED; \ - uv_ref((loop)); + uv__req_register(loop, req); #define SET_UV_LAST_ERROR_FROM_REQ(req) \ uv__set_error(req->loop, req->errorno, req->sys_errno_); @@ -1519,6 +1519,7 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime, void uv_process_fs_req(uv_loop_t* loop, uv_fs_t* req) { assert(req->cb); + uv__req_unregister(loop, req); SET_UV_LAST_ERROR_FROM_REQ(req); req->cb(req); } @@ -1552,10 +1553,6 @@ void uv_fs_req_cleanup(uv_fs_t* req) { req->path = NULL; } - if (req->flags & UV_FS_ASYNC_QUEUED) { - uv_unref(loop); - } - req->flags |= UV_FS_CLEANEDUP; } diff --git a/src/win/getaddrinfo.c b/src/win/getaddrinfo.c index 5353c0b5..bdfe1bb9 100644 --- a/src/win/getaddrinfo.c +++ b/src/win/getaddrinfo.c @@ -77,23 +77,21 @@ static uv_err_code uv_translate_eai_error(int eai_errno) { /* getaddrinfo worker thread implementation */ static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) { - uv_getaddrinfo_t* handle = (uv_getaddrinfo_t*) parameter; - uv_loop_t* loop = handle->loop; + uv_getaddrinfo_t* req = (uv_getaddrinfo_t*) parameter; + uv_loop_t* loop = req->loop; int ret; - assert(handle != NULL); + assert(req != NULL); - if (handle != NULL) { - /* call OS function on this thread */ - ret = GetAddrInfoW(handle->node, - handle->service, - handle->hints, - &handle->res); - handle->retcode = ret; + /* call OS function on this thread */ + ret = GetAddrInfoW(req->node, + req->service, + req->hints, + &req->res); + req->retcode = ret; - /* post getaddrinfo completed */ - POST_COMPLETION_FOR_REQ(loop, &handle->getadddrinfo_req); - } + /* post getaddrinfo completed */ + POST_COMPLETION_FOR_REQ(loop, req); return 0; } @@ -108,8 +106,7 @@ static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) { * and copy all structs and referenced strings into the one block. * Each size calculation is adjusted to avoid unaligned pointers. */ -void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* handle, - uv_req_t* req) { +void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) { int addrinfo_len = 0; int name_len = 0; size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo)); @@ -120,15 +117,15 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* handle, int status = 0; /* release input parameter memory */ - if (handle->alloc != NULL) { - free(handle->alloc); - handle->alloc = NULL; + if (req->alloc != NULL) { + free(req->alloc); + req->alloc = NULL; } - if (handle->retcode == 0) { + if (req->retcode == 0) { /* convert addrinfoW to addrinfo */ /* first calculate required length */ - addrinfow_ptr = handle->res; + addrinfow_ptr = req->res; while (addrinfow_ptr != NULL) { addrinfo_len += addrinfo_struct_len + ALIGNED_SIZE(addrinfow_ptr->ai_addrlen); @@ -150,7 +147,7 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* handle, /* do conversions */ if (alloc_ptr != NULL) { cur_ptr = alloc_ptr; - addrinfow_ptr = handle->res; + addrinfow_ptr = req->res; while (addrinfow_ptr != NULL) { /* copy addrinfo struct data */ @@ -206,21 +203,21 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* handle, } } else { /* GetAddrInfo failed */ - uv__set_artificial_error(loop, uv_translate_eai_error(handle->retcode)); + uv__set_artificial_error(loop, uv_translate_eai_error(req->retcode)); status = -1; } /* return memory to system */ - if (handle->res != NULL) { - FreeAddrInfoW(handle->res); - handle->res = NULL; + if (req->res != NULL) { + FreeAddrInfoW(req->res); + req->res = NULL; } complete: - /* finally do callback with converted result */ - handle->getaddrinfo_cb(handle, status, (struct addrinfo*)alloc_ptr); + uv__req_unregister(loop, req); - uv_unref(loop); + /* finally do callback with converted result */ + req->getaddrinfo_cb(req, status, (struct addrinfo*)alloc_ptr); } @@ -237,7 +234,7 @@ void uv_freeaddrinfo(struct addrinfo* ai) { /* * Entry point for getaddrinfo * we convert the UTF-8 strings to UNICODE - * and save the UNICODE string pointers in the handle + * and save the UNICODE string pointers in the req * We also copy hints so that caller does not need to keep memory until the * callback. * return UV_OK if a callback will be made @@ -248,7 +245,7 @@ void uv_freeaddrinfo(struct addrinfo* ai) { * Each size calculation is adjusted to avoid unaligned pointers. */ int uv_getaddrinfo(uv_loop_t* loop, - uv_getaddrinfo_t* handle, + uv_getaddrinfo_t* req, uv_getaddrinfo_cb getaddrinfo_cb, const char* node, const char* service, @@ -258,18 +255,18 @@ int uv_getaddrinfo(uv_loop_t* loop, int hintssize = 0; char* alloc_ptr = NULL; - if (handle == NULL || getaddrinfo_cb == NULL || + if (req == NULL || getaddrinfo_cb == NULL || (node == NULL && service == NULL)) { uv__set_sys_error(loop, WSAEINVAL); goto error; } - uv_req_init(loop, (uv_req_t*)handle); + uv_req_init(loop, (uv_req_t*)req); - handle->getaddrinfo_cb = getaddrinfo_cb; - handle->res = NULL; - handle->type = UV_GETADDRINFO; - handle->loop = loop; + req->getaddrinfo_cb = getaddrinfo_cb; + req->res = NULL; + req->type = UV_GETADDRINFO; + req->loop = loop; /* calculate required memory size for all input values */ if (node != NULL) { @@ -300,12 +297,12 @@ int uv_getaddrinfo(uv_loop_t* loop, } /* save alloc_ptr now so we can free if error */ - handle->alloc = (void*)alloc_ptr; + req->alloc = (void*)alloc_ptr; /* convert node string to UTF16 into allocated memory and save pointer in */ - /* handle */ + /* the reques. */ if (node != NULL) { - handle->node = (wchar_t*)alloc_ptr; + req->node = (wchar_t*)alloc_ptr; if (uv_utf8_to_utf16(node, (wchar_t*) alloc_ptr, nodesize / sizeof(wchar_t)) == 0) { @@ -314,13 +311,13 @@ int uv_getaddrinfo(uv_loop_t* loop, } alloc_ptr += nodesize; } else { - handle->node = NULL; + req->node = NULL; } /* convert service string to UTF16 into allocated memory and save pointer */ - /* in handle */ + /* in the req. */ if (service != NULL) { - handle->service = (wchar_t*)alloc_ptr; + req->service = (wchar_t*)alloc_ptr; if (uv_utf8_to_utf16(service, (wchar_t*) alloc_ptr, servicesize / sizeof(wchar_t)) == 0) { @@ -329,44 +326,39 @@ int uv_getaddrinfo(uv_loop_t* loop, } alloc_ptr += servicesize; } else { - handle->service = NULL; + req->service = NULL; } - /* copy hints to allocated memory and save pointer in handle */ + /* copy hints to allocated memory and save pointer in req */ if (hints != NULL) { - handle->hints = (struct addrinfoW*)alloc_ptr; - handle->hints->ai_family = hints->ai_family; - handle->hints->ai_socktype = hints->ai_socktype; - handle->hints->ai_protocol = hints->ai_protocol; - handle->hints->ai_flags = hints->ai_flags; - handle->hints->ai_addrlen = 0; - handle->hints->ai_canonname = NULL; - handle->hints->ai_addr = NULL; - handle->hints->ai_next = NULL; + req->hints = (struct addrinfoW*)alloc_ptr; + req->hints->ai_family = hints->ai_family; + req->hints->ai_socktype = hints->ai_socktype; + req->hints->ai_protocol = hints->ai_protocol; + req->hints->ai_flags = hints->ai_flags; + req->hints->ai_addrlen = 0; + req->hints->ai_canonname = NULL; + req->hints->ai_addr = NULL; + req->hints->ai_next = NULL; } else { - handle->hints = NULL; + req->hints = NULL; } - /* init request for Post handling */ - uv_req_init(loop, &handle->getadddrinfo_req); - handle->getadddrinfo_req.data = handle; - handle->getadddrinfo_req.type = UV_GETADDRINFO_REQ; - /* Ask thread to run. Treat this as a long operation */ if (QueueUserWorkItem(&getaddrinfo_thread_proc, - handle, + req, WT_EXECUTELONGFUNCTION) == 0) { uv__set_sys_error(loop, GetLastError()); goto error; } - uv_ref(loop); + uv__req_register(loop, req); return 0; error: - if (handle != NULL && handle->alloc != NULL) { - free(handle->alloc); + if (req != NULL && req->alloc != NULL) { + free(req->alloc); } return -1; } diff --git a/src/win/handle.c b/src/win/handle.c index 39bd7dd5..b5011438 100644 --- a/src/win/handle.c +++ b/src/win/handle.c @@ -57,30 +57,23 @@ uv_handle_type uv_guess_handle(uv_file file) { int uv_is_active(const 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; + return (handle->flags & UV__ACTIVE) && !(handle->flags & UV_HANDLE_CLOSING); +} - case UV_POLL: - return ((uv_poll_t*) handle)->events != 0; - default: - return 1; - } +void uv_handle_init(uv_loop_t* loop, uv_handle_t* handle) { + handle->loop = loop; + handle->flags = UV__REF; + + loop->counters.handle_init++; } void uv_close(uv_handle_t* handle, uv_close_cb cb) { - uv_pipe_t* pipe; - uv_udp_t* udp; - uv_process_t* process; - uv_loop_t* loop = handle->loop; if (handle->flags & UV_HANDLE_CLOSING) { + assert(0); return; } @@ -90,16 +83,11 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) { /* Handle-specific close actions */ switch (handle->type) { case UV_TCP: - uv_tcp_close((uv_tcp_t*)handle); + uv_tcp_close(loop, (uv_tcp_t*)handle); return; case UV_NAMED_PIPE: - pipe = (uv_pipe_t*)handle; - pipe->flags &= ~(UV_HANDLE_READING | UV_HANDLE_LISTENING); - close_pipe(pipe, NULL, NULL); - if (pipe->reqs_pending == 0) { - uv_want_endgame(loop, handle); - } + uv_pipe_close(loop, (uv_pipe_t*) handle); return; case UV_TTY: @@ -107,51 +95,47 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) { return; case UV_UDP: - udp = (uv_udp_t*) handle; - uv_udp_recv_stop(udp); - closesocket(udp->socket); - if (udp->reqs_pending == 0) { - uv_want_endgame(loop, handle); - } + uv_udp_close(loop, (uv_udp_t*) handle); return; case UV_POLL: - uv_poll_close(handle->loop, (uv_poll_t*) handle); + uv_poll_close(loop, (uv_poll_t*) handle); return; case UV_TIMER: uv_timer_stop((uv_timer_t*)handle); + uv__handle_start(handle); uv_want_endgame(loop, handle); return; case UV_PREPARE: uv_prepare_stop((uv_prepare_t*)handle); + uv__handle_start(handle); uv_want_endgame(loop, handle); return; case UV_CHECK: uv_check_stop((uv_check_t*)handle); + uv__handle_start(handle); uv_want_endgame(loop, handle); return; case UV_IDLE: uv_idle_stop((uv_idle_t*)handle); + uv__handle_start(handle); uv_want_endgame(loop, handle); return; case UV_ASYNC: - if (!((uv_async_t*)handle)->async_sent) { - uv_want_endgame(loop, handle); - } + uv_async_close(loop, (uv_async_t*) handle); return; case UV_PROCESS: - process = (uv_process_t*)handle; - uv_process_close(loop, process); + uv_process_close(loop, (uv_process_t*) handle); return; case UV_FS_EVENT: - uv_fs_event_close(loop, (uv_fs_event_t*)handle); + uv_fs_event_close(loop, (uv_fs_event_t*) handle); return; default: @@ -179,7 +163,7 @@ void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) { void uv_process_endgames(uv_loop_t* loop) { uv_handle_t* handle; - while (loop->endgame_handles && loop->refs > 0) { + while (loop->endgame_handles) { handle = loop->endgame_handles; loop->endgame_handles = handle->endgame_next; diff --git a/src/win/internal.h b/src/win/internal.h index 0e647739..362e23f2 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -30,15 +30,6 @@ #include "winsock.h" -/* - * Timers - */ -void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle); - -DWORD uv_get_poll_timeout(uv_loop_t* loop); -void uv_process_timers(uv_loop_t* loop); - - /* * Handles */ @@ -47,10 +38,14 @@ void uv_process_timers(uv_loop_t* loop); #define UV_HANDLE_CLOSING 0x00000001 #define UV_HANDLE_CLOSED 0x00000002 #define UV_HANDLE_ENDGAME_QUEUED 0x00000004 -#define UV_HANDLE_UV_ALLOCED 0x00000008 #define UV_HANDLE_ACTIVE 0x00000010 -/* Used by streams. */ +/* Keep in sync with uv-common.h: */ +#define UV__REF 0x00000020 +#define UV__ACTIVE 0x00000040 +/* reserved: #define UV_HANDLE_INTERNAL 0x00000080 */ + +/* Used by streams and UDP handles. */ #define UV_HANDLE_READING 0x00000100 #define UV_HANDLE_BOUND 0x00000200 #define UV_HANDLE_BIND_ERROR 0x00000400 @@ -72,8 +67,7 @@ void uv_process_timers(uv_loop_t* loop); #define UV_HANDLE_TCP_SINGLE_ACCEPT 0x08000000 #define UV_HANDLE_TCP_ACCEPT_STATE_CHANGING 0x10000000 #define UV_HANDLE_TCP_SOCKET_CLOSED 0x20000000 -#define UV_HANDLE_SHARED_TCP_SERVER 0x40000000 -#define UV_HANDLE_SHARED_TCP_SOCKET 0x80000000 +#define UV_HANDLE_SHARED_TCP_SOCKET 0x40000000 /* Only used by uv_pipe_t handles. */ #define UV_HANDLE_NON_OVERLAPPED_PIPE 0x01000000 @@ -108,6 +102,41 @@ void uv_process_endgames(uv_loop_t* loop); #define UV_SUCCEEDED_WITH_IOCP(result) \ ((result) || (GetLastError() == ERROR_IO_PENDING)) +#define DECREASE_ACTIVE_COUNT(loop, handle) \ + do { \ + if (--(handle)->activecnt == 0 && \ + !((handle)->flags & UV_HANDLE_CLOSING)) { \ + uv__handle_stop((handle)); \ + } \ + assert((handle)->activecnt >= 0); \ + } while (0) + +#define INCREASE_ACTIVE_COUNT(loop, handle) \ + do { \ + if ((handle)->activecnt++ == 0) { \ + uv__handle_start((handle)); \ + } \ + assert((handle)->activecnt > 0); \ + } while (0) + +#define REGISTER_HANDLE_REQ(loop, handle, req) \ + do { \ + INCREASE_ACTIVE_COUNT((loop), (handle)); \ + uv__req_register((loop), (req)); \ + } while (0) + +#define UNREGISTER_HANDLE_REQ(loop, handle, req) \ + do { \ + DECREASE_ACTIVE_COUNT((loop), (handle)); \ + uv__req_unregister((loop), (req)); \ + } while (0) + + +/* + * Handles + */ +void uv_handle_init(uv_loop_t* loop, uv_handle_t* handle); + /* * Requests @@ -155,6 +184,7 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, uv_connect_t* req); +void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp); void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle); int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info, @@ -163,8 +193,6 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info, int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, LPWSAPROTOCOL_INFOW protocol_info); -void uv_tcp_close(uv_tcp_t* tcp); - /* * UDP @@ -173,6 +201,7 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req); void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, uv_udp_send_t* req); +void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle); void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle); @@ -181,8 +210,6 @@ void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle); */ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, char* name, size_t nameSize); -void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err); -void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle); int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client); @@ -206,6 +233,10 @@ void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, uv_shutdown_t* req); +void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle); +void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle); +void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle); + /* * TTY @@ -243,6 +274,15 @@ void uv_poll_close(uv_loop_t* loop, uv_poll_t* handle); void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle); +/* + * Timers + */ +void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle); + +DWORD uv_get_poll_timeout(uv_loop_t* loop); +void uv_process_timers(uv_loop_t* loop); + + /* * Loop watchers */ @@ -256,6 +296,7 @@ void uv_idle_invoke(uv_loop_t* loop); /* * Async watcher */ +void uv_async_close(uv_loop_t* loop, uv_async_t* handle); void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle); void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle, @@ -284,8 +325,7 @@ void uv_process_ares_cleanup_req(uv_loop_t* loop, uv_ares_task_t* handle, /* * Getaddrinfo */ -void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* handle, - uv_req_t* req); +void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req); /* diff --git a/src/win/loop-watcher.c b/src/win/loop-watcher.c index c597cd99..46d184ca 100644 --- a/src/win/loop-watcher.c +++ b/src/win/loop-watcher.c @@ -22,7 +22,6 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -30,25 +29,19 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { if (handle->flags & UV_HANDLE_CLOSING) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->close_cb) { handle->close_cb(handle); } - - uv_unref(loop); } } #define UV_LOOP_WATCHER_DEFINE(name, NAME) \ int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \ + uv_handle_init(loop, (uv_handle_t*) handle); \ handle->type = UV_##NAME; \ - handle->loop = loop; \ - handle->flags = 0; \ - \ - uv_ref(loop); \ - \ - loop->counters.handle_init++; \ loop->counters.name##_init++; \ \ return 0; \ @@ -77,6 +70,7 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { \ handle->name##_cb = cb; \ handle->flags |= UV_HANDLE_ACTIVE; \ + uv__handle_start(handle); \ \ return 0; \ } \ @@ -108,6 +102,7 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { } \ \ handle->flags &= ~UV_HANDLE_ACTIVE; \ + uv__handle_stop(handle); \ \ return 0; \ } \ diff --git a/src/win/pipe.c b/src/win/pipe.c index 35da85e6..2b48e38f 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -25,7 +25,6 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -280,7 +279,6 @@ static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) { void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { - unsigned int uv_alloced; DWORD result; uv_shutdown_t* req; NTSTATUS nt_status; @@ -296,12 +294,14 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { handle->shutdown_req = NULL; if (handle->flags & UV_HANDLE_CLOSING) { + UNREGISTER_HANDLE_REQ(loop, handle, req); + /* Already closing. Cancel the shutdown. */ if (req->cb) { uv__set_sys_error(loop, WSAEINTR); req->cb(req, -1); } - uv_unref(loop); + DECREASE_PENDING_REQ_COUNT(handle); return; } @@ -315,12 +315,14 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { if (nt_status != STATUS_SUCCESS) { /* Failure */ + UNREGISTER_HANDLE_REQ(loop, handle, req); + handle->flags &= ~UV_HANDLE_SHUTTING; if (req->cb) { uv__set_sys_error(loop, pRtlNtStatusToDosError(nt_status)); req->cb(req, -1); } - uv_unref(loop); + DECREASE_PENDING_REQ_COUNT(handle); return; } @@ -340,12 +342,14 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { } else { /* Failure. */ + UNREGISTER_HANDLE_REQ(loop, handle, req); + handle->flags &= ~UV_HANDLE_SHUTTING; if (req->cb) { uv__set_sys_error(loop, GetLastError()); req->cb(req, -1); } - uv_unref(loop); + DECREASE_PENDING_REQ_COUNT(handle); return; } @@ -355,6 +359,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { handle->reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->flags & UV_HANDLE_CONNECTION) { if (handle->pending_ipc_info.socket_info) { @@ -380,19 +385,9 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { handle->accept_reqs = NULL; } - /* Remember the state of this flag because the close callback is */ - /* allowed to clobber or free the handle's memory */ - uv_alloced = handle->flags & UV_HANDLE_UV_ALLOCED; - if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } - - if (uv_alloced) { - free(handle); - } - - uv_unref(loop); } } @@ -573,7 +568,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, goto error; } - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); handle->reqs_pending++; return; @@ -596,7 +591,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, SET_REQ_SUCCESS(req); uv_insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); return; error: @@ -613,14 +608,14 @@ error: SET_REQ_ERROR(req, errorno); uv_insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); return; } /* Cleans up uv_pipe_t (server or connection) and all resources associated */ /* with it. */ -void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err) { +void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) { int i; HANDLE pipeHandle; @@ -652,6 +647,27 @@ void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err) { } +void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) { + if (handle->flags & UV_HANDLE_READING) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + } + + if (handle->flags & UV_HANDLE_LISTENING) { + handle->flags &= ~UV_HANDLE_LISTENING; + DECREASE_ACTIVE_COUNT(loop, handle); + } + + uv_pipe_cleanup(loop, handle); + + if (handle->reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } + + uv__handle_start(handle); +} + + static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle, uv_pipe_accept_t* req, BOOL firstInstance) { assert(handle->flags & UV_HANDLE_LISTENING); @@ -717,7 +733,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { return -1; } - return uv_tcp_import((uv_tcp_t*)client, server->pending_ipc_info.socket_info, + return uv_tcp_import((uv_tcp_t*)client, server->pending_ipc_info.socket_info, server->pending_ipc_info.tcp_connection); } else { pipe_client = (uv_pipe_t*)client; @@ -753,17 +769,19 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { /* Starts listening for connections for the given pipe. */ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { uv_loop_t* loop = handle->loop; - int i; + if (handle->flags & UV_HANDLE_LISTENING) { + handle->connection_cb = cb; + } + if (!(handle->flags & UV_HANDLE_BOUND)) { uv__set_artificial_error(loop, UV_EINVAL); return -1; } - if (handle->flags & UV_HANDLE_LISTENING || - handle->flags & UV_HANDLE_READING) { - uv__set_artificial_error(loop, UV_EALREADY); + if (handle->flags & UV_HANDLE_READING) { + uv__set_artificial_error(loop, UV_EISCONN); return -1; } @@ -773,6 +791,7 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { } handle->flags |= UV_HANDLE_LISTENING; + INCREASE_ACTIVE_COUNT(loop, handle); handle->connection_cb = cb; /* First pipe handle should have already been created in uv_pipe_bind */ @@ -955,17 +974,13 @@ static int uv_pipe_read_start_impl(uv_pipe_t* handle, uv_alloc_cb alloc_cb, return -1; } - if (handle->flags & UV_HANDLE_READING) { - uv__set_artificial_error(loop, UV_EALREADY); - return -1; - } - if (handle->flags & UV_HANDLE_EOF) { uv__set_artificial_error(loop, UV_EOF); return -1; } handle->flags |= UV_HANDLE_READING; + INCREASE_ACTIVE_COUNT(loop, handle); handle->read_cb = read_cb; handle->read2_cb = read2_cb; handle->alloc_cb = alloc_cb; @@ -1154,10 +1169,10 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req, /* Request queued by the kernel. */ ipc_header_req->queued_bytes = ipc_frame.header.flags & UV_IPC_TCP_SERVER ? sizeof(ipc_frame) : sizeof(ipc_frame.header); - handle->write_queue_size += req->queued_bytes; + handle->write_queue_size += ipc_header_req->queued_bytes; } - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, ipc_header_req); handle->reqs_pending++; handle->write_reqs_pending++; @@ -1212,7 +1227,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req, } } - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); handle->reqs_pending++; handle->write_reqs_pending++; @@ -1435,6 +1450,8 @@ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, assert(handle->write_queue_size >= req->queued_bytes); handle->write_queue_size -= req->queued_bytes; + UNREGISTER_HANDLE_REQ(loop, handle, req); + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { if (req->wait_handle != INVALID_HANDLE_VALUE) { UnregisterWait(req->wait_handle); @@ -1476,7 +1493,6 @@ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, uv_want_endgame(loop, (uv_handle_t*)handle); } - uv_unref(loop); DECREASE_PENDING_REQ_COUNT(handle); } @@ -1513,6 +1529,8 @@ void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, uv_connect_t* req) { assert(handle->type == UV_NAMED_PIPE); + UNREGISTER_HANDLE_REQ(loop, handle, req); + if (req->cb) { if (REQ_SUCCESS(req)) { uv_pipe_connection_init(handle); @@ -1523,7 +1541,6 @@ void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, } } - uv_unref(loop); DECREASE_PENDING_REQ_COUNT(handle); } @@ -1532,6 +1549,8 @@ void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, uv_shutdown_t* req) { assert(handle->type == UV_NAMED_PIPE); + UNREGISTER_HANDLE_REQ(loop, handle, req); + /* Initialize and optionally start the eof timer. */ /* This makes no sense if we've already seen EOF. */ if (!(handle->flags & UV_HANDLE_EOF)) { @@ -1548,7 +1567,6 @@ void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, req->cb(req, 0); } - uv_unref(loop); DECREASE_PENDING_REQ_COUNT(handle); } @@ -1564,7 +1582,7 @@ static void eof_timer_init(uv_pipe_t* pipe) { r = uv_timer_init(pipe->loop, pipe->eof_timer); assert(r == 0); /* timers can't fail */ pipe->eof_timer->data = pipe; - uv_unref(pipe->loop); + uv_unref((uv_handle_t*) pipe->eof_timer); } @@ -1598,7 +1616,7 @@ static void eof_timer_cb(uv_timer_t* timer, int status) { /* or in uv_process_pipe_shutdown_req if a read is pending, */ /* and we always immediately stop the timer in */ /* uv_process_pipe_read_req. */ - assert(pipe->flags & UV_HANDLE_READ_PENDING) ; + assert(pipe->flags & UV_HANDLE_READ_PENDING); /* If there are many packets coming off the iocp then the timer callback */ /* may be called before the read request is coming off the queue. */ @@ -1627,7 +1645,6 @@ static void eof_timer_destroy(uv_pipe_t* pipe) { assert(pipe->flags && UV_HANDLE_CONNECTION); if (pipe->eof_timer) { - uv_ref(pipe->loop); uv_close((uv_handle_t*) pipe->eof_timer, eof_timer_close_cb); pipe->eof_timer = NULL; } diff --git a/src/win/poll.c b/src/win/poll.c index e0b9b5ad..c6d68ffd 100644 --- a/src/win/poll.c +++ b/src/win/poll.c @@ -20,13 +20,12 @@ */ +#include "uv.h" +#include "internal.h" + #include #include -#include "uv.h" -#include "../uv-common.h" -#include "internal.h" - static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = { {0xe70f1aa0, 0xab8b, 0x11cf, @@ -202,6 +201,13 @@ static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0); handle->events = events; + + if (handle->events != 0) { + uv__handle_start(handle); + } else { + uv__handle_stop(handle); + } + if ((handle->events & ~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) { uv__fast_poll_submit_poll_req(handle->loop, handle); @@ -213,6 +219,7 @@ static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { static void uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) { handle->events = 0; + uv__handle_start(handle); if (handle->submitted_events_1 == 0 && handle->submitted_events_2 == 0) { @@ -449,6 +456,13 @@ static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0); handle->events = events; + + if (handle->events != 0) { + uv__handle_start(handle); + } else { + uv__handle_stop(handle); + } + if ((handle->events & ~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) { uv__slow_poll_submit_poll_req(handle->loop, handle); @@ -460,6 +474,7 @@ static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { static void uv__slow_poll_close(uv_loop_t* loop, uv_poll_t* handle) { handle->events = 0; + uv__handle_start(handle); if (handle->submitted_events_1 == 0 && handle->submitted_events_2 == 0) { @@ -501,10 +516,9 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, socket = base_socket; } + uv_handle_init(loop, (uv_handle_t*) handle); handle->type = UV_POLL; handle->socket = socket; - handle->loop = loop; - handle->flags = 0; handle->events = 0; /* Obtain protocol information about the socket. */ @@ -542,9 +556,6 @@ int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, handle->poll_req_2.type = UV_POLL_REQ; handle->poll_req_2.data = handle; - uv_ref(loop); - - loop->counters.handle_init++; loop->counters.poll_init++; return 0; @@ -561,6 +572,7 @@ int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) { } handle->poll_cb = cb; + return 0; } @@ -600,10 +612,9 @@ void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) { assert(handle->submitted_events_2 == 0); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } - - uv_unref(loop); } diff --git a/src/win/process.c b/src/win/process.c index aacb0617..481b945c 100644 --- a/src/win/process.c +++ b/src/win/process.c @@ -20,7 +20,6 @@ */ #include "uv.h" -#include "../uv-common.h" #include "internal.h" #include @@ -55,9 +54,8 @@ typedef struct env_var { static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) { + uv_handle_init(loop, (uv_handle_t*) handle); handle->type = UV_PROCESS; - handle->loop = loop; - handle->flags = 0; handle->exit_cb = NULL; handle->pid = 0; handle->exit_signal = 0; @@ -77,8 +75,6 @@ static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) { loop->counters.handle_init++; loop->counters.process_init++; - - uv_ref(loop); } @@ -689,30 +685,28 @@ static void close_child_stdio(uv_process_t* process) { void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) { DWORD exit_code; + /* FIXME: race condition. */ + if (handle->flags & UV_HANDLE_CLOSING) { + return; + } + /* Unregister from process notification. */ if (handle->wait_handle != INVALID_HANDLE_VALUE) { UnregisterWait(handle->wait_handle); handle->wait_handle = INVALID_HANDLE_VALUE; } - if (handle->process_handle != INVALID_HANDLE_VALUE) { - /* Get the exit code. */ - if (!GetExitCodeProcess(handle->process_handle, &exit_code)) { - exit_code = 127; - } - - /* Clean-up the process handle. */ - CloseHandle(handle->process_handle); - handle->process_handle = INVALID_HANDLE_VALUE; - } else { - /* We probably left the child stdio handles open to report the error */ - /* asynchronously, so close them now. */ - close_child_stdio(handle); - - /* The process never even started in the first place. */ + if (handle->process_handle == INVALID_HANDLE_VALUE || + !GetExitCodeProcess(handle->process_handle, &exit_code)) { + /* The process never even started in the first place, or we were unable */ + /* to obtain the exit code. */ exit_code = 127; } + /* Set the handle to inactive: no callbacks will be made after the exit */ + /* callback.*/ + uv__handle_stop(handle); + /* Fire the exit callback. */ if (handle->exit_cb) { handle->exit_cb(handle, exit_code, handle->exit_signal); @@ -726,21 +720,9 @@ void uv_process_proc_close(uv_loop_t* loop, uv_process_t* handle) { } -void uv_process_endgame(uv_loop_t* loop, uv_process_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((uv_handle_t*)handle); - } - - uv_unref(loop); - } -} - - void uv_process_close(uv_loop_t* loop, uv_process_t* handle) { + uv__handle_start(handle); + if (handle->wait_handle != INVALID_HANDLE_VALUE) { handle->close_handle = CreateEvent(NULL, FALSE, FALSE, NULL); UnregisterWaitEx(handle->wait_handle, handle->close_handle); @@ -755,6 +737,25 @@ void uv_process_close(uv_loop_t* loop, uv_process_t* handle) { } +void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) { + if (handle->flags & UV_HANDLE_CLOSING) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); + + /* Clean-up the process handle. */ + CloseHandle(handle->process_handle); + + /* Clean up the child stdio ends that may have been left open. */ + close_child_stdio(handle); + + if (handle->close_cb) { + handle->close_cb((uv_handle_t*)handle); + } + } +} + + static int uv_create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe, HANDLE* child_pipe, DWORD server_access, DWORD child_access, int overlapped) { @@ -816,7 +817,7 @@ static int uv_create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe, done: if (err) { if (server_pipe->handle != INVALID_HANDLE_VALUE) { - close_pipe(server_pipe, NULL, NULL); + uv_pipe_cleanup(loop, server_pipe); } if (*child_pipe != INVALID_HANDLE_VALUE) { @@ -1058,7 +1059,12 @@ done: } } - if (err) { + if (err == 0) { + /* Spawn was succesful. The handle will be active until the exit */ + /* is made or the handle is closed, whichever happens first. */ + uv__handle_start(process); + } else { + /* Spawn was not successful. Clean up. */ if (process->wait_handle != INVALID_HANDLE_VALUE) { UnregisterWait(process->wait_handle); process->wait_handle = INVALID_HANDLE_VALUE; diff --git a/src/win/req.c b/src/win/req.c index dcfbd9c5..1aae7091 100644 --- a/src/win/req.c +++ b/src/win/req.c @@ -22,7 +22,6 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -147,8 +146,8 @@ void uv_process_reqs(uv_loop_t* loop) { uv_process_ares_cleanup_req(loop, (uv_ares_task_t*) req->data, req); break; - case UV_GETADDRINFO_REQ: - uv_process_getaddrinfo_req(loop, (uv_getaddrinfo_t*) req->data, req); + case UV_GETADDRINFO: + uv_process_getaddrinfo_req(loop, (uv_getaddrinfo_t*) req); break; case UV_PROCESS_EXIT: diff --git a/src/win/stream.c b/src/win/stream.c index 4275bce1..dad8669b 100644 --- a/src/win/stream.c +++ b/src/win/stream.c @@ -22,19 +22,15 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" void uv_stream_init(uv_loop_t* loop, uv_stream_t* handle) { + uv_handle_init(loop, (uv_handle_t*) handle); handle->write_queue_size = 0; - handle->loop = loop; - handle->flags = 0; + handle->activecnt = 0; - loop->counters.handle_init++; loop->counters.stream_init++; - - uv_ref(loop); } @@ -109,8 +105,11 @@ int uv_read2_start(uv_stream_t* handle, uv_alloc_cb alloc_cb, int uv_read_stop(uv_stream_t* handle) { if (handle->type == UV_TTY) { return uv_tty_read_stop((uv_tty_t*) handle); - } else { + } else if (handle->flags & UV_HANDLE_READING) { handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(handle->loop, handle); + return 0; + } else { return 0; } } @@ -171,7 +170,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) { handle->flags |= UV_HANDLE_SHUTTING; handle->shutdown_req = req; handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); uv_want_endgame(loop, (uv_handle_t*)handle); diff --git a/src/win/tcp.c b/src/win/tcp.c index 4f624f45..fd956a09 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -22,7 +22,6 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -143,12 +142,12 @@ static int uv_tcp_set_socket(uv_loop_t* loop, uv_tcp_t* handle, int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) { - uv_stream_init(loop, (uv_stream_t*)handle); + uv_stream_init(loop, (uv_stream_t*) handle); + handle->type = UV_TCP; handle->accept_reqs = NULL; handle->pending_accepts = NULL; handle->socket = INVALID_SOCKET; - handle->type = UV_TCP; handle->reqs_pending = 0; handle->func_acceptex = NULL; handle->func_connectex = NULL; @@ -170,6 +169,8 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { handle->shutdown_req != NULL && handle->write_reqs_pending == 0) { + UNREGISTER_HANDLE_REQ(loop, handle, handle->shutdown_req); + if (handle->flags & UV_HANDLE_CLOSING) { status = -1; sys_error = WSAEINTR; @@ -180,6 +181,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { status = -1; sys_error = WSAGetLastError(); } + if (handle->shutdown_req->cb) { if (status == -1) { uv__set_sys_error(loop, sys_error); @@ -188,8 +190,6 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { } handle->shutdown_req = NULL; - - uv_unref(loop); DECREASE_PENDING_REQ_COUNT(handle); return; } @@ -198,6 +198,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { handle->reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) { closesocket(handle->socket); @@ -240,8 +241,6 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { } loop->active_tcp_streams--; - - uv_unref(loop); } } @@ -500,6 +499,15 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { assert(backlog > 0); + if (handle->flags & UV_HANDLE_LISTENING) { + handle->connection_cb = cb; + } + + if (handle->flags & UV_HANDLE_READING) { + uv__set_artificial_error(loop, UV_EISCONN); + return -1; + } + if (handle->flags & UV_HANDLE_BIND_ERROR) { uv__set_sys_error(loop, handle->bind_error); return -1; @@ -524,6 +532,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { handle->flags |= UV_HANDLE_LISTENING; handle->connection_cb = cb; + INCREASE_ACTIVE_COUNT(loop, handle); simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1 : uv_simultaneous_server_accepts; @@ -642,6 +651,7 @@ int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, handle->flags |= UV_HANDLE_READING; handle->read_cb = read_cb; handle->alloc_cb = alloc_cb; + INCREASE_ACTIVE_COUNT(loop, handle); /* If reading was stopped and then started again, there could still be a */ /* read request pending. */ @@ -702,12 +712,12 @@ int uv__tcp_connect(uv_connect_t* req, if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { /* Process the req without IOCP. */ handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); uv_insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(success)) { /* The req will be processed with IOCP. */ handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); } else { uv__set_sys_error(loop, WSAGetLastError()); return -1; @@ -763,11 +773,11 @@ int uv__tcp_connect6(uv_connect_t* req, if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); uv_insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(success)) { handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); } else { uv__set_sys_error(loop, WSAGetLastError()); return -1; @@ -872,15 +882,15 @@ int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle, req->queued_bytes = 0; handle->reqs_pending++; handle->write_reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); uv_insert_pending_req(loop, (uv_req_t*) req); - uv_ref(loop); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* Request queued by the kernel. */ req->queued_bytes = uv_count_bufs(bufs, bufcnt); handle->reqs_pending++; handle->write_reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); handle->write_queue_size += req->queued_bytes; - uv_ref(loop); if (handle->flags & UV_HANDLE_EMULATE_IOCP && !RegisterWaitForSingleObject(&req->wait_handle, req->event_handle, post_write_completion, (void*) req, @@ -912,6 +922,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, if ((handle->flags & UV_HANDLE_READING) || !(handle->flags & UV_HANDLE_ZERO_READ)) { handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); buf = (handle->flags & UV_HANDLE_ZERO_READ) ? uv_buf_init(NULL, 0) : handle->read_buffer; @@ -942,8 +953,12 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, } } else { /* Connection closed */ - handle->flags &= ~UV_HANDLE_READING; + if (handle->flags & UV_HANDLE_READING) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + } handle->flags |= UV_HANDLE_EOF; + uv__set_error(loop, UV_EOF, ERROR_SUCCESS); buf.base = 0; buf.len = 0; @@ -974,7 +989,9 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, } else { /* Connection closed */ handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); handle->flags |= UV_HANDLE_EOF; + uv__set_error(loop, UV_EOF, ERROR_SUCCESS); handle->read_cb((uv_stream_t*)handle, -1, buf); break; @@ -986,16 +1003,18 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv__set_sys_error(loop, WSAEWOULDBLOCK); handle->read_cb((uv_stream_t*)handle, 0, buf); } else { + /* Ouch! serious error. */ + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + if (err == WSAECONNABORTED) { - /* - * Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix. - */ + /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with */ + /* Unix. */ uv__set_error(loop, UV_ECONNRESET, err); } else { - /* Ouch! serious error. */ uv__set_sys_error(loop, err); } - handle->flags &= ~UV_HANDLE_READING; + handle->read_cb((uv_stream_t*)handle, -1, buf); } break; @@ -1021,6 +1040,8 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, assert(handle->write_queue_size >= req->queued_bytes); handle->write_queue_size -= req->queued_bytes; + UNREGISTER_HANDLE_REQ(loop, handle, req); + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { if (req->wait_handle != INVALID_HANDLE_VALUE) { UnregisterWait(req->wait_handle); @@ -1042,7 +1063,6 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, } DECREASE_PENDING_REQ_COUNT(handle); - uv_unref(loop); } @@ -1059,6 +1079,7 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, if (req->accept_socket == INVALID_SOCKET) { if (handle->flags & UV_HANDLE_LISTENING) { handle->flags &= ~UV_HANDLE_LISTENING; + DECREASE_ACTIVE_COUNT(loop, handle); if (handle->connection_cb) { uv__set_sys_error(loop, GET_REQ_SOCK_ERROR(req)); handle->connection_cb((uv_stream_t*)handle, -1); @@ -1096,28 +1117,27 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, uv_connect_t* req) { assert(handle->type == UV_TCP); - if (req->cb) { - if (REQ_SUCCESS(req)) { - if (setsockopt(handle->socket, - SOL_SOCKET, - SO_UPDATE_CONNECT_CONTEXT, - NULL, - 0) == 0) { - uv_connection_init((uv_stream_t*)handle); - loop->active_tcp_streams++; - ((uv_connect_cb)req->cb)(req, 0); - } else { - uv__set_sys_error(loop, WSAGetLastError()); - ((uv_connect_cb)req->cb)(req, -1); - } + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (REQ_SUCCESS(req)) { + if (setsockopt(handle->socket, + SOL_SOCKET, + SO_UPDATE_CONNECT_CONTEXT, + NULL, + 0) == 0) { + uv_connection_init((uv_stream_t*)handle); + loop->active_tcp_streams++; + ((uv_connect_cb)req->cb)(req, 0); } else { - uv__set_sys_error(loop, GET_REQ_SOCK_ERROR(req)); + uv__set_sys_error(loop, WSAGetLastError()); ((uv_connect_cb)req->cb)(req, -1); } + } else { + uv__set_sys_error(loop, GET_REQ_SOCK_ERROR(req)); + ((uv_connect_cb)req->cb)(req, -1); } DECREASE_PENDING_REQ_COUNT(handle); - uv_unref(loop); } @@ -1149,7 +1169,7 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info, if (uv_tcp_set_socket(tcp->loop, tcp, socket, 1) != 0) { return -1; } - + tcp->loop->active_tcp_streams++; return 0; } @@ -1189,11 +1209,10 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) { } - int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, LPWSAPROTOCOL_INFOW protocol_info) { if (!(handle->flags & UV_HANDLE_CONNECTION)) { - /* + /* * We're about to share the socket with another process. Because * this is a listening socket, we assume that the other process will * be accepting connections on it. So, before sharing the socket @@ -1257,7 +1276,7 @@ int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { } -void uv_tcp_close(uv_tcp_t* tcp) { +void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { int non_ifs_lsp; int close_socket = 1; @@ -1276,7 +1295,7 @@ void uv_tcp_close(uv_tcp_t* tcp) { uv_tcp_non_ifs_lsp_ipv4; if (!non_ifs_lsp) { - /* + /* * Shared socket with no non-IFS LSPs, request to cancel pending I/O. * The socket will be closed inside endgame. */ @@ -1286,13 +1305,23 @@ void uv_tcp_close(uv_tcp_t* tcp) { } } - tcp->flags &= ~(UV_HANDLE_READING | UV_HANDLE_LISTENING); + if (tcp->flags & UV_HANDLE_READING) { + tcp->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, tcp); + } + + if (tcp->flags & UV_HANDLE_LISTENING) { + tcp->flags &= ~UV_HANDLE_LISTENING; + DECREASE_ACTIVE_COUNT(loop, tcp); + } if (close_socket) { closesocket(tcp->socket); tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED; } + uv__handle_start(tcp); + if (tcp->reqs_pending == 0) { uv_want_endgame(tcp->loop, (uv_handle_t*)tcp); } diff --git a/src/win/thread.c b/src/win/thread.c index d6d3ce8f..01b81408 100644 --- a/src/win/thread.c +++ b/src/win/thread.c @@ -19,11 +19,12 @@ * IN THE SOFTWARE. */ -#include "uv.h" -#include "../uv-common.h" -#include "internal.h" #include +#include "uv.h" +#include "internal.h" + + #define HAVE_SRWLOCK_API() (pTryAcquireSRWLockShared != NULL) #ifdef _MSC_VER /* msvc */ diff --git a/src/win/threadpool.c b/src/win/threadpool.c index 4fb20d34..e066810d 100644 --- a/src/win/threadpool.c +++ b/src/win/threadpool.c @@ -61,13 +61,13 @@ int uv_queue_work(uv_loop_t* loop, uv_work_t* req, uv_work_cb work_cb, return -1; } - uv_ref(loop); + uv__req_register(loop, req); return 0; } void uv_process_work_req(uv_loop_t* loop, uv_work_t* req) { assert(req->after_work_cb); + uv__req_unregister(loop, req); req->after_work_cb(req); - uv_unref(loop); } diff --git a/src/win/timer.c b/src/win/timer.c index dc2034b6..fbde888d 100644 --- a/src/win/timer.c +++ b/src/win/timer.c @@ -26,6 +26,7 @@ #include "internal.h" #include "tree.h" + #undef NANOSEC #define NANOSEC 1000000000 @@ -111,16 +112,12 @@ RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare); int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) { - loop->counters.handle_init++; - loop->counters.timer_init++; - + uv_handle_init(loop, (uv_handle_t*) handle); handle->type = UV_TIMER; - handle->loop = loop; - handle->flags = 0; handle->timer_cb = NULL; handle->repeat = 0; - uv_ref(loop); + loop->counters.timer_init++; return 0; } @@ -130,12 +127,11 @@ void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle) { if (handle->flags & UV_HANDLE_CLOSING) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } - - uv_unref(loop); } } @@ -152,6 +148,7 @@ int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, int64_t timeout, handle->due = loop->time + timeout; handle->repeat = repeat; handle->flags |= UV_HANDLE_ACTIVE; + uv__handle_start(handle); if (RB_INSERT(uv_timer_tree_s, &loop->timers, handle) != NULL) { uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT"); @@ -170,6 +167,7 @@ int uv_timer_stop(uv_timer_t* handle) { RB_REMOVE(uv_timer_tree_s, &loop->timers, handle); handle->flags &= ~UV_HANDLE_ACTIVE; + uv__handle_stop(handle); return 0; } @@ -187,6 +185,7 @@ int uv_timer_again(uv_timer_t* handle) { if (handle->flags & UV_HANDLE_ACTIVE) { RB_REMOVE(uv_timer_tree_s, &loop->timers, handle); handle->flags &= ~UV_HANDLE_ACTIVE; + uv__handle_stop(handle); } if (handle->repeat) { @@ -197,6 +196,7 @@ int uv_timer_again(uv_timer_t* handle) { } handle->flags |= UV_HANDLE_ACTIVE; + uv__handle_start(handle); } return 0; @@ -268,6 +268,7 @@ void uv_process_timers(uv_loop_t* loop) { } else { /* If non-repeating, mark the timer as inactive. */ timer->flags &= ~UV_HANDLE_ACTIVE; + uv__handle_stop(timer); } timer->timer_cb((uv_timer_t*) timer, 0); diff --git a/src/win/tty.c b/src/win/tty.c index 6f6aac87..bd46215e 100644 --- a/src/win/tty.c +++ b/src/win/tty.c @@ -25,7 +25,6 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -462,8 +461,9 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, /* Fetch the number of events */ if (!GetNumberOfConsoleInputEvents(handle->handle, &records_left)) { - handle->flags &= ~UV_HANDLE_READING; uv__set_sys_error(loop, GetLastError()); + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); handle->read_cb((uv_stream_t*)handle, -1, uv_null_buf_); goto out; } @@ -483,6 +483,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, &records_read)) { uv__set_sys_error(loop, GetLastError()); handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); handle->read_cb((uv_stream_t*) handle, -1, buf); goto out; } @@ -583,6 +584,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, if (!char_len) { uv__set_sys_error(loop, GetLastError()); handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); handle->read_cb((uv_stream_t*) handle, -1, buf); goto out; } @@ -691,6 +693,7 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle, !(handle->flags & UV_HANDLE_TTY_RAW)) { /* Real error */ handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); uv__set_sys_error(loop, GET_REQ_ERROR(req)); handle->read_cb((uv_stream_t*) handle, -1, buf); } else { @@ -738,6 +741,7 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, uv_loop_t* loop = handle->loop; handle->flags |= UV_HANDLE_READING; + INCREASE_ACTIVE_COUNT(loop, handle); handle->read_cb = read_cb; handle->alloc_cb = alloc_cb; @@ -762,7 +766,12 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, int uv_tty_read_stop(uv_tty_t* handle) { - handle->flags &= ~UV_HANDLE_READING; + uv_loop_t* loop = handle->loop; + + if (handle->flags & UV_HANDLE_READING) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + } /* Cancel raw read */ if ((handle->flags & UV_HANDLE_READ_PENDING) && @@ -772,7 +781,7 @@ int uv_tty_read_stop(uv_tty_t* handle) { DWORD written; memset(&record, 0, sizeof record); if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) { - uv__set_sys_error(handle->loop, GetLastError()); + uv__set_sys_error(loop, GetLastError()); return -1; } } @@ -1680,7 +1689,7 @@ int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle, handle->reqs_pending++; handle->write_reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); req->queued_bytes = 0; @@ -1700,6 +1709,7 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, uv_write_t* req) { handle->write_queue_size -= req->queued_bytes; + UNREGISTER_HANDLE_REQ(loop, handle, req); if (req->cb) { uv__set_sys_error(loop, GET_REQ_ERROR(req)); @@ -1713,7 +1723,6 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, } DECREASE_PENDING_REQ_COUNT(handle); - uv_unref(loop); } @@ -1723,6 +1732,8 @@ void uv_tty_close(uv_tty_t* handle) { uv_tty_read_stop(handle); CloseHandle(handle->handle); + uv__handle_start(handle); + if (handle->reqs_pending == 0) { uv_want_endgame(handle->loop, (uv_handle_t*) handle); } @@ -1733,6 +1744,8 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { if ((handle->flags && UV_HANDLE_CONNECTION) && handle->shutdown_req != NULL && handle->write_reqs_pending == 0) { + UNREGISTER_HANDLE_REQ(loop, handle, handle->shutdown_req); + /* TTY shutdown is really just a no-op */ if (handle->shutdown_req->cb) { if (handle->flags & UV_HANDLE_CLOSING) { @@ -1745,7 +1758,6 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { handle->shutdown_req = NULL; - uv_unref(loop); DECREASE_PENDING_REQ_COUNT(handle); return; } @@ -1762,12 +1774,11 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } - - uv_unref(loop); } } diff --git a/src/win/udp.c b/src/win/udp.c index 42069aff..ddd08a26 100644 --- a/src/win/udp.c +++ b/src/win/udp.c @@ -22,7 +22,6 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -121,11 +120,12 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { + uv_handle_init(loop, (uv_handle_t*) handle); + handle->type = UV_UDP; handle->socket = INVALID_SOCKET; handle->reqs_pending = 0; - handle->loop = loop; - handle->flags = 0; + handle->activecnt = 0; handle->func_wsarecv = WSARecv; handle->func_wsarecvfrom = WSARecvFrom; @@ -133,26 +133,34 @@ int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { handle->recv_req.type = UV_UDP_RECV; handle->recv_req.data = handle; - uv_ref(loop); - - loop->counters.handle_init++; loop->counters.udp_init++; return 0; } +void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) { + uv_udp_recv_stop(handle); + closesocket(handle->socket); + + uv__handle_start(handle); + + if (handle->reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) { if (handle->flags & UV_HANDLE_CLOSING && handle->reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } - - uv_unref(loop); } } @@ -350,6 +358,7 @@ int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, } handle->flags |= UV_HANDLE_READING; + INCREASE_ACTIVE_COUNT(loop, handle); loop->active_udp_streams++; handle->recv_cb = recv_cb; @@ -368,6 +377,7 @@ int uv_udp_recv_stop(uv_udp_t* handle) { if (handle->flags & UV_HANDLE_READING) { handle->flags &= ~UV_HANDLE_READING; handle->loop->active_udp_streams--; + DECREASE_ACTIVE_COUNT(loop, handle); } return 0; @@ -399,13 +409,13 @@ static int uv__udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[], /* Request completed immediately. */ req->queued_bytes = 0; handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); uv_insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* Request queued by the kernel. */ req->queued_bytes = uv_count_bufs(bufs, bufcnt); handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); } else { /* Send failed due to an error. */ uv__set_sys_error(loop, WSAGetLastError()); @@ -561,6 +571,8 @@ void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, uv_udp_send_t* req) { assert(handle->type == UV_UDP); + UNREGISTER_HANDLE_REQ(loop, handle, req); + if (req->cb) { if (REQ_SUCCESS(req)) { req->cb(req, 0); @@ -570,7 +582,6 @@ void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, } } - uv_unref(loop); DECREASE_PENDING_REQ_COUNT(handle); } diff --git a/src/win/util.c b/src/win/util.c index f4d5fdbe..10c22712 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -29,9 +29,10 @@ #include "uv.h" #include "internal.h" -#include "tlhelp32.h" -#include "psapi.h" -#include "iphlpapi.h" + +#include +#include +#include /* diff --git a/src/win/winapi.c b/src/win/winapi.c index a474c92a..4614a3ad 100644 --- a/src/win/winapi.c +++ b/src/win/winapi.c @@ -22,7 +22,6 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" diff --git a/src/win/winsock.c b/src/win/winsock.c index a29cd161..2c3e49a1 100644 --- a/src/win/winsock.c +++ b/src/win/winsock.c @@ -22,9 +22,9 @@ #include #include "uv.h" -#include "../uv-common.h" #include "internal.h" + /* Whether ipv6 is supported */ int uv_allow_ipv6; diff --git a/test/benchmark-udp-packet-storm.c b/test/benchmark-udp-packet-storm.c index 5ffa4e05..59412870 100644 --- a/test/benchmark-udp-packet-storm.c +++ b/test/benchmark-udp-packet-storm.c @@ -144,7 +144,7 @@ static int do_packet_storm(int n_senders, int n_receivers) { ASSERT(r == 0); /* Timer should not keep loop alive. */ - uv_unref(loop); + uv_unref((uv_handle_t*)&timeout); for (i = 0; i < n_receivers; i++) { struct sockaddr_in addr; diff --git a/test/test-eio-overflow.c b/test/test-eio-overflow.c index de3d65b7..c7a8f506 100644 --- a/test/test-eio-overflow.c +++ b/test/test-eio-overflow.c @@ -68,7 +68,6 @@ void idle_cb(uv_idle_t* idle, int status) { int r; r = uv_idle_stop(idle); - uv_unref(uv_default_loop()); ASSERT(r == 0); } } diff --git a/test/test-list.h b/test/test-list.h index 6961b6f2..75e08488 100644 --- a/test/test-list.h +++ b/test/test-list.h @@ -89,7 +89,6 @@ TEST_DECLARE (tcp_ref) TEST_DECLARE (tcp_ref2) TEST_DECLARE (tcp_ref3) TEST_DECLARE (tcp_ref4) -TEST_DECLARE (tcp_ref5) TEST_DECLARE (udp_ref) TEST_DECLARE (udp_ref2) TEST_DECLARE (udp_ref3) @@ -97,7 +96,6 @@ TEST_DECLARE (pipe_ref) TEST_DECLARE (pipe_ref2) TEST_DECLARE (pipe_ref3) TEST_DECLARE (pipe_ref4) -TEST_DECLARE (pipe_ref5) TEST_DECLARE (process_ref) TEST_DECLARE (async) TEST_DECLARE (get_currentexe) @@ -275,8 +273,6 @@ TASK_LIST_START TEST_HELPER (tcp_ref3, tcp4_echo_server) TEST_ENTRY (tcp_ref4) TEST_HELPER (tcp_ref4, tcp4_echo_server) - TEST_ENTRY (tcp_ref5) - TEST_HELPER (tcp_ref5, tcp4_echo_server) TEST_ENTRY (udp_ref) TEST_ENTRY (udp_ref2) TEST_ENTRY (udp_ref3) @@ -287,8 +283,6 @@ TASK_LIST_START TEST_HELPER (pipe_ref3, pipe_echo_server) TEST_ENTRY (pipe_ref4) TEST_HELPER (pipe_ref4, pipe_echo_server) - TEST_ENTRY (pipe_ref5) - TEST_HELPER (pipe_ref5, pipe_echo_server) TEST_ENTRY (process_ref) TEST_ENTRY (loop_handles) diff --git a/test/test-loop-handles.c b/test/test-loop-handles.c index 866445da..45a41f18 100644 --- a/test/test-loop-handles.c +++ b/test/test-loop-handles.c @@ -323,7 +323,7 @@ TEST_IMPL(loop_handles) { ASSERT(r == 0); r = uv_timer_start(&timer_handle, timer_cb, TIMEOUT, TIMEOUT); ASSERT(r == 0); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&timer_handle); r = uv_run(uv_default_loop()); ASSERT(r == 0); diff --git a/test/test-ref.c b/test/test-ref.c index cab3a703..cc59aa7b 100644 --- a/test/test-ref.c +++ b/test/test-ref.c @@ -32,30 +32,50 @@ static uv_connect_t connect_req; static char buffer[32767]; +static int req_cb_called; +static int connect_cb_called; +static int write_cb_called; +static int shutdown_cb_called; + static void fail_cb(void) { FATAL("fail_cb should not have been called"); } -static void write_unref_cb(uv_connect_t* req, int status) { - uv_buf_t buf = uv_buf_init(buffer, sizeof buffer); +static void req_cb(uv_handle_t* req, int status) { + req_cb_called++; +} + +static void shutdown_cb(uv_shutdown_t* req, int status) { + ASSERT(req == &shutdown_req); + shutdown_cb_called++; +} + + +static void write_cb(uv_write_t* req, int status) { + ASSERT(req == &write_req); + uv_shutdown(&shutdown_req, req->handle, shutdown_cb); + write_cb_called++; +} + + +static void connect_and_write(uv_connect_t* req, int status) { + uv_buf_t buf = uv_buf_init(buffer, sizeof buffer); ASSERT(req == &connect_req); ASSERT(status == 0); - - uv_write(&write_req, req->handle, &buf, 1, (uv_write_cb) fail_cb); - uv_unref(uv_default_loop()); /* uv_write refs the loop */ + uv_write(&write_req, req->handle, &buf, 1, write_cb); + connect_cb_called++; } -static void shutdown_unref_cb(uv_connect_t* req, int status) { +static void connect_and_shutdown(uv_connect_t* req, int status) { ASSERT(req == &connect_req); ASSERT(status == 0); - - uv_shutdown(&shutdown_req, req->handle, (uv_shutdown_cb) fail_cb); - uv_unref(uv_default_loop()); /* uv_shutdown refs the loop */ + uv_shutdown(&shutdown_req, req->handle, shutdown_cb); + connect_cb_called++; } @@ -69,7 +89,7 @@ TEST_IMPL(idle_ref) { uv_idle_t h; uv_idle_init(uv_default_loop(), &h); uv_idle_start(&h, NULL); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -78,7 +98,7 @@ TEST_IMPL(idle_ref) { TEST_IMPL(async_ref) { uv_async_t h; uv_async_init(uv_default_loop(), &h, NULL); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -88,7 +108,7 @@ TEST_IMPL(prepare_ref) { uv_prepare_t h; uv_prepare_init(uv_default_loop(), &h); uv_prepare_start(&h, NULL); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -98,17 +118,16 @@ TEST_IMPL(check_ref) { uv_check_t h; uv_check_init(uv_default_loop(), &h); uv_check_start(&h, NULL); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } -static void prepare_cb(uv_prepare_t* handle, int status) { - ASSERT(handle != NULL); +static void prepare_cb(uv_prepare_t* h, int status) { + ASSERT(h != NULL); ASSERT(status == 0); - - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)h); } @@ -124,7 +143,7 @@ TEST_IMPL(unref_in_prepare_cb) { TEST_IMPL(timer_ref) { uv_timer_t h; uv_timer_init(uv_default_loop(), &h); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -133,8 +152,8 @@ TEST_IMPL(timer_ref) { TEST_IMPL(timer_ref2) { uv_timer_t h; uv_timer_init(uv_default_loop(), &h); - uv_timer_start(&h, (uv_timer_cb) fail_cb, 42, 42); - uv_unref(uv_default_loop()); + uv_timer_start(&h, (uv_timer_cb)fail_cb, 42, 42); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -142,8 +161,8 @@ TEST_IMPL(timer_ref2) { TEST_IMPL(fs_event_ref) { uv_fs_event_t h; - uv_fs_event_init(uv_default_loop(), &h, ".", (uv_fs_event_cb) fail_cb, 0); - uv_unref(uv_default_loop()); + uv_fs_event_init(uv_default_loop(), &h, ".", (uv_fs_event_cb)fail_cb, 0); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -152,7 +171,7 @@ TEST_IMPL(fs_event_ref) { TEST_IMPL(tcp_ref) { uv_tcp_t h; uv_tcp_init(uv_default_loop(), &h); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -162,7 +181,7 @@ TEST_IMPL(tcp_ref2) { uv_tcp_t h; uv_tcp_init(uv_default_loop(), &h); uv_listen((uv_stream_t*)&h, 128, (uv_connection_cb)fail_cb); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -172,10 +191,11 @@ TEST_IMPL(tcp_ref3) { struct sockaddr_in addr = uv_ip4_addr("127.0.0.1", TEST_PORT); uv_tcp_t h; uv_tcp_init(uv_default_loop(), &h); - uv_tcp_connect(&connect_req, &h, addr, (uv_connect_cb)fail_cb); - uv_unref(uv_default_loop()); - uv_unref(uv_default_loop()); /* connect req refs the loop */ + uv_tcp_connect(&connect_req, &h, addr, connect_and_shutdown); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); + ASSERT(connect_cb_called == 1); + ASSERT(shutdown_cb_called == 1); return 0; } @@ -184,20 +204,12 @@ TEST_IMPL(tcp_ref4) { struct sockaddr_in addr = uv_ip4_addr("127.0.0.1", TEST_PORT); uv_tcp_t h; uv_tcp_init(uv_default_loop(), &h); - uv_tcp_connect(&connect_req, &h, addr, write_unref_cb); - uv_unref(uv_default_loop()); - uv_run(uv_default_loop()); - return 0; -} - - -TEST_IMPL(tcp_ref5) { - struct sockaddr_in addr = uv_ip4_addr("127.0.0.1", TEST_PORT); - uv_tcp_t h; - uv_tcp_init(uv_default_loop(), &h); - uv_tcp_connect(&connect_req, &h, addr, shutdown_unref_cb); - uv_unref(uv_default_loop()); + uv_tcp_connect(&connect_req, &h, addr, connect_and_write); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); + ASSERT(connect_cb_called == 1); + ASSERT(write_cb_called == 1); + ASSERT(shutdown_cb_called == 1); return 0; } @@ -205,7 +217,7 @@ TEST_IMPL(tcp_ref5) { TEST_IMPL(udp_ref) { uv_udp_t h; uv_udp_init(uv_default_loop(), &h); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -217,7 +229,7 @@ TEST_IMPL(udp_ref2) { uv_udp_init(uv_default_loop(), &h); uv_udp_bind(&h, addr, 0); uv_udp_recv_start(&h, (uv_alloc_cb)fail_cb, (uv_udp_recv_cb)fail_cb); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -230,10 +242,10 @@ TEST_IMPL(udp_ref3) { uv_udp_t h; uv_udp_init(uv_default_loop(), &h); - uv_udp_send(&req, &h, &buf, 1, addr, (uv_udp_send_cb)fail_cb); - uv_unref(uv_default_loop()); - uv_unref(uv_default_loop()); /* send req refs the loop */ + uv_udp_send(&req, &h, &buf, 1, addr, (uv_udp_send_cb)req_cb); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); + ASSERT(req_cb_called == 1); return 0; } @@ -242,7 +254,7 @@ TEST_IMPL(udp_ref3) { TEST_IMPL(pipe_ref) { uv_pipe_t h; uv_pipe_init(uv_default_loop(), &h, 0); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -252,7 +264,7 @@ TEST_IMPL(pipe_ref2) { uv_pipe_t h; uv_pipe_init(uv_default_loop(), &h, 0); uv_listen((uv_stream_t*)&h, 128, (uv_connection_cb)fail_cb); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); return 0; } @@ -261,10 +273,11 @@ TEST_IMPL(pipe_ref2) { TEST_IMPL(pipe_ref3) { uv_pipe_t h; uv_pipe_init(uv_default_loop(), &h, 0); - uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, (uv_connect_cb)fail_cb); - uv_unref(uv_default_loop()); - uv_unref(uv_default_loop()); /* connect req refs the loop */ + uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_and_shutdown); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); + ASSERT(connect_cb_called == 1); + ASSERT(shutdown_cb_called == 1); return 0; } @@ -272,19 +285,12 @@ TEST_IMPL(pipe_ref3) { TEST_IMPL(pipe_ref4) { uv_pipe_t h; uv_pipe_init(uv_default_loop(), &h, 0); - uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, write_unref_cb); - uv_unref(uv_default_loop()); - uv_run(uv_default_loop()); - return 0; -} - - -TEST_IMPL(pipe_ref5) { - uv_pipe_t h; - uv_pipe_init(uv_default_loop(), &h, 0); - uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, shutdown_unref_cb); - uv_unref(uv_default_loop()); + uv_pipe_connect(&connect_req, &h, TEST_PIPENAME, connect_and_write); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); + ASSERT(connect_cb_called == 1); + ASSERT(write_cb_called == 1); + ASSERT(shutdown_cb_called == 1); return 0; } @@ -312,7 +318,7 @@ TEST_IMPL(process_ref) { r = uv_spawn(uv_default_loop(), &h, options); ASSERT(r == 0); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&h); uv_run(uv_default_loop()); r = uv_process_kill(&h, /* SIGTERM */ 15); diff --git a/test/test-stdio-over-pipes.c b/test/test-stdio-over-pipes.c index 98173fe3..0a3f04c6 100644 --- a/test/test-stdio-over-pipes.c +++ b/test/test-stdio-over-pipes.c @@ -203,8 +203,8 @@ int stdio_over_pipes_helper() { uv_pipe_open(&stdout_pipe, 1); /* Unref both stdio handles to make sure that all writes complete. */ - uv_unref(loop); - uv_unref(loop); + uv_unref((uv_handle_t*)&stdin_pipe); + uv_unref((uv_handle_t*)&stdout_pipe); for (i = 0; i < ARRAY_SIZE(buffers); i++) { buf[i] = uv_buf_init((char*)buffers[i], strlen(buffers[i])); @@ -222,8 +222,8 @@ int stdio_over_pipes_helper() { ASSERT(on_pipe_read_called == 0); ASSERT(close_cb_called == 0); - uv_ref(loop); - uv_ref(loop); + uv_ref((uv_handle_t*)&stdout_pipe); + uv_ref((uv_handle_t*)&stdin_pipe); r = uv_read_start((uv_stream_t*)&stdin_pipe, on_read_alloc, on_pipe_read); diff --git a/test/test-tcp-close.c b/test/test-tcp-close.c index 5da8a84f..33f79974 100644 --- a/test/test-tcp-close.c +++ b/test/test-tcp-close.c @@ -88,7 +88,7 @@ static void start_server(uv_loop_t* loop, uv_tcp_t* handle) { r = uv_listen((uv_stream_t*)handle, 128, connection_cb); ASSERT(r == 0); - uv_unref(loop); + uv_unref((uv_handle_t*)handle); } diff --git a/test/test-timer-again.c b/test/test-timer-again.c index 9eeee1e3..e492c364 100644 --- a/test/test-timer-again.c +++ b/test/test-timer-again.c @@ -104,7 +104,7 @@ TEST_IMPL(timer_again) { r = uv_timer_again(&dummy); ASSERT(r == -1); ASSERT(uv_last_error(uv_default_loop()).code == UV_EINVAL); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&dummy); /* Start timer repeat_1. */ r = uv_timer_init(uv_default_loop(), &repeat_1); diff --git a/test/test-timer.c b/test/test-timer.c index 1a0aabd6..c961aff4 100644 --- a/test/test-timer.c +++ b/test/test-timer.c @@ -114,7 +114,7 @@ TEST_IMPL(timer) { ASSERT(r == 0); r = uv_timer_stop(&never); ASSERT(r == 0); - uv_unref(uv_default_loop()); + uv_unref((uv_handle_t*)&never); uv_run(uv_default_loop()); diff --git a/test/test-udp-options.c b/test/test-udp-options.c index 34e652b7..4ff650dc 100644 --- a/test/test-udp-options.c +++ b/test/test-udp-options.c @@ -38,7 +38,7 @@ TEST_IMPL(udp_options) { r = uv_udp_init(loop, &h); ASSERT(r == 0); - uv_unref(loop); /* don't keep the loop alive */ + uv_unref((uv_handle_t*)&h); /* don't keep the loop alive */ r = uv_udp_bind(&h, uv_ip4_addr("0.0.0.0", TEST_PORT), 0); ASSERT(r == 0); diff --git a/uv.gyp b/uv.gyp index 4b804dcb..86a46b17 100644 --- a/uv.gyp +++ b/uv.gyp @@ -47,6 +47,8 @@ 'include/ares.h', 'include/ares_version.h', 'include/uv.h', + 'include/uv-private/ngx-queue.h', + 'include/uv-private/tree.h', 'src/uv-common.c', 'src/uv-common.h', 'src/ares/ares_cancel.c', @@ -125,7 +127,6 @@ '_GNU_SOURCE', ], 'sources': [ - 'include/uv-private/tree.h', 'include/uv-private/uv-win.h', 'src/ares/config_win32/ares_config.h', 'src/ares/windows_port.c', @@ -179,11 +180,9 @@ 'sources': [ 'include/uv-private/eio.h', 'include/uv-private/ev.h', - 'include/uv-private/ngx-queue.h', 'include/uv-private/uv-unix.h', 'src/unix/async.c', 'src/unix/cares.c', - 'src/unix/check.c', 'src/unix/core.c', 'src/unix/dl.c', 'src/unix/eio/ecb.h', @@ -195,12 +194,10 @@ 'src/unix/ev/ev_wrap.h', 'src/unix/ev/event.h', 'src/unix/fs.c', - 'src/unix/idle.c', 'src/unix/internal.h', 'src/unix/loop.c', 'src/unix/pipe.c', 'src/unix/poll.c', - 'src/unix/prepare.c', 'src/unix/process.c', 'src/unix/stream.c', 'src/unix/tcp.c',