aboutsummaryrefslogtreecommitdiff
path: root/src/win
diff options
context:
space:
mode:
Diffstat (limited to 'src/win')
-rw-r--r--src/win/async.c20
-rw-r--r--src/win/atomicops-inl.h61
-rw-r--r--src/win/core.c198
-rw-r--r--src/win/fs-fd-hash-inl.h8
-rw-r--r--src/win/fs.c73
-rw-r--r--src/win/handle-inl.h68
-rw-r--r--src/win/pipe.c3
-rw-r--r--src/win/poll.c6
-rw-r--r--src/win/req-inl.h130
-rw-r--r--src/win/tcp.c126
-rw-r--r--src/win/thread.c2
-rw-r--r--src/win/util.c15
-rw-r--r--src/win/winapi.c10
-rw-r--r--src/win/winsock.h28
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.