diff options
Diffstat (limited to 'src/win')
-rw-r--r-- | src/win/async.c | 20 | ||||
-rw-r--r-- | src/win/atomicops-inl.h | 61 | ||||
-rw-r--r-- | src/win/core.c | 198 | ||||
-rw-r--r-- | src/win/fs-fd-hash-inl.h | 8 | ||||
-rw-r--r-- | src/win/fs.c | 73 | ||||
-rw-r--r-- | src/win/handle-inl.h | 68 | ||||
-rw-r--r-- | src/win/pipe.c | 3 | ||||
-rw-r--r-- | src/win/poll.c | 6 | ||||
-rw-r--r-- | src/win/req-inl.h | 130 | ||||
-rw-r--r-- | src/win/tcp.c | 126 | ||||
-rw-r--r-- | src/win/thread.c | 2 | ||||
-rw-r--r-- | src/win/util.c | 15 | ||||
-rw-r--r-- | src/win/winapi.c | 10 | ||||
-rw-r--r-- | src/win/winsock.h | 28 |
14 files changed, 396 insertions, 352 deletions
diff --git a/src/win/async.c b/src/win/async.c index b904676e..4c2cd265 100644 --- a/src/win/async.c +++ b/src/win/async.c @@ -23,10 +23,28 @@ #include "uv.h" #include "internal.h" -#include "atomicops-inl.h" #include "handle-inl.h" #include "req-inl.h" +#ifdef _MSC_VER /* MSVC */ + +/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less + * efficient than InterlockedExchange, but InterlockedExchange8 does not exist, + * and interlocked operations on larger targets might require the target to be + * aligned. */ +#pragma intrinsic(_InterlockedOr8) + +static char uv__atomic_exchange_set(char volatile* target) { + return _InterlockedOr8(target, 1); +} + +#else /* GCC, Clang in mingw mode */ + +static char uv__atomic_exchange_set(char volatile* target) { + return __sync_fetch_and_or(target, 1); +} + +#endif /* _MSC_VER */ void uv__async_endgame(uv_loop_t* loop, uv_async_t* handle) { if (handle->flags & UV_HANDLE_CLOSING && diff --git a/src/win/atomicops-inl.h b/src/win/atomicops-inl.h deleted file mode 100644 index 2f984c6d..00000000 --- a/src/win/atomicops-inl.h +++ /dev/null @@ -1,61 +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. - */ - -#ifndef UV_WIN_ATOMICOPS_INL_H_ -#define UV_WIN_ATOMICOPS_INL_H_ - -#include "uv.h" -#include "internal.h" - - -/* Atomic set operation on char */ -#ifdef _MSC_VER /* MSVC */ - -/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less - * efficient than InterlockedExchange, but InterlockedExchange8 does not exist, - * and interlocked operations on larger targets might require the target to be - * aligned. */ -#pragma intrinsic(_InterlockedOr8) - -static char INLINE uv__atomic_exchange_set(char volatile* target) { - return _InterlockedOr8(target, 1); -} - -#else /* GCC, Clang in mingw mode */ - -static inline char uv__atomic_exchange_set(char volatile* target) { -#if defined(__i386__) || defined(__x86_64__) - /* Mingw-32 version, hopefully this works for 64-bit gcc as well. */ - const char one = 1; - char old_value; - __asm__ __volatile__ ("lock xchgb %0, %1\n\t" - : "=r"(old_value), "=m"(*target) - : "0"(one), "m"(*target) - : "memory"); - return old_value; -#else - return __sync_fetch_and_or(target, 1); -#endif -} - -#endif - -#endif /* UV_WIN_ATOMICOPS_INL_H_ */ diff --git a/src/win/core.c b/src/win/core.c index 5f41c87a..317238fd 100644 --- a/src/win/core.c +++ b/src/win/core.c @@ -428,6 +428,7 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { BOOL success; uv_req_t* req; OVERLAPPED_ENTRY overlappeds[128]; + OVERLAPPED* overlapped; ULONG count; ULONG i; int repeat; @@ -491,7 +492,8 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { if (actual_timeout == 0) uv__metrics_inc_events_waiting(loop, 1); - req = uv__overlapped_to_req(overlappeds[i].lpOverlapped); + overlapped = overlappeds[i].lpOverlapped; + req = container_of(overlapped, uv_req_t, u.io.overlapped); uv__insert_pending_req(loop, req); } } @@ -525,6 +527,177 @@ static void uv__poll(uv_loop_t* loop, DWORD timeout) { } +#define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \ + do { \ + switch (((uv_handle_t*) (req)->handle_at)->type) { \ + case UV_TCP: \ + uv__process_tcp_##method##_req(loop, \ + (uv_tcp_t*) ((req)->handle_at), \ + req); \ + break; \ + \ + case UV_NAMED_PIPE: \ + uv__process_pipe_##method##_req(loop, \ + (uv_pipe_t*) ((req)->handle_at), \ + req); \ + break; \ + \ + case UV_TTY: \ + uv__process_tty_##method##_req(loop, \ + (uv_tty_t*) ((req)->handle_at), \ + req); \ + break; \ + \ + default: \ + assert(0); \ + } \ + } while (0) + + +static void uv__process_reqs(uv_loop_t* loop) { + uv_req_t* req; + uv_req_t* first; + uv_req_t* next; + + if (loop->pending_reqs_tail == NULL) + return; + + first = loop->pending_reqs_tail->next_req; + next = first; + loop->pending_reqs_tail = NULL; + + while (next != NULL) { + req = next; + next = req->next_req != first ? req->next_req : NULL; + + switch (req->type) { + case UV_READ: + DELEGATE_STREAM_REQ(loop, req, read, data); + break; + + case UV_WRITE: + DELEGATE_STREAM_REQ(loop, (uv_write_t*) req, write, handle); + break; + + case UV_ACCEPT: + DELEGATE_STREAM_REQ(loop, req, accept, data); + break; + + case UV_CONNECT: + DELEGATE_STREAM_REQ(loop, (uv_connect_t*) req, connect, handle); + break; + + case UV_SHUTDOWN: + DELEGATE_STREAM_REQ(loop, (uv_shutdown_t*) req, shutdown, handle); + break; + + case UV_UDP_RECV: + uv__process_udp_recv_req(loop, (uv_udp_t*) req->data, req); + break; + + case UV_UDP_SEND: + uv__process_udp_send_req(loop, + ((uv_udp_send_t*) req)->handle, + (uv_udp_send_t*) req); + break; + + case UV_WAKEUP: + uv__process_async_wakeup_req(loop, (uv_async_t*) req->data, req); + break; + + case UV_SIGNAL_REQ: + uv__process_signal_req(loop, (uv_signal_t*) req->data, req); + break; + + case UV_POLL_REQ: + uv__process_poll_req(loop, (uv_poll_t*) req->data, req); + break; + + case UV_PROCESS_EXIT: + uv__process_proc_exit(loop, (uv_process_t*) req->data); + break; + + case UV_FS_EVENT_REQ: + uv__process_fs_event_req(loop, req, (uv_fs_event_t*) req->data); + break; + + default: + assert(0); + } + } +} + +#undef DELEGATE_STREAM_REQ + +static void uv__process_endgames(uv_loop_t* loop) { + uv_handle_t* handle; + + while (loop->endgame_handles) { + handle = loop->endgame_handles; + loop->endgame_handles = handle->endgame_next; + + handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED; + + switch (handle->type) { + case UV_TCP: + uv__tcp_endgame(loop, (uv_tcp_t*) handle); + break; + + case UV_NAMED_PIPE: + uv__pipe_endgame(loop, (uv_pipe_t*) handle); + break; + + case UV_TTY: + uv__tty_endgame(loop, (uv_tty_t*) handle); + break; + + case UV_UDP: + uv__udp_endgame(loop, (uv_udp_t*) handle); + break; + + case UV_POLL: + uv__poll_endgame(loop, (uv_poll_t*) handle); + break; + + case UV_TIMER: + uv__timer_close((uv_timer_t*) handle); + uv__handle_close(handle); + break; + + case UV_PREPARE: + case UV_CHECK: + case UV_IDLE: + uv__loop_watcher_endgame(loop, handle); + break; + + case UV_ASYNC: + uv__async_endgame(loop, (uv_async_t*) handle); + break; + + case UV_SIGNAL: + uv__signal_endgame(loop, (uv_signal_t*) handle); + break; + + case UV_PROCESS: + uv__process_endgame(loop, (uv_process_t*) handle); + break; + + case UV_FS_EVENT: + uv__fs_event_endgame(loop, (uv_fs_event_t*) handle); + break; + + case UV_FS_POLL: + uv__fs_poll_endgame(loop, (uv_fs_poll_t*) handle); + break; + + default: + assert(0); + break; + } + } +} + + int uv_run(uv_loop_t *loop, uv_run_mode mode) { DWORD timeout; int r; @@ -681,3 +854,26 @@ int uv__getsockpeername(const uv_handle_t* handle, return 0; } + +void uv__insert_pending_req(uv_loop_t* loop, uv_req_t* req) { + req->next_req = NULL; + if (loop->pending_reqs_tail) { +#ifdef _DEBUG + /* Ensure the request is not already in the queue, or the queue + * will get corrupted. + */ + uv_req_t* current = loop->pending_reqs_tail; + do { + assert(req != current); + current = current->next_req; + } while (current != loop->pending_reqs_tail); +#endif + + req->next_req = loop->pending_reqs_tail->next_req; + loop->pending_reqs_tail->next_req = req; + loop->pending_reqs_tail = req; + } else { + req->next_req = req; + loop->pending_reqs_tail = req; + } +} diff --git a/src/win/fs-fd-hash-inl.h b/src/win/fs-fd-hash-inl.h index 0b532af1..fd875d28 100644 --- a/src/win/fs-fd-hash-inl.h +++ b/src/win/fs-fd-hash-inl.h @@ -73,7 +73,7 @@ static struct uv__fd_hash_entry_group_s static struct uv__fd_hash_bucket_s uv__fd_hash[UV__FD_HASH_SIZE]; -INLINE static void uv__fd_hash_init(void) { +static void uv__fd_hash_init(void) { size_t i; int err; @@ -119,7 +119,7 @@ INLINE static void uv__fd_hash_init(void) { FIND_IN_GROUP_PTR(UV__FD_HASH_GROUP_SIZE); \ } while (0) -INLINE static int uv__fd_hash_get(int fd, struct uv__fd_info_s* info) { +static int uv__fd_hash_get(int fd, struct uv__fd_info_s* info) { FIND_COMMON_VARIABLES uv_mutex_lock(&uv__fd_hash_mutex); @@ -134,7 +134,7 @@ INLINE static int uv__fd_hash_get(int fd, struct uv__fd_info_s* info) { return entry_ptr != NULL; } -INLINE static void uv__fd_hash_add(int fd, struct uv__fd_info_s* info) { +static void uv__fd_hash_add(int fd, struct uv__fd_info_s* info) { FIND_COMMON_VARIABLES uv_mutex_lock(&uv__fd_hash_mutex); @@ -164,7 +164,7 @@ INLINE static void uv__fd_hash_add(int fd, struct uv__fd_info_s* info) { uv_mutex_unlock(&uv__fd_hash_mutex); } -INLINE static int uv__fd_hash_remove(int fd, struct uv__fd_info_s* info) { +static int uv__fd_hash_remove(int fd, struct uv__fd_info_s* info) { FIND_COMMON_VARIABLES uv_mutex_lock(&uv__fd_hash_mutex); diff --git a/src/win/fs.c b/src/win/fs.c index 27248f64..4e156930 100644 --- a/src/win/fs.c +++ b/src/win/fs.c @@ -167,9 +167,10 @@ typedef enum { FS__STAT_PATH_TRY_SLOW } fs__stat_path_return_t; -INLINE static void fs__stat_assign_statbuf_null(uv_stat_t* statbuf); -INLINE static void fs__stat_assign_statbuf(uv_stat_t* statbuf, - FILE_STAT_BASIC_INFORMATION stat_info, int do_lstat); +static void fs__stat_assign_statbuf_null(uv_stat_t* statbuf); +static void fs__stat_assign_statbuf(uv_stat_t* statbuf, + FILE_STAT_BASIC_INFORMATION stat_info, + int do_lstat); void uv__fs_init(void) { @@ -182,9 +183,9 @@ void uv__fs_init(void) { } -INLINE static int fs__readlink_handle(HANDLE handle, - char** target_ptr, - size_t* target_len_ptr) { +static int fs__readlink_handle(HANDLE handle, + char** target_ptr, + size_t* target_len_ptr) { char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer; WCHAR* w_target; @@ -319,8 +320,10 @@ INLINE static int fs__readlink_handle(HANDLE handle, } -INLINE static int fs__capture_path(uv_fs_t* req, const char* path, - const char* new_path, const int copy_path) { +static int fs__capture_path(uv_fs_t* req, + const char* path, + const char* new_path, + const int copy_path) { WCHAR* buf; WCHAR* pos; size_t buf_sz = 0; @@ -394,8 +397,10 @@ INLINE static int fs__capture_path(uv_fs_t* req, const char* path, } -INLINE static void uv__fs_req_init(uv_loop_t* loop, uv_fs_t* req, - uv_fs_type fs_type, const uv_fs_cb cb) { +static void uv__fs_req_init(uv_loop_t* loop, + uv_fs_t* req, + uv_fs_type fs_type, + const uv_fs_cb cb) { uv__once_init(); UV_REQ_INIT(req, UV_FS); req->loop = loop; @@ -1698,8 +1703,9 @@ void fs__closedir(uv_fs_t* req) { SET_REQ_RESULT(req, 0); } -INLINE static fs__stat_path_return_t fs__stat_path(WCHAR* path, - uv_stat_t* statbuf, int do_lstat) { +static fs__stat_path_return_t fs__stat_path(WCHAR* path, + uv_stat_t* statbuf, + int do_lstat) { FILE_STAT_BASIC_INFORMATION stat_info; /* Check if the new fast API is available. */ @@ -1735,8 +1741,7 @@ INLINE static fs__stat_path_return_t fs__stat_path(WCHAR* path, return FS__STAT_PATH_SUCCESS; } -INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, - int do_lstat) { +static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, int do_lstat) { size_t target_length = 0; FILE_FS_DEVICE_INFORMATION device_info; FILE_ALL_INFORMATION file_info; @@ -1827,7 +1832,7 @@ INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf, return 0; } -INLINE static void fs__stat_assign_statbuf_null(uv_stat_t* statbuf) { +static void fs__stat_assign_statbuf_null(uv_stat_t* statbuf) { memset(statbuf, 0, sizeof(uv_stat_t)); statbuf->st_mode = _S_IFCHR; statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) | @@ -1837,8 +1842,9 @@ INLINE static void fs__stat_assign_statbuf_null(uv_stat_t* statbuf) { statbuf->st_rdev = FILE_DEVICE_NULL << 16; } -INLINE static void fs__stat_assign_statbuf(uv_stat_t* statbuf, - FILE_STAT_BASIC_INFORMATION stat_info, int do_lstat) { +static void fs__stat_assign_statbuf(uv_stat_t* statbuf, + FILE_STAT_BASIC_INFORMATION stat_info, + int do_lstat) { statbuf->st_dev = stat_info.VolumeSerialNumber.LowPart; /* Todo: st_mode should probably always be 0666 for everyone. We might also @@ -1943,18 +1949,19 @@ INLINE static void fs__stat_assign_statbuf(uv_stat_t* statbuf, } -INLINE static void fs__stat_prepare_path(WCHAR* pathw) { +static void fs__stat_prepare_path(WCHAR* pathw) { size_t len = wcslen(pathw); - /* TODO: ignore namespaced paths. */ if (len > 1 && pathw[len - 2] != L':' && (pathw[len - 1] == L'\\' || pathw[len - 1] == L'/')) { pathw[len - 1] = '\0'; } } -INLINE static DWORD fs__stat_directory(WCHAR* path, uv_stat_t* statbuf, - int do_lstat, DWORD ret_error) { +static DWORD fs__stat_directory(WCHAR* path, + uv_stat_t* statbuf, + int do_lstat, + DWORD ret_error) { HANDLE handle = INVALID_HANDLE_VALUE; FILE_STAT_BASIC_INFORMATION stat_info; FILE_ID_FULL_DIR_INFORMATION dir_info; @@ -2127,9 +2134,9 @@ cleanup: return ret_error; } -INLINE static DWORD fs__stat_impl_from_path(WCHAR* path, - int do_lstat, - uv_stat_t* statbuf) { +static DWORD fs__stat_impl_from_path(WCHAR* path, + int do_lstat, + uv_stat_t* statbuf) { HANDLE handle; DWORD flags; DWORD ret; @@ -2174,7 +2181,7 @@ INLINE static DWORD fs__stat_impl_from_path(WCHAR* path, } -INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) { +static void fs__stat_impl(uv_fs_t* req, int do_lstat) { DWORD error; error = fs__stat_impl_from_path(req->file.pathw, do_lstat, &req->statbuf); @@ -2197,7 +2204,7 @@ INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) { } -INLINE static int fs__fstat_handle(int fd, HANDLE handle, uv_stat_t* statbuf) { +static int fs__fstat_handle(int fd, HANDLE handle, uv_stat_t* statbuf) { DWORD file_type; /* Each file type is processed differently. */ @@ -2273,7 +2280,7 @@ static void fs__rename(uv_fs_t* req) { } -INLINE static void fs__sync_impl(uv_fs_t* req) { +static void fs__sync_impl(uv_fs_t* req) { int fd = req->file.fd; int result; @@ -2579,7 +2586,7 @@ fchmod_cleanup: } -INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) { +static int fs__utime_handle(HANDLE handle, double atime, double mtime) { FILETIME filetime_as, *filetime_a = &filetime_as; FILETIME filetime_ms, *filetime_m = &filetime_ms; FILETIME now; @@ -2607,10 +2614,10 @@ INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) { return 0; } -INLINE static DWORD fs__utime_impl_from_path(WCHAR* path, - double atime, - double mtime, - int do_lutime) { +static DWORD fs__utime_impl_from_path(WCHAR* path, + double atime, + double mtime, + int do_lutime) { HANDLE handle; DWORD flags; DWORD ret; @@ -2640,7 +2647,7 @@ INLINE static DWORD fs__utime_impl_from_path(WCHAR* path, return ret; } -INLINE static void fs__utime_impl(uv_fs_t* req, int do_lutime) { +static void fs__utime_impl(uv_fs_t* req, int do_lutime) { DWORD error; error = fs__utime_impl_from_path(req->file.pathw, diff --git a/src/win/handle-inl.h b/src/win/handle-inl.h index 4722e857..e30d148c 100644 --- a/src/win/handle-inl.h +++ b/src/win/handle-inl.h @@ -95,74 +95,6 @@ INLINE static void uv__want_endgame(uv_loop_t* loop, uv_handle_t* handle) { } -INLINE static void uv__process_endgames(uv_loop_t* loop) { - uv_handle_t* handle; - - while (loop->endgame_handles) { - handle = loop->endgame_handles; - loop->endgame_handles = handle->endgame_next; - - handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED; - - switch (handle->type) { - case UV_TCP: - uv__tcp_endgame(loop, (uv_tcp_t*) handle); - break; - - case UV_NAMED_PIPE: - uv__pipe_endgame(loop, (uv_pipe_t*) handle); - break; - - case UV_TTY: - uv__tty_endgame(loop, (uv_tty_t*) handle); - break; - - case UV_UDP: - uv__udp_endgame(loop, (uv_udp_t*) handle); - break; - - case UV_POLL: - uv__poll_endgame(loop, (uv_poll_t*) handle); - break; - - case UV_TIMER: - uv__timer_close((uv_timer_t*) handle); - uv__handle_close(handle); - break; - - case UV_PREPARE: - case UV_CHECK: - case UV_IDLE: - uv__loop_watcher_endgame(loop, handle); - break; - - case UV_ASYNC: - uv__async_endgame(loop, (uv_async_t*) handle); - break; - - case UV_SIGNAL: - uv__signal_endgame(loop, (uv_signal_t*) handle); - break; - - case UV_PROCESS: - uv__process_endgame(loop, (uv_process_t*) handle); - break; - - case UV_FS_EVENT: - uv__fs_event_endgame(loop, (uv_fs_event_t*) handle); - break; - - case UV_FS_POLL: - uv__fs_poll_endgame(loop, (uv_fs_poll_t*) handle); - break; - - default: - assert(0); - break; - } - } -} - INLINE static HANDLE uv__get_osfhandle(int fd) { /* _get_osfhandle() raises an assert in debug builds if the FD is invalid. diff --git a/src/win/pipe.c b/src/win/pipe.c index d05bfd28..8f86a1fe 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -2149,7 +2149,8 @@ void uv__process_pipe_read_req(uv_loop_t* loop, } else { /* The zero-read completed without error, indicating there is data * available in the kernel buffer. */ - while (handle->flags & UV_HANDLE_READING) { + while (handle->flags & UV_HANDLE_READING && + !(handle->flags & UV_HANDLE_READ_PENDING)) { bytes_requested = 65536; /* Depending on the type of pipe, read either IPC frames or raw data. */ if (handle->ipc) diff --git a/src/win/poll.c b/src/win/poll.c index 7fec2b99..a20867a9 100644 --- a/src/win/poll.c +++ b/src/win/poll.c @@ -211,15 +211,11 @@ static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp, protocol_info->iProtocol, protocol_info, 0, - WSA_FLAG_OVERLAPPED); + WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT); if (sock == INVALID_SOCKET) { return INVALID_SOCKET; } - if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) { - goto error; - }; - if (CreateIoCompletionPort((HANDLE) sock, iocp, (ULONG_PTR) sock, diff --git a/src/win/req-inl.h b/src/win/req-inl.h index cf16e8ba..af6fb752 100644 --- a/src/win/req-inl.h +++ b/src/win/req-inl.h @@ -81,134 +81,6 @@ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); \ } - -INLINE static uv_req_t* uv__overlapped_to_req(OVERLAPPED* overlapped) { - return container_of(overlapped, uv_req_t, u.io.overlapped); -} - - -INLINE static void uv__insert_pending_req(uv_loop_t* loop, uv_req_t* req) { - req->next_req = NULL; - if (loop->pending_reqs_tail) { -#ifdef _DEBUG - /* Ensure the request is not already in the queue, or the queue - * will get corrupted. - */ - uv_req_t* current = loop->pending_reqs_tail; - do { - assert(req != current); - current = current->next_req; - } while(current != loop->pending_reqs_tail); -#endif - - req->next_req = loop->pending_reqs_tail->next_req; - loop->pending_reqs_tail->next_req = req; - loop->pending_reqs_tail = req; - } else { - req->next_req = req; - loop->pending_reqs_tail = req; - } -} - - -#define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \ - do { \ - switch (((uv_handle_t*) (req)->handle_at)->type) { \ - case UV_TCP: \ - uv__process_tcp_##method##_req(loop, \ - (uv_tcp_t*) ((req)->handle_at), \ - req); \ - break; \ - \ - case UV_NAMED_PIPE: \ - uv__process_pipe_##method##_req(loop, \ - (uv_pipe_t*) ((req)->handle_at), \ - req); \ - break; \ - \ - case UV_TTY: \ - uv__process_tty_##method##_req(loop, \ - (uv_tty_t*) ((req)->handle_at), \ - req); \ - break; \ - \ - default: \ - assert(0); \ - } \ - } while (0) - - -INLINE static void uv__process_reqs(uv_loop_t* loop) { - uv_req_t* req; - uv_req_t* first; - uv_req_t* next; - - if (loop->pending_reqs_tail == NULL) - return; - - first = loop->pending_reqs_tail->next_req; - next = first; - loop->pending_reqs_tail = NULL; - - while (next != NULL) { - req = next; - next = req->next_req != first ? req->next_req : NULL; - - switch (req->type) { - case UV_READ: - DELEGATE_STREAM_REQ(loop, req, read, data); - break; - - case UV_WRITE: - DELEGATE_STREAM_REQ(loop, (uv_write_t*) req, write, handle); - break; - - case UV_ACCEPT: - DELEGATE_STREAM_REQ(loop, req, accept, data); - break; - - case UV_CONNECT: - DELEGATE_STREAM_REQ(loop, (uv_connect_t*) req, connect, handle); - break; - - case UV_SHUTDOWN: - DELEGATE_STREAM_REQ(loop, (uv_shutdown_t*) req, shutdown, handle); - break; - - case UV_UDP_RECV: - uv__process_udp_recv_req(loop, (uv_udp_t*) req->data, req); - break; - - case UV_UDP_SEND: - uv__process_udp_send_req(loop, - ((uv_udp_send_t*) req)->handle, - (uv_udp_send_t*) req); - break; - - case UV_WAKEUP: - uv__process_async_wakeup_req(loop, (uv_async_t*) req->data, req); - break; - - case UV_SIGNAL_REQ: - uv__process_signal_req(loop, (uv_signal_t*) req->data, req); - break; - - case UV_POLL_REQ: - uv__process_poll_req(loop, (uv_poll_t*) req->data, req); - break; - - case UV_PROCESS_EXIT: - uv__process_proc_exit(loop, (uv_process_t*) req->data); - break; - - case UV_FS_EVENT_REQ: - uv__process_fs_event_req(loop, req, (uv_fs_event_t*) req->data); - break; - - default: - assert(0); - } - } -} +void uv__insert_pending_req(uv_loop_t* loop, uv_req_t* req); #endif /* UV_WIN_REQ_INL_H_ */ diff --git a/src/win/tcp.c b/src/win/tcp.c index c452c12e..5b7604a9 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -49,29 +49,99 @@ static int uv__tcp_nodelay(uv_tcp_t* handle, SOCKET socket, int enable) { } -static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsigned int delay) { +/* + * Check if Windows version is 10.0.16299 (Windows 10, version 1709) or later. + */ +static int minimal_windows10_version1709(void) { + OSVERSIONINFOW os_info; + if (!pRtlGetVersion) + return 0; + pRtlGetVersion(&os_info); + if (os_info.dwMajorVersion < 10) + return 0; + if (os_info.dwMajorVersion > 10) + return 1; + if (os_info.dwMinorVersion > 0) + return 1; + return os_info.dwBuildNumber >= 16299; +} + + +static int uv__tcp_keepalive(uv_tcp_t* handle, + SOCKET socket, + int on, + unsigned int idle, + unsigned int intvl, + unsigned int cnt) { if (setsockopt(socket, SOL_SOCKET, SO_KEEPALIVE, - (const char*)&enable, - sizeof enable) == -1) { + (const char*)&on, + sizeof on) == -1) { return WSAGetLastError(); } - if (!enable) + if (!on) return 0; - if (delay < 1) + if (idle < 1 || intvl < 1 || cnt < 1) return UV_EINVAL; - if (setsockopt(socket, - IPPROTO_TCP, - TCP_KEEPALIVE, - (const char*)&delay, - sizeof delay) == -1) { - return WSAGetLastError(); + /* Windows 10, version 1709 (build 10.0.16299) and later require second units + * for TCP keepalive options. */ + if (minimal_windows10_version1709()) { + if (setsockopt(socket, + IPPROTO_TCP, + TCP_KEEPIDLE, + (const char*)&idle, + sizeof idle) == -1) { + return WSAGetLastError(); + } + + if (setsockopt(socket, + IPPROTO_TCP, + TCP_KEEPINTVL, + (const char*)&intvl, + sizeof intvl) == -1) { + return WSAGetLastError(); + } + + if (setsockopt(socket, + IPPROTO_TCP, + TCP_KEEPCNT, + (const char*)&cnt, + sizeof cnt) == -1) { + return WSAGetLastError(); + } + + return 0; } + /* For those versions prior to Windows 10 version 1709, + * we fall back to SIO_KEEPALIVE_VALS that expects millisecond units. + * The SIO_KEEPALIVE_VALS IOCTL is supported on Windows 2000 + * and later versions of the operating system. */ + struct tcp_keepalive keepalive; + keepalive.onoff = on; + keepalive.keepalivetime = idle * 1000; + keepalive.keepaliveinterval = intvl * 1000; + /* On Windows Vista and later, the number of keep-alive probes + * (data retransmissions) is set to 10 and cannot be changed. + * On Windows Server 2003, Windows XP, and Windows 2000, the default setting + * for number of keep-alive probes is 5 and cannot be changed programmatically. + */ + DWORD dummy; + if (WSAIoctl(socket, + SIO_KEEPALIVE_VALS, + (LPVOID) &keepalive, + sizeof keepalive, + NULL, + 0, + &dummy, + NULL, + NULL) == -1) + return WSAGetLastError(); + return 0; } @@ -132,7 +202,7 @@ static int uv__tcp_set_socket(uv_loop_t* loop, /* TODO: Use stored delay. */ if (handle->flags & UV_HANDLE_TCP_KEEPALIVE) { - err = uv__tcp_keepalive(handle, socket, 1, 60); + err = uv__tcp_keepalive(handle, socket, 1, 60, 1, 10); if (err) return err; } @@ -749,20 +819,6 @@ static int uv__is_loopback(const struct sockaddr_storage* storage) { return 0; } -// Check if Windows version is 10.0.16299 or later -static int uv__is_fast_loopback_fail_supported(void) { - OSVERSIONINFOW os_info; - if (!pRtlGetVersion) - return 0; - pRtlGetVersion(&os_info); - if (os_info.dwMajorVersion < 10) - return 0; - if (os_info.dwMajorVersion > 10) - return 1; - if (os_info.dwMinorVersion > 0) - return 1; - return os_info.dwBuildNumber >= 16299; -} static int uv__tcp_try_connect(uv_connect_t* req, uv_tcp_t* handle, @@ -809,7 +865,7 @@ static int uv__tcp_try_connect(uv_connect_t* req, * is not reachable, instead of waiting for 2s. We do not care if this fails. * This only works on Windows version 10.0.16299 and later. */ - if (uv__is_fast_loopback_fail_supported() && uv__is_loopback(&converted)) { + if (minimal_windows10_version1709() && uv__is_loopback(&converted)) { memset(&retransmit_ioctl, 0, sizeof(retransmit_ioctl)); retransmit_ioctl.Rtt = TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS; retransmit_ioctl.MaxSynRetransmissions = TCP_INITIAL_RTO_NO_SYN_RETRANSMISSIONS; @@ -1335,22 +1391,30 @@ int uv_tcp_nodelay(uv_tcp_t* handle, int enable) { } -int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) { +int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int idle) { + return uv_tcp_keepalive_ex(handle, on, idle, 1, 10); +} + +int uv_tcp_keepalive_ex(uv_tcp_t* handle, + int on, + unsigned int idle, + unsigned int intvl, + unsigned int cnt) { int err; if (handle->socket != INVALID_SOCKET) { - err = uv__tcp_keepalive(handle, handle->socket, enable, delay); + err = uv__tcp_keepalive(handle, handle->socket, on, idle, intvl, cnt); if (err) return uv_translate_sys_error(err); } - if (enable) { + if (on) { handle->flags |= UV_HANDLE_TCP_KEEPALIVE; } else { handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE; } - /* TODO: Store delay if handle->socket isn't created yet. */ + /* TODO: Store idle if handle->socket isn't created yet. */ return 0; } diff --git a/src/win/thread.c b/src/win/thread.c index 753cb6a3..9c38e3d8 100644 --- a/src/win/thread.c +++ b/src/win/thread.c @@ -284,7 +284,7 @@ int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) { static void uv__thread_name_init_once(void) { HMODULE m; - m = GetModuleHandleA("api-ms-win-core-processthreads-l1-1-3.dll"); + m = GetModuleHandleW(L"api-ms-win-core-processthreads-l1-1-3.dll"); if (m != NULL) { pGetThreadDescription = (void*) GetProcAddress(m, "GetThreadDescription"); pSetThreadDescription = (void*) GetProcAddress(m, "SetThreadDescription"); diff --git a/src/win/util.c b/src/win/util.c index da1238d3..8c2681fe 100644 --- a/src/win/util.c +++ b/src/win/util.c @@ -378,10 +378,15 @@ done: static int uv__get_process_title(void) { WCHAR title_w[MAX_TITLE_LENGTH]; DWORD wlen; + DWORD err; + SetLastError(ERROR_SUCCESS); wlen = GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR)); - if (wlen == 0) - return uv_translate_sys_error(GetLastError()); + if (wlen == 0) { + err = GetLastError(); + if (err != 0) + return uv_translate_sys_error(err); + } return uv__convert_utf16_to_utf8(title_w, wlen, &process_title); } @@ -867,12 +872,6 @@ int uv_interface_addresses(uv_interface_address_t** addresses_ptr, } -void uv_free_interface_addresses(uv_interface_address_t* addresses, - int count) { - uv__free(addresses); -} - - int uv_getrusage(uv_rusage_t *uv_rusage) { FILETIME create_time, exit_time, kernel_time, user_time; SYSTEMTIME kernel_system_time, user_system_time; diff --git a/src/win/winapi.c b/src/win/winapi.c index 315a0d49..786a9daa 100644 --- a/src/win/winapi.c +++ b/src/win/winapi.c @@ -55,9 +55,9 @@ void uv__winapi_init(void) { HMODULE ws2_32_module; HMODULE api_win_core_file_module; - ntdll_module = GetModuleHandleA("ntdll.dll"); + ntdll_module = GetModuleHandleW(L"ntdll.dll"); if (ntdll_module == NULL) { - uv_fatal_error(GetLastError(), "GetModuleHandleA"); + uv_fatal_error(GetLastError(), "GetModuleHandleW"); } pRtlGetVersion = (sRtlGetVersion) GetProcAddress(ntdll_module, @@ -123,20 +123,20 @@ void uv__winapi_init(void) { GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification"); } - user32_module = GetModuleHandleA("user32.dll"); + user32_module = GetModuleHandleW(L"user32.dll"); if (user32_module != NULL) { pSetWinEventHook = (sSetWinEventHook) GetProcAddress(user32_module, "SetWinEventHook"); } - ws2_32_module = GetModuleHandleA("ws2_32.dll"); + ws2_32_module = GetModuleHandleW(L"ws2_32.dll"); if (ws2_32_module != NULL) { pGetHostNameW = (uv_sGetHostNameW) GetProcAddress( ws2_32_module, "GetHostNameW"); } - api_win_core_file_module = GetModuleHandleA("api-ms-win-core-file-l2-1-4.dll"); + api_win_core_file_module = GetModuleHandleW(L"api-ms-win-core-file-l2-1-4.dll"); if (api_win_core_file_module != NULL) { pGetFileInformationByName = (sGetFileInformationByName)GetProcAddress( api_win_core_file_module, "GetFileInformationByName"); diff --git a/src/win/winsock.h b/src/win/winsock.h index bb3808a3..e14b8b51 100644 --- a/src/win/winsock.h +++ b/src/win/winsock.h @@ -38,10 +38,6 @@ # define SO_UPDATE_CONNECT_CONTEXT 0x7010 #endif -#ifndef TCP_KEEPALIVE -# define TCP_KEEPALIVE 3 -#endif - #ifndef IPV6_V6ONLY # define IPV6_V6ONLY 27 #endif @@ -62,6 +58,30 @@ # define MCAST_LEAVE_SOURCE_GROUP 46 #endif +#ifndef SIO_KEEPALIVE_VALS +#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4) +struct tcp_keepalive { + u_long onoff; + u_long keepalivetime; + u_long keepaliveinterval; +}; +#endif + +/* + * TCP keepalive definitions on MinGW are located in <netinet/tcp.h>. + */ +#ifndef TCP_KEEPIDLE +#define TCP_KEEPIDLE 0x03 /* start keepalives after this period */ +#endif + +#ifndef TCP_KEEPINTVL +#define TCP_KEEPINTVL 0x11 /* interval between keepalives */ +#endif + +#ifndef TCP_KEEPCNT +#define TCP_KEEPCNT 0x10 /* number of keepalives before death */ +#endif + /* * TDI defines that are only in the DDK. * We only need receive flags so far. |