summaryrefslogtreecommitdiff
path: root/deps/uv/src/win
diff options
context:
space:
mode:
Diffstat (limited to 'deps/uv/src/win')
-rw-r--r--deps/uv/src/win/core.c161
-rw-r--r--deps/uv/src/win/error.c1
-rw-r--r--deps/uv/src/win/fs.c177
-rw-r--r--deps/uv/src/win/getaddrinfo.c63
-rw-r--r--deps/uv/src/win/getnameinfo.c61
-rw-r--r--deps/uv/src/win/internal.h35
-rw-r--r--deps/uv/src/win/pipe.c64
-rw-r--r--deps/uv/src/win/process.c280
-rw-r--r--deps/uv/src/win/req-inl.h16
-rw-r--r--deps/uv/src/win/stream-inl.h11
-rw-r--r--deps/uv/src/win/tcp.c65
-rw-r--r--deps/uv/src/win/threadpool.c81
-rw-r--r--deps/uv/src/win/timer.c50
-rw-r--r--deps/uv/src/win/tty.c4
-rw-r--r--deps/uv/src/win/udp.c27
15 files changed, 655 insertions, 441 deletions
diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c
index 540fb5fa0d..c39597561d 100644
--- a/deps/uv/src/win/core.c
+++ b/deps/uv/src/win/core.c
@@ -26,7 +26,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#if !defined(__MINGW32__)
+#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
#include <crtdbg.h>
#endif
@@ -44,19 +44,21 @@ static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
static uv_once_t uv_default_loop_init_guard_ = UV_ONCE_INIT;
-#if defined(_DEBUG) && !defined(__MINGW32__)
-/* Our crt debug report handler allows us to temporarily disable asserts */
-/* just for the current thread. */
+#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
+/* Our crt debug report handler allows us to temporarily disable asserts
+ * just for the current thread.
+ */
-__declspec( thread ) int uv__crt_assert_enabled = TRUE;
+UV_THREAD_LOCAL int uv__crt_assert_enabled = TRUE;
static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_val) {
if (uv__crt_assert_enabled || report_type != _CRT_ASSERT)
return FALSE;
if (ret_val) {
- /* Set ret_val to 0 to continue with normal execution. */
- /* Set ret_val to 1 to trigger a breakpoint. */
+ /* Set ret_val to 0 to continue with normal execution.
+ * Set ret_val to 1 to trigger a breakpoint.
+ */
if(IsDebuggerPresent())
*ret_val = 1;
@@ -67,6 +69,8 @@ static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_v
/* Don't call _CrtDbgReport. */
return TRUE;
}
+#else
+UV_THREAD_LOCAL int uv__crt_assert_enabled = FALSE;
#endif
@@ -84,21 +88,24 @@ static void uv_init(void) {
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
SEM_NOOPENFILEERRORBOX);
- /* Tell the CRT to not exit the application when an invalid parameter is */
- /* passed. The main issue is that invalid FDs will trigger this behavior. */
+ /* Tell the CRT to not exit the application when an invalid parameter is
+ * passed. The main issue is that invalid FDs will trigger this behavior.
+ */
#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
_set_invalid_parameter_handler(uv__crt_invalid_parameter_handler);
#endif
- /* We also need to setup our debug report handler because some CRT */
- /* functions (eg _get_osfhandle) raise an assert when called with invalid */
- /* FDs even though they return the proper error code in the release build. */
-#if defined(_DEBUG) && !defined(__MINGW32__)
+ /* We also need to setup our debug report handler because some CRT
+ * functions (eg _get_osfhandle) raise an assert when called with invalid
+ * FDs even though they return the proper error code in the release build.
+ */
+#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
_CrtSetReportHook(uv__crt_dbg_report_handler);
#endif
- /* Fetch winapi function pointers. This must be done first because other */
- /* intialization code might need these function pointers to be loaded. */
+ /* Fetch winapi function pointers. This must be done first because other
+ * intialization code might need these function pointers to be loaded.
+ */
uv_winapi_init();
/* Initialize winsock */
@@ -127,12 +134,14 @@ int uv_loop_init(uv_loop_t* loop) {
if (loop->iocp == NULL)
return uv_translate_sys_error(GetLastError());
- /* To prevent uninitialized memory access, loop->time must be intialized */
- /* to zero before calling uv_update_time for the first time. */
+ /* To prevent uninitialized memory access, loop->time must be intialized
+ * to zero before calling uv_update_time for the first time.
+ */
loop->time = 0;
loop->last_tick_count = 0;
uv_update_time(loop);
+ QUEUE_INIT(&loop->wq);
QUEUE_INIT(&loop->handle_queue);
QUEUE_INIT(&loop->active_reqs);
loop->active_handles = 0;
@@ -159,6 +168,15 @@ int uv_loop_init(uv_loop_t* loop) {
loop->timer_counter = 0;
loop->stop_flag = 0;
+ if (uv_mutex_init(&loop->wq_mutex))
+ abort();
+
+ if (uv_async_init(loop, &loop->wq_async, uv__work_done))
+ abort();
+
+ uv__handle_unref(&loop->wq_async);
+ loop->wq_async.flags |= UV__HANDLE_INTERNAL;
+
return 0;
}
@@ -183,6 +201,31 @@ uv_loop_t* uv_default_loop(void) {
}
+static void uv__loop_close(uv_loop_t* loop) {
+ /* close the async handle without needeing an extra loop iteration */
+ assert(!loop->wq_async.async_sent);
+ loop->wq_async.close_cb = NULL;
+ uv__handle_closing(&loop->wq_async);
+ uv__handle_close(&loop->wq_async);
+
+ if (loop != &uv_default_loop_) {
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) {
+ SOCKET sock = loop->poll_peer_sockets[i];
+ if (sock != 0 && sock != INVALID_SOCKET)
+ closesocket(sock);
+ }
+ }
+ /* TODO: cleanup default loop*/
+
+ uv_mutex_lock(&loop->wq_mutex);
+ assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
+ assert(!uv__has_active_reqs(loop));
+ uv_mutex_unlock(&loop->wq_mutex);
+ uv_mutex_destroy(&loop->wq_mutex);
+}
+
+
int uv_loop_close(uv_loop_t* loop) {
QUEUE* q;
uv_handle_t* h;
@@ -193,15 +236,13 @@ int uv_loop_close(uv_loop_t* loop) {
if (!(h->flags & UV__HANDLE_INTERNAL))
return UV_EBUSY;
}
- if (loop != &uv_default_loop_) {
- size_t i;
- for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) {
- SOCKET sock = loop->poll_peer_sockets[i];
- if (sock != 0 && sock != INVALID_SOCKET)
- closesocket(sock);
- }
- }
- /* TODO: cleanup default loop*/
+
+ uv__loop_close(loop);
+
+#ifndef NDEBUG
+ memset(loop, -1, sizeof(*loop));
+#endif
+
return 0;
}
@@ -224,7 +265,8 @@ uv_loop_t* uv_loop_new(void) {
void uv_loop_delete(uv_loop_t* loop) {
- assert(uv_loop_close(loop) == 0);
+ int err = uv_loop_close(loop);
+ assert(err == 0);
if (loop != &uv_default_loop_)
free(loop);
}
@@ -236,22 +278,31 @@ int uv_backend_fd(const uv_loop_t* loop) {
int uv_backend_timeout(const uv_loop_t* loop) {
- return 0;
+ if (loop->stop_flag != 0)
+ return 0;
+
+ if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
+ return 0;
+
+ if (loop->pending_reqs_tail)
+ return 0;
+
+ if (loop->endgame_handles)
+ return 0;
+
+ if (loop->idle_handles)
+ return 0;
+
+ return uv__next_timeout(loop);
}
-static void uv_poll(uv_loop_t* loop, int block) {
- DWORD bytes, timeout;
+static void uv_poll(uv_loop_t* loop, DWORD timeout) {
+ DWORD bytes;
ULONG_PTR key;
OVERLAPPED* overlapped;
uv_req_t* req;
- if (block) {
- timeout = uv_get_poll_timeout(loop);
- } else {
- timeout = 0;
- }
-
GetQueuedCompletionStatus(loop->iocp,
&bytes,
&key,
@@ -266,28 +317,22 @@ static void uv_poll(uv_loop_t* loop, int block) {
/* Serious error */
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
} else {
- /* We're sure that at least `timeout` milliseconds have expired, but */
- /* this may not be reflected yet in the GetTickCount() return value. */
- /* Therefore we ensure it's taken into account here. */
+ /* We're sure that at least `timeout` milliseconds have expired, but
+ * this may not be reflected yet in the GetTickCount() return value.
+ * Therefore we ensure it's taken into account here.
+ */
uv__time_forward(loop, timeout);
}
}
-static void uv_poll_ex(uv_loop_t* loop, int block) {
+static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) {
BOOL success;
- DWORD timeout;
uv_req_t* req;
OVERLAPPED_ENTRY overlappeds[128];
ULONG count;
ULONG i;
- if (block) {
- timeout = uv_get_poll_timeout(loop);
- } else {
- timeout = 0;
- }
-
success = pGetQueuedCompletionStatusEx(loop->iocp,
overlappeds,
ARRAY_SIZE(overlappeds),
@@ -305,9 +350,10 @@ static void uv_poll_ex(uv_loop_t* loop, int block) {
/* Serious error */
uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx");
} else if (timeout > 0) {
- /* We're sure that at least `timeout` milliseconds have expired, but */
- /* this may not be reflected yet in the GetTickCount() return value. */
- /* Therefore we ensure it's taken into account here. */
+ /* We're sure that at least `timeout` milliseconds have expired, but
+ * this may not be reflected yet in the GetTickCount() return value.
+ * Therefore we ensure it's taken into account here.
+ */
uv__time_forward(loop, timeout);
}
}
@@ -326,8 +372,9 @@ int uv_loop_alive(const uv_loop_t* loop) {
int uv_run(uv_loop_t *loop, uv_run_mode mode) {
+ DWORD timeout;
int r;
- void (*poll)(uv_loop_t* loop, int block);
+ void (*poll)(uv_loop_t* loop, DWORD timeout);
if (pGetQueuedCompletionStatusEx)
poll = &uv_poll_ex;
@@ -346,13 +393,11 @@ int uv_run(uv_loop_t *loop, uv_run_mode mode) {
uv_idle_invoke(loop);
uv_prepare_invoke(loop);
- (*poll)(loop, loop->idle_handles == NULL &&
- loop->pending_reqs_tail == NULL &&
- loop->endgame_handles == NULL &&
- !loop->stop_flag &&
- (loop->active_handles > 0 ||
- !QUEUE_EMPTY(&loop->active_reqs)) &&
- !(mode & UV_RUN_NOWAIT));
+ timeout = 0;
+ if ((mode & UV_RUN_NOWAIT) == 0)
+ timeout = uv_backend_timeout(loop);
+
+ (*poll)(loop, timeout);
uv_check_invoke(loop);
uv_process_endgames(loop);
diff --git a/deps/uv/src/win/error.c b/deps/uv/src/win/error.c
index 3162bc787f..5c5514736e 100644
--- a/deps/uv/src/win/error.c
+++ b/deps/uv/src/win/error.c
@@ -133,6 +133,7 @@ int uv_translate_sys_error(int sys_errno) {
case ERROR_DIRECTORY: return UV_ENOENT;
case ERROR_FILE_NOT_FOUND: return UV_ENOENT;
case ERROR_INVALID_NAME: return UV_ENOENT;
+ case ERROR_INVALID_DRIVE: return UV_ENOENT;
case ERROR_INVALID_REPARSE_DATA: return UV_ENOENT;
case ERROR_MOD_NOT_FOUND: return UV_ENOENT;
case ERROR_PATH_NOT_FOUND: return UV_ENOENT;
diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c
index f31c0a2999..8b52e610f4 100644
--- a/deps/uv/src/win/fs.c
+++ b/deps/uv/src/win/fs.c
@@ -44,12 +44,8 @@
#define QUEUE_FS_TP_JOB(loop, req) \
do { \
- if (!QueueUserWorkItem(&uv_fs_thread_proc, \
- req, \
- WT_EXECUTEDEFAULT)) { \
- return uv_translate_sys_error(GetLastError()); \
- } \
uv__req_register(loop, req); \
+ uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done); \
} while (0)
#define SET_REQ_RESULT(req, result_value) \
@@ -232,11 +228,7 @@ INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req,
req->result = 0;
req->ptr = NULL;
req->path = NULL;
-
- if (cb != NULL) {
- req->cb = cb;
- memset(&req->overlapped, 0, sizeof(req->overlapped));
- }
+ req->cb = cb;
}
@@ -729,6 +721,78 @@ void fs__mkdir(uv_fs_t* req) {
}
+/* Some parts of the implementation were borrowed from glibc. */
+void fs__mkdtemp(uv_fs_t* req) {
+ static const WCHAR letters[] =
+ L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ size_t len;
+ WCHAR* template_part;
+ static uint64_t value;
+ unsigned int count;
+ int fd;
+
+ /* A lower bound on the number of temporary files to attempt to
+ generate. The maximum total number of temporary file names that
+ can exist for a given template is 62**6. It should never be
+ necessary to try all these combinations. Instead if a reasonable
+ number of names is tried (we define reasonable as 62**3) fail to
+ give the system administrator the chance to remove the problems. */
+#define ATTEMPTS_MIN (62 * 62 * 62)
+
+ /* The number of times to attempt to generate a temporary file. To
+ conform to POSIX, this must be no smaller than TMP_MAX. */
+#if ATTEMPTS_MIN < TMP_MAX
+ unsigned int attempts = TMP_MAX;
+#else
+ unsigned int attempts = ATTEMPTS_MIN;
+#endif
+
+ len = wcslen(req->pathw);
+ if (len < 6 || wcsncmp(&req->pathw[len - 6], L"XXXXXX", 6)) {
+ SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
+ return;
+ }
+
+ /* This is where the Xs start. */
+ template_part = &req->pathw[len - 6];
+
+ /* Get some random data. */
+ value += uv_hrtime() ^ _getpid();
+
+ for (count = 0; count < attempts; value += 7777, ++count) {
+ uint64_t v = value;
+
+ /* Fill in the random bits. */
+ template_part[0] = letters[v % 62];
+ v /= 62;
+ template_part[1] = letters[v % 62];
+ v /= 62;
+ template_part[2] = letters[v % 62];
+ v /= 62;
+ template_part[3] = letters[v % 62];
+ v /= 62;
+ template_part[4] = letters[v % 62];
+ v /= 62;
+ template_part[5] = letters[v % 62];
+
+ fd = _wmkdir(req->pathw);
+
+ if (fd >= 0) {
+ len = strlen(req->path);
+ wcstombs((char*) req->path + len - 6, template_part, 6);
+ SET_REQ_RESULT(req, 0);
+ return;
+ } else if (errno != EEXIST) {
+ SET_REQ_RESULT(req, -1);
+ return;
+ }
+ }
+
+ /* We got out of the loop because we ran out of combinations to try. */
+ SET_REQ_RESULT(req, -1);
+}
+
+
void fs__readdir(uv_fs_t* req) {
WCHAR* pathw = req->pathw;
size_t len = wcslen(pathw);
@@ -1401,7 +1465,7 @@ static void fs__create_junction(uv_fs_t* req, const WCHAR* path,
/* Open the directory */
handle = CreateFileW(new_path,
- GENERIC_ALL,
+ GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
@@ -1510,11 +1574,10 @@ static void fs__fchown(uv_fs_t* req) {
}
-static DWORD WINAPI uv_fs_thread_proc(void* parameter) {
- uv_fs_t* req = (uv_fs_t*) parameter;
- uv_loop_t* loop = req->loop;
+static void uv__fs_work(struct uv__work* w) {
+ uv_fs_t* req;
- assert(req != NULL);
+ req = container_of(w, uv_fs_t, work_req);
assert(req->type == UV_FS);
#define XX(uc, lc) case UV_FS_##uc: fs__##lc(req); break;
@@ -1537,6 +1600,7 @@ static DWORD WINAPI uv_fs_thread_proc(void* parameter) {
XX(UNLINK, unlink)
XX(RMDIR, rmdir)
XX(MKDIR, mkdir)
+ XX(MKDTEMP, mkdtemp)
XX(RENAME, rename)
XX(READDIR, readdir)
XX(LINK, link)
@@ -1547,9 +1611,41 @@ static DWORD WINAPI uv_fs_thread_proc(void* parameter) {
default:
assert(!"bad uv_fs_type");
}
+}
- POST_COMPLETION_FOR_REQ(loop, req);
- return 0;
+
+static void uv__fs_done(struct uv__work* w, int status) {
+ uv_fs_t* req;
+
+ req = container_of(w, uv_fs_t, work_req);
+ uv__req_unregister(req->loop, req);
+
+ if (status == UV_ECANCELED) {
+ assert(req->result == 0);
+ req->result = UV_ECANCELED;
+ }
+
+ if (req->cb != NULL)
+ req->cb(req);
+}
+
+
+void uv_fs_req_cleanup(uv_fs_t* req) {
+ if (req->flags & UV_FS_CLEANEDUP)
+ return;
+
+ if (req->flags & UV_FS_FREE_PATHS)
+ free(req->pathw);
+
+ if (req->flags & UV_FS_FREE_PTR)
+ free(req->ptr);
+
+ req->path = NULL;
+ req->pathw = NULL;
+ req->new_pathw = NULL;
+ req->ptr = NULL;
+
+ req->flags |= UV_FS_CLEANEDUP;
}
@@ -1701,6 +1797,26 @@ int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
}
+int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_MKDTEMP, cb);
+
+ err = fs__capture_path(loop, req, tpl, NULL, TRUE);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__mkdtemp(req);
+ return req->result;
+ }
+}
+
+
int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
int err;
@@ -2064,30 +2180,3 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
return req->result;
}
}
-
-
-void uv_process_fs_req(uv_loop_t* loop, uv_fs_t* req) {
- assert(req->cb);
- uv__req_unregister(loop, req);
- req->cb(req);
-}
-
-
-void uv_fs_req_cleanup(uv_fs_t* req) {
- if (req->flags & UV_FS_CLEANEDUP)
- return;
-
- if (req->flags & UV_FS_FREE_PATHS)
- free(req->pathw);
-
- if (req->flags & UV_FS_FREE_PTR)
- free(req->ptr);
-
- req->path = NULL;
- req->pathw = NULL;
- req->new_pathw = NULL;
- req->ptr = NULL;
-
- req->flags |= UV_FS_CLEANEDUP;
-}
-
diff --git a/deps/uv/src/win/getaddrinfo.c b/deps/uv/src/win/getaddrinfo.c
index b87a933f0f..086200a9ea 100644
--- a/deps/uv/src/win/getaddrinfo.c
+++ b/deps/uv/src/win/getaddrinfo.c
@@ -56,25 +56,13 @@
#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2)
-/* getaddrinfo worker thread implementation */
-static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) {
- uv_getaddrinfo_t* req = (uv_getaddrinfo_t*) parameter;
- uv_loop_t* loop = req->loop;
- int ret;
-
- assert(req != NULL);
-
- /* 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, req);
+static void uv__getaddrinfo_work(struct uv__work* w) {
+ uv_getaddrinfo_t* req;
+ int err;
- return 0;
+ req = container_of(w, uv_getaddrinfo_t, work_req);
+ err = GetAddrInfoW(req->node, req->service, req->hints, &req->res);
+ req->retcode = uv__getaddrinfo_translate_error(err);
}
@@ -87,7 +75,8 @@ 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* req) {
+static void uv__getaddrinfo_done(struct uv__work* w, int status) {
+ uv_getaddrinfo_t* req;
int addrinfo_len = 0;
int name_len = 0;
size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));
@@ -95,7 +84,8 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) {
struct addrinfo* addrinfo_ptr;
char* alloc_ptr = NULL;
char* cur_ptr = NULL;
- int err = 0;
+
+ req = container_of(w, uv_getaddrinfo_t, work_req);
/* release input parameter memory */
if (req->alloc != NULL) {
@@ -103,6 +93,16 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) {
req->alloc = NULL;
}
+ if (status == UV_ECANCELED) {
+ assert(req->retcode == 0);
+ req->retcode = UV_EAI_CANCELED;
+ if (req->res != NULL) {
+ FreeAddrInfoW(req->res);
+ req->res = NULL;
+ }
+ goto complete;
+ }
+
if (req->retcode == 0) {
/* convert addrinfoW to addrinfo */
/* first calculate required length */
@@ -113,7 +113,7 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) {
if (addrinfow_ptr->ai_canonname != NULL) {
name_len = uv_utf16_to_utf8(addrinfow_ptr->ai_canonname, -1, NULL, 0);
if (name_len == 0) {
- err = uv_translate_sys_error(GetLastError());
+ req->retcode = uv_translate_sys_error(GetLastError());
goto complete;
}
addrinfo_len += ALIGNED_SIZE(name_len);
@@ -178,11 +178,8 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) {
}
}
} else {
- err = UV_EAI_MEMORY;
+ req->retcode = UV_EAI_MEMORY;
}
- } else {
- /* GetAddrInfo failed */
- err = uv__getaddrinfo_translate_error(req->retcode);
}
/* return memory to system */
@@ -192,10 +189,10 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) {
}
complete:
- uv__req_unregister(loop, req);
+ uv__req_unregister(req->loop, req);
/* finally do callback with converted result */
- req->getaddrinfo_cb(req, err, (struct addrinfo*)alloc_ptr);
+ req->getaddrinfo_cb(req, req->retcode, (struct addrinfo*)alloc_ptr);
}
@@ -246,6 +243,7 @@ int uv_getaddrinfo(uv_loop_t* loop,
req->res = NULL;
req->type = UV_GETADDRINFO;
req->loop = loop;
+ req->retcode = 0;
/* calculate required memory size for all input values */
if (node != NULL) {
@@ -323,13 +321,10 @@ int uv_getaddrinfo(uv_loop_t* loop,
req->hints = NULL;
}
- /* Ask thread to run. Treat this as a long operation */
- if (QueueUserWorkItem(&getaddrinfo_thread_proc,
- req,
- WT_EXECUTELONGFUNCTION) == 0) {
- err = GetLastError();
- goto error;
- }
+ uv__work_submit(loop,
+ &req->work_req,
+ uv__getaddrinfo_work,
+ uv__getaddrinfo_done);
uv__req_register(loop, req);
diff --git a/deps/uv/src/win/getnameinfo.c b/deps/uv/src/win/getnameinfo.c
index 48eb16d8ca..45608dae85 100644
--- a/deps/uv/src/win/getnameinfo.c
+++ b/deps/uv/src/win/getnameinfo.c
@@ -27,23 +27,31 @@
#include "internal.h"
#include "req-inl.h"
-
-/* getnameinfo worker thread implementation */
-static DWORD WINAPI getnameinfo_thread_proc(void* parameter) {
- uv_getnameinfo_t* req = (uv_getnameinfo_t*)parameter;
- uv_loop_t* loop = req->loop;
+#ifndef GetNameInfo
+int WSAAPI GetNameInfoW(
+ const SOCKADDR *pSockaddr,
+ socklen_t SockaddrLength,
+ PWCHAR pNodeBuffer,
+ DWORD NodeBufferSize,
+ PWCHAR pServiceBuffer,
+ DWORD ServiceBufferSize,
+ INT Flags
+);
+#endif
+
+static void uv__getnameinfo_work(struct uv__work* w) {
+ uv_getnameinfo_t* req;
WCHAR host[NI_MAXHOST];
WCHAR service[NI_MAXSERV];
int ret = 0;
- assert(req != NULL);
-
+ req = container_of(w, uv_getnameinfo_t, work_req);
ret = GetNameInfoW((struct sockaddr*)&req->storage,
sizeof(req->storage),
host,
- sizeof(host),
+ ARRAY_SIZE(host),
service,
- sizeof(service),
+ ARRAY_SIZE(service),
req->flags);
req->retcode = uv__getaddrinfo_translate_error(ret);
@@ -65,30 +73,29 @@ static DWORD WINAPI getnameinfo_thread_proc(void* parameter) {
sizeof(req->service),
NULL,
NULL);
-
- /* post getnameinfo completed */
- POST_COMPLETION_FOR_REQ(loop, req);
-
- return 0;
}
/*
* Called from uv_run when complete.
*/
-void uv_process_getnameinfo_req(uv_loop_t* loop, uv_getnameinfo_t* req) {
+static void uv__getnameinfo_done(struct uv__work* w, int status) {
+ uv_getnameinfo_t* req;
char* host;
char* service;
- if (req->retcode == 0) {
+ req = container_of(w, uv_getnameinfo_t, work_req);
+ uv__req_unregister(req->loop, req);
+ host = service = NULL;
+
+ if (status == UV_ECANCELED) {
+ assert(req->retcode == 0);
+ req->retcode = UV_EAI_CANCELED;
+ } else if (req->retcode == 0) {
host = req->host;
service = req->service;
- } else {
- host = NULL;
- service = NULL;
}
- uv__req_unregister(loop, req);
req->getnameinfo_cb(req, req->retcode, host, service);
}
@@ -119,20 +126,18 @@ int uv_getnameinfo(uv_loop_t* loop,
}
uv_req_init(loop, (uv_req_t*)req);
+ uv__req_register(loop, req);
req->getnameinfo_cb = getnameinfo_cb;
req->flags = flags;
req->type = UV_GETNAMEINFO;
req->loop = loop;
+ req->retcode = 0;
- /* Ask thread to run. Treat this as a long operation. */
- if (QueueUserWorkItem(&getnameinfo_thread_proc,
- req,
- WT_EXECUTELONGFUNCTION) == 0) {
- return uv_translate_sys_error(GetLastError());
- }
-
- uv__req_register(loop, req);
+ uv__work_submit(loop,
+ &req->work_req,
+ uv__getnameinfo_work,
+ uv__getnameinfo_done);
return 0;
}
diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h
index 83c4a66893..9eadb71235 100644
--- a/deps/uv/src/win/internal.h
+++ b/deps/uv/src/win/internal.h
@@ -31,13 +31,16 @@
#ifdef _MSC_VER
# define INLINE __inline
+# define UV_THREAD_LOCAL __declspec( thread )
#else
# define INLINE inline
+# define UV_THREAD_LOCAL __thread
#endif
#ifdef _DEBUG
-extern __declspec( thread ) int uv__crt_assert_enabled;
+
+extern UV_THREAD_LOCAL int uv__crt_assert_enabled;
#define UV_BEGIN_DISABLE_CRT_ASSERT() \
{ \
@@ -72,7 +75,6 @@ extern __declspec( thread ) int uv__crt_assert_enabled;
/* Used by streams and UDP handles. */
#define UV_HANDLE_READING 0x00000100
#define UV_HANDLE_BOUND 0x00000200
-#define UV_HANDLE_BIND_ERROR 0x00000400
#define UV_HANDLE_LISTENING 0x00000800
#define UV_HANDLE_CONNECTION 0x00001000
#define UV_HANDLE_CONNECTED 0x00002000
@@ -122,6 +124,12 @@ extern __declspec( thread ) int uv__crt_assert_enabled;
/*
* TCP
*/
+
+typedef struct {
+ WSAPROTOCOL_INFOW socket_info;
+ int delayed_error;
+} uv__ipc_socket_info_ex;
+
int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb);
int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client);
int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
@@ -140,7 +148,7 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
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,
+int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
int tcp_connection);
int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
@@ -231,7 +239,7 @@ void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle);
*/
void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle);
-DWORD uv_get_poll_timeout(uv_loop_t* loop);
+DWORD uv__next_timeout(const uv_loop_t* loop);
void uv__time_forward(uv_loop_t* loop, uint64_t msecs);
void uv_process_timers(uv_loop_t* loop);
@@ -286,28 +294,9 @@ int uv_translate_sys_error(int sys_errno);
/*
- * Getaddrinfo
- */
-void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req);
-
-
-/*
-* Getnameinfo
-*/
-void uv_process_getnameinfo_req(uv_loop_t* loop, uv_getnameinfo_t* req);
-
-
-/*
* FS
*/
void uv_fs_init();
-void uv_process_fs_req(uv_loop_t* loop, uv_fs_t* req);
-
-
-/*
- * Threadpool
- */
-void uv_process_work_req(uv_loop_t* loop, uv_work_t* req);
/*
diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c
index 2fcedde369..3bf2a220d0 100644
--- a/deps/uv/src/win/pipe.c
+++ b/deps/uv/src/win/pipe.c
@@ -35,10 +35,10 @@ typedef struct uv__ipc_queue_item_s uv__ipc_queue_item_t;
struct uv__ipc_queue_item_s {
/*
- * NOTE: It is important for socket_info to be the first field,
+ * NOTE: It is important for socket_info_ex to be the first field,
* because we will we assigning it to the pending_ipc_info.socket_info
*/
- WSAPROTOCOL_INFOW socket_info;
+ uv__ipc_socket_info_ex socket_info_ex;
QUEUE member;
int tcp_connection;
};
@@ -73,7 +73,7 @@ typedef struct {
/* IPC frame, which contains an imported TCP socket stream. */
typedef struct {
uv_ipc_frame_header_t header;
- WSAPROTOCOL_INFOW socket_info;
+ uv__ipc_socket_info_ex socket_info_ex;
} uv_ipc_frame_uv_stream;
static void eof_timer_init(uv_pipe_t* pipe);
@@ -230,7 +230,7 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
NTSTATUS nt_status;
IO_STATUS_BLOCK io_status;
FILE_MODE_INFORMATION mode_info;
- DWORD mode = PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT;
+ DWORD mode = PIPE_READMODE_BYTE | PIPE_WAIT;
DWORD current_mode = 0;
DWORD err = 0;
@@ -246,11 +246,9 @@ static int uv_set_pipe_handle(uv_loop_t* loop,
if (!GetNamedPipeHandleState(pipeHandle, &current_mode, NULL, NULL,
NULL, NULL, 0)) {
return -1;
- } else if (current_mode != mode) {
+ } else if (current_mode & PIPE_NOWAIT) {
SetLastError(ERROR_ACCESS_DENIED);
return -1;
- } else {
- duplex_flags &= ~UV_HANDLE_WRITABLE;
}
} else {
/* If this returns ERROR_INVALID_PARAMETER we probably opened
@@ -410,7 +408,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
socket = WSASocketW(FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
- &item->socket_info,
+ &item->socket_info_ex.socket_info,
0,
WSA_FLAG_OVERLAPPED);
free(item);
@@ -789,7 +787,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
item = QUEUE_DATA(q, uv__ipc_queue_item_t, member);
err = uv_tcp_import((uv_tcp_t*)client,
- &item->socket_info,
+ &item->socket_info_ex,
item->tcp_connection);
if (err != 0)
return err;
@@ -1134,10 +1132,13 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
tcp_send_handle = (uv_tcp_t*)send_handle;
err = uv_tcp_duplicate_socket(tcp_send_handle, handle->ipc_pid,
- &ipc_frame.socket_info);
+ &ipc_frame.socket_info_ex.socket_info);
if (err) {
return err;
}
+
+ ipc_frame.socket_info_ex.delayed_error = tcp_send_handle->delayed_error;
+
ipc_frame.header.flags |= UV_IPC_TCP_SERVER;
if (tcp_send_handle->flags & UV_HANDLE_CONNECTION) {
@@ -1254,7 +1255,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
}
/* Request queued by the kernel. */
- req->queued_bytes = uv_count_bufs(bufs, nbufs);
+ req->queued_bytes = uv__count_bufs(bufs, nbufs);
handle->write_queue_size += req->queued_bytes;
} else if (handle->flags & UV_HANDLE_BLOCKING_WRITES) {
/* Using overlapped IO, but wait for completion before returning */
@@ -1311,7 +1312,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop,
req->queued_bytes = 0;
} else {
/* Request queued by the kernel. */
- req->queued_bytes = uv_count_bufs(bufs, nbufs);
+ req->queued_bytes = uv__count_bufs(bufs, nbufs);
handle->write_queue_size += req->queued_bytes;
}
@@ -1397,7 +1398,7 @@ static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle,
void uv__pipe_insert_pending_socket(uv_pipe_t* handle,
- WSAPROTOCOL_INFOW* info,
+ uv__ipc_socket_info_ex* info,
int tcp_connection) {
uv__ipc_queue_item_t* item;
@@ -1405,7 +1406,7 @@ void uv__pipe_insert_pending_socket(uv_pipe_t* handle,
if (item == NULL)
uv_fatal_error(ERROR_OUTOFMEMORY, "malloc");
- memcpy(&item->socket_info, info, sizeof(item->socket_info));
+ memcpy(&item->socket_info_ex, info, sizeof(item->socket_info_ex));
item->tcp_connection = tcp_connection;
QUEUE_INSERT_TAIL(&handle->pending_ipc_info.queue, &item->member);
handle->pending_ipc_info.queue_len++;
@@ -1471,11 +1472,11 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
if (ipc_frame.header.flags & UV_IPC_TCP_SERVER) {
assert(avail - sizeof(ipc_frame.header) >=
- sizeof(ipc_frame.socket_info));
+ sizeof(ipc_frame.socket_info_ex));
/* Read the TCP socket info. */
if (!ReadFile(handle->handle,
- &ipc_frame.socket_info,
+ &ipc_frame.socket_info_ex,
sizeof(ipc_frame) - sizeof(ipc_frame.header),
&bytes,
NULL)) {
@@ -1489,7 +1490,7 @@ void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
/* Store the pending socket info. */
uv__pipe_insert_pending_socket(
handle,
- &ipc_frame.socket_info,
+ &ipc_frame.socket_info_ex,
ipc_frame.header.flags & UV_IPC_TCP_CONNECTION);
}
@@ -1772,7 +1773,34 @@ static void eof_timer_close_cb(uv_handle_t* handle) {
int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
HANDLE os_handle = uv__get_osfhandle(file);
- DWORD duplex_flags = UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_ACCESS_INFORMATION access;
+ DWORD duplex_flags = 0;
+
+ /* Determine what kind of permissions we have on this handle.
+ * Cygwin opens the pipe in message mode, but we can support it,
+ * just query the access flags and set the stream flags accordingly.
+ */
+ nt_status = pNtQueryInformationFile(os_handle,
+ &io_status,
+ &access,
+ sizeof(access),
+ FileAccessInformation);
+ if (nt_status != STATUS_SUCCESS)
+ return UV_EINVAL;
+
+ if (pipe->ipc) {
+ if (!(access.AccessFlags & FILE_WRITE_DATA) ||
+ !(access.AccessFlags & FILE_READ_DATA)) {
+ return UV_EINVAL;
+ }
+ }
+
+ if (access.AccessFlags & FILE_WRITE_DATA)
+ duplex_flags |= UV_HANDLE_WRITABLE;
+ if (access.AccessFlags & FILE_READ_DATA)
+ duplex_flags |= UV_HANDLE_READABLE;
if (os_handle == INVALID_HANDLE_VALUE ||
uv_set_pipe_handle(pipe->loop, pipe, os_handle, duplex_flags) == -1) {
diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c
index 7a85858c56..40023e5572 100644
--- a/deps/uv/src/win/process.c
+++ b/deps/uv/src/win/process.c
@@ -25,6 +25,8 @@
#include <stdlib.h>
#include <signal.h>
#include <limits.h>
+#include <malloc.h>
+#include <wchar.h>
#include "uv.h"
#include "internal.h"
@@ -36,14 +38,27 @@
typedef struct env_var {
- const char* narrow;
- const WCHAR* wide;
- size_t len; /* including null or '=' */
- DWORD value_len;
- int supplied;
+ const WCHAR* const wide;
+ const WCHAR* const wide_eq;
+ const size_t len; /* including null or '=' */
} env_var_t;
-#define E_V(str) { str "=", L##str, sizeof(str), 0, 0 }
+#define E_V(str) { L##str, L##str L"=", sizeof(str) }
+
+static const env_var_t required_vars[] = { /* keep me sorted */
+ E_V("HOMEDRIVE"),
+ E_V("HOMEPATH"),
+ E_V("LOGONSERVER"),
+ E_V("PATH"),
+ E_V("SYSTEMDRIVE"),
+ E_V("SYSTEMROOT"),
+ E_V("TEMP"),
+ E_V("USERDOMAIN"),
+ E_V("USERNAME"),
+ E_V("USERPROFILE"),
+ E_V("WINDIR"),
+};
+static size_t n_required_vars = ARRAY_SIZE(required_vars);
static HANDLE uv_global_job_handle_;
@@ -587,25 +602,56 @@ error:
}
-/*
- * If we learn that people are passing in huge environment blocks
- * then we should probably qsort() the array and then bsearch()
- * to see if it contains this variable. But there are ownership
- * issues associated with that solution; this is the caller's
- * char**, and modifying it is rude.
- */
-static void check_required_vars_contains_var(env_var_t* required, int count,
- const char* var) {
- int i;
- for (i = 0; i < count; ++i) {
- if (_strnicmp(required[i].narrow, var, required[i].len) == 0) {
- required[i].supplied = 1;
- return;
+int env_strncmp(const wchar_t* a, int na, const wchar_t* b) {
+ wchar_t* a_eq;
+ wchar_t* b_eq;
+ wchar_t* A;
+ wchar_t* B;
+ int nb;
+ int r;
+
+ if (na < 0) {
+ a_eq = wcschr(a, L'=');
+ assert(a_eq);
+ na = (int)(long)(a_eq - a);
+ } else {
+ na--;
+ }
+ b_eq = wcschr(b, L'=');
+ assert(b_eq);
+ nb = b_eq - b;
+
+ A = alloca((na+1) * sizeof(wchar_t));
+ B = alloca((nb+1) * sizeof(wchar_t));
+
+ r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, a, na, A, na);
+ assert(r==na);
+ A[na] = L'\0';
+ r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, b, nb, B, nb);
+ assert(r==nb);
+ B[nb] = L'\0';
+
+ while (1) {
+ wchar_t AA = *A++;
+ wchar_t BB = *B++;
+ if (AA < BB) {
+ return -1;
+ } else if (AA > BB) {
+ return 1;
+ } else if (!AA && !BB) {
+ return 0;
}
}
}
+static int qsort_wcscmp(const void *a, const void *b) {
+ wchar_t* astr = *(wchar_t* const*)a;
+ wchar_t* bstr = *(wchar_t* const*)b;
+ return env_strncmp(astr, -1, bstr);
+}
+
+
/*
* The way windows takes environment variables is different than what C does;
* Windows wants a contiguous block of null-terminated strings, terminated
@@ -616,95 +662,171 @@ static void check_required_vars_contains_var(env_var_t* required, int count,
* TEMP. SYSTEMDRIVE is probably also important. We therefore ensure that
* these get defined if the input environment block does not contain any
* values for them.
+ *
+ * Also add variables known to Cygwin to be required for correct
+ * subprocess operation in many cases:
+ * https://github.com/Alexpux/Cygwin/blob/b266b04fbbd3a595f02ea149e4306d3ab9b1fe3d/winsup/cygwin/environ.cc#L955
+ *
*/
int make_program_env(char* env_block[], WCHAR** dst_ptr) {
WCHAR* dst;
WCHAR* ptr;
char** env;
- size_t env_len = 1; /* room for closing null */
+ size_t env_len = 0;
int len;
size_t i;
DWORD var_size;
+ size_t env_block_count = 1; /* 1 for null-terminator */
+ WCHAR* dst_copy;
+ WCHAR** ptr_copy;
+ WCHAR** env_copy;
+ DWORD* required_vars_value_len = alloca(n_required_vars * sizeof(DWORD*));
- env_var_t required_vars[] = {
- E_V("SYSTEMROOT"),
- E_V("SYSTEMDRIVE"),
- E_V("TEMP"),
- };
-
+ /* first pass: determine size in UTF-16 */
for (env = env_block; *env; env++) {
int len;
- check_required_vars_contains_var(required_vars,
- ARRAY_SIZE(required_vars),
- *env);
-
- len = MultiByteToWideChar(CP_UTF8,
- 0,
- *env,
- -1,
- NULL,
- 0);
- if (len <= 0) {
- return GetLastError();
+ if (strchr(*env, '=')) {
+ len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ *env,
+ -1,
+ NULL,
+ 0);
+ if (len <= 0) {
+ return GetLastError();
+ }
+ env_len += len;
+ env_block_count++;
}
+ }
- env_len += len;
+ /* second pass: copy to UTF-16 environment block */
+ dst_copy = _malloca(env_len * sizeof(WCHAR));
+ if (!dst_copy) {
+ return ERROR_OUTOFMEMORY;
}
+ env_copy = alloca(env_block_count * sizeof(WCHAR*));
- for (i = 0; i < ARRAY_SIZE(required_vars); ++i) {
- if (!required_vars[i].supplied) {
- env_len += required_vars[i].len;
+ ptr = dst_copy;
+ ptr_copy = env_copy;
+ for (env = env_block; *env; env++) {
+ if (strchr(*env, '=')) {
+ len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ *env,
+ -1,
+ ptr,
+ (int) (env_len - (ptr - dst_copy)));
+ if (len <= 0) {
+ DWORD err = GetLastError();
+ _freea(dst_copy);
+ return err;
+ }
+ *ptr_copy++ = ptr;
+ ptr += len;
+ }
+ }
+ *ptr_copy = NULL;
+ assert(env_len == ptr - dst_copy);
+
+ /* sort our (UTF-16) copy */
+ qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp);
+
+ /* third pass: check for required variables */
+ for (ptr_copy = env_copy, i = 0; i < n_required_vars; ) {
+ int cmp;
+ if (!*ptr_copy) {
+ cmp = -1;
+ } else {
+ cmp = env_strncmp(required_vars[i].wide_eq,
+ required_vars[i].len,
+ *ptr_copy);
+ }
+ if (cmp < 0) {
+ /* missing required var */
var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0);
- if (var_size == 0) {
- return GetLastError();
+ required_vars_value_len[i] = var_size;
+ if (var_size != 0) {
+ env_len += required_vars[i].len;
+ env_len += var_size;
}
- required_vars[i].value_len = var_size;
- env_len += var_size;
+ i++;
+ } else {
+ ptr_copy++;
+ if (cmp == 0)
+ i++;
}
}
- dst = malloc(env_len * sizeof(WCHAR));
+ /* final pass: copy, in sort order, and inserting required variables */
+ dst = malloc((1+env_len) * sizeof(WCHAR));
if (!dst) {
+ _freea(dst_copy);
return ERROR_OUTOFMEMORY;
}
- ptr = dst;
-
- for (env = env_block; *env; env++, ptr += len) {
- len = MultiByteToWideChar(CP_UTF8,
- 0,
- *env,
- -1,
- ptr,
- (int) (env_len - (ptr - dst)));
- if (len <= 0) {
- free(dst);
- return GetLastError();
+ for (ptr = dst, ptr_copy = env_copy, i = 0;
+ *ptr_copy || i < n_required_vars;
+ ptr += len) {
+ int cmp;
+ if (i >= n_required_vars) {
+ cmp = 1;
+ } else if (!*ptr_copy) {
+ cmp = -1;
+ } else {
+ cmp = env_strncmp(required_vars[i].wide_eq,
+ required_vars[i].len,
+ *ptr_copy);
}
- }
-
- for (i = 0; i < ARRAY_SIZE(required_vars); ++i) {
- if (!required_vars[i].supplied) {
- wcscpy(ptr, required_vars[i].wide);
- ptr += required_vars[i].len - 1;
- *ptr++ = L'=';
- var_size = GetEnvironmentVariableW(required_vars[i].wide,
- ptr,
- required_vars[i].value_len);
- if (var_size == 0) {
- uv_fatal_error(GetLastError(), "GetEnvironmentVariableW");
+ if (cmp < 0) {
+ /* missing required var */
+ len = required_vars_value_len[i];
+ if (len) {
+ wcscpy(ptr, required_vars[i].wide_eq);
+ ptr += required_vars[i].len;
+ var_size = GetEnvironmentVariableW(required_vars[i].wide,
+ ptr,
+ (int) (env_len - (ptr - dst)));
+ if (var_size != len-1) { /* race condition? */
+ uv_fatal_error(GetLastError(), "GetEnvironmentVariableW");
+ }
}
- ptr += required_vars[i].value_len;
+ i++;
+ } else {
+ /* copy var from env_block */
+ DWORD r;
+ len = wcslen(*ptr_copy) + 1;
+ r = wmemcpy_s(ptr, (env_len - (ptr - dst)), *ptr_copy, len);
+ assert(!r);
+ ptr_copy++;
+ if (cmp == 0)
+ i++;
}
}
/* Terminate with an extra NULL. */
+ assert(env_len == (ptr - dst));
*ptr = L'\0';
+ _freea(dst_copy);
*dst_ptr = dst;
return 0;
}
+/*
+ * Attempt to find the value of the PATH environment variable in the child's
+ * preprocessed environment.
+ *
+ * If found, a pointer into `env` is returned. If not found, NULL is returned.
+ */
+static WCHAR* find_path(WCHAR *env) {
+ for (; env != NULL && *env != 0; env += wcslen(env) + 1) {
+ if (wcsncmp(env, L"PATH=", 5) == 0)
+ return &env[5];
+ }
+
+ return NULL;
+}
/*
* Called on Windows thread-pool thread to indicate that
@@ -802,7 +924,7 @@ int uv_spawn(uv_loop_t* loop,
const uv_process_options_t* options) {
int i;
int err = 0;
- WCHAR* path = NULL;
+ WCHAR* path = NULL, *alloc_path = NULL;
BOOL result;
WCHAR* application_path = NULL, *application = NULL, *arguments = NULL,
*env = NULL, *cwd = NULL;
@@ -876,7 +998,8 @@ int uv_spawn(uv_loop_t* loop,
}
/* Get PATH environment variable. */
- {
+ path = find_path(env);
+ if (path == NULL) {
DWORD path_len, r;
path_len = GetEnvironmentVariableW(L"PATH", NULL, 0);
@@ -885,11 +1008,12 @@ int uv_spawn(uv_loop_t* loop,
goto done;
}
- path = (WCHAR*) malloc(path_len * sizeof(WCHAR));
- if (path == NULL) {
+ alloc_path = (WCHAR*) malloc(path_len * sizeof(WCHAR));
+ if (alloc_path == NULL) {
err = ERROR_OUTOFMEMORY;
goto done;
}
+ path = alloc_path;
r = GetEnvironmentVariableW(L"PATH", path, path_len);
if (r == 0 || r >= path_len) {
@@ -1023,7 +1147,7 @@ int uv_spawn(uv_loop_t* loop,
free(arguments);
free(cwd);
free(env);
- free(path);
+ free(alloc_path);
if (process->child_stdio_buffer != NULL) {
/* Clean up child stdio handles. */
diff --git a/deps/uv/src/win/req-inl.h b/deps/uv/src/win/req-inl.h
index cbc2ba8e18..97342e5c7e 100644
--- a/deps/uv/src/win/req-inl.h
+++ b/deps/uv/src/win/req-inl.h
@@ -195,26 +195,10 @@ INLINE static void uv_process_reqs(uv_loop_t* loop) {
uv_process_poll_req(loop, (uv_poll_t*) req->data, req);
break;
- case UV_GETADDRINFO:
- uv_process_getaddrinfo_req(loop, (uv_getaddrinfo_t*) req);
- break;
-
- case UV_GETNAMEINFO:
- uv_process_getnameinfo_req(loop, (uv_getnameinfo_t*)req);
- break;
-
case UV_PROCESS_EXIT:
uv_process_proc_exit(loop, (uv_process_t*) req->data);
break;
- case UV_FS:
- uv_process_fs_req(loop, (uv_fs_t*) req);
- break;
-
- case UV_WORK:
- uv_process_work_req(loop, (uv_work_t*) req);
- break;
-
case UV_FS_EVENT_REQ:
uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data);
break;
diff --git a/deps/uv/src/win/stream-inl.h b/deps/uv/src/win/stream-inl.h
index e4bf086368..97a6b90b50 100644
--- a/deps/uv/src/win/stream-inl.h
+++ b/deps/uv/src/win/stream-inl.h
@@ -53,15 +53,4 @@ INLINE static void uv_connection_init(uv_stream_t* handle) {
}
-INLINE static size_t uv_count_bufs(const uv_buf_t bufs[], unsigned int nbufs) {
- unsigned int i;
- size_t bytes;
-
- bytes = 0;
- for (i = 0; i < nbufs; i++)
- bytes += (size_t) bufs[i].len;
-
- return bytes;
-}
-
#endif /* UV_WIN_STREAM_INL_H_ */
diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c
index ccd7a11e2c..a213ad63e7 100644
--- a/deps/uv/src/win/tcp.c
+++ b/deps/uv/src/win/tcp.c
@@ -156,6 +156,7 @@ int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
handle->func_acceptex = NULL;
handle->func_connectex = NULL;
handle->processed_accepts = 0;
+ handle->delayed_error = 0;
return 0;
}
@@ -235,6 +236,17 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
}
+/* Unlike on Unix, here we don't set SO_REUSEADDR, because it doesn't just
+ * allow binding to addresses that are in use by sockets in TIME_WAIT, it
+ * effectively allows 'stealing' a port which is in use by another application.
+ *
+ * SO_EXCLUSIVEADDRUSE is also not good here because it does cehck all sockets,
+ * regardless of state, so we'd get an error even if the port is in use by a
+ * socket in TIME_WAIT state.
+ *
+ * See issue #1360.
+ *
+ */
static int uv_tcp_try_bind(uv_tcp_t* handle,
const struct sockaddr* addr,
unsigned int addrlen,
@@ -291,8 +303,7 @@ static int uv_tcp_try_bind(uv_tcp_t* handle,
err = WSAGetLastError();
if (err == WSAEADDRINUSE) {
/* Some errors are not to be reported until connect() or listen() */
- handle->bind_error = err;
- handle->flags |= UV_HANDLE_BIND_ERROR;
+ handle->delayed_error = err;
} else {
return err;
}
@@ -517,8 +528,8 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
return WSAEISCONN;
}
- if (handle->flags & UV_HANDLE_BIND_ERROR) {
- return handle->bind_error;
+ if (handle->delayed_error) {
+ return handle->delayed_error;
}
if (!(handle->flags & UV_HANDLE_BOUND)) {
@@ -528,6 +539,8 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
0);
if (err)
return err;
+ if (handle->delayed_error)
+ return handle->delayed_error;
}
if (!handle->func_acceptex) {
@@ -699,8 +712,8 @@ static int uv_tcp_try_connect(uv_connect_t* req,
DWORD bytes;
int err;
- if (handle->flags & UV_HANDLE_BIND_ERROR) {
- return handle->bind_error;
+ if (handle->delayed_error) {
+ return handle->delayed_error;
}
if (!(handle->flags & UV_HANDLE_BOUND)) {
@@ -714,6 +727,8 @@ static int uv_tcp_try_connect(uv_connect_t* req,
err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0);
if (err)
return err;
+ if (handle->delayed_error)
+ return handle->delayed_error;
}
if (!handle->func_connectex) {
@@ -762,8 +777,8 @@ int uv_tcp_getsockname(const uv_tcp_t* handle,
return UV_EINVAL;
}
- if (handle->flags & UV_HANDLE_BIND_ERROR) {
- return uv_translate_sys_error(handle->bind_error);
+ if (handle->delayed_error) {
+ return uv_translate_sys_error(handle->delayed_error);
}
result = getsockname(handle->socket, name, namelen);
@@ -784,8 +799,8 @@ int uv_tcp_getpeername(const uv_tcp_t* handle,
return UV_EINVAL;
}
- if (handle->flags & UV_HANDLE_BIND_ERROR) {
- return uv_translate_sys_error(handle->bind_error);
+ if (handle->delayed_error) {
+ return uv_translate_sys_error(handle->delayed_error);
}
result = getpeername(handle->socket, name, namelen);
@@ -839,7 +854,7 @@ int uv_tcp_write(uv_loop_t* loop,
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, nbufs);
+ req->queued_bytes = uv__count_bufs(bufs, nbufs);
handle->reqs_pending++;
handle->write_reqs_pending++;
REGISTER_HANDLE_REQ(loop, handle, req);
@@ -1009,8 +1024,12 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
}
if (req->cb) {
- err = GET_REQ_SOCK_ERROR(req);
- req->cb(req, uv_translate_sys_error(err));
+ err = uv_translate_sys_error(GET_REQ_SOCK_ERROR(req));
+ if (err == UV_ECONNABORTED) {
+ /* use UV_ECANCELED for consistency with Unix */
+ err = UV_ECANCELED;
+ }
+ req->cb(req, err);
}
handle->write_reqs_pending--;
@@ -1102,14 +1121,13 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
}
-int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info,
+int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
int tcp_connection) {
int err;
-
SOCKET socket = WSASocketW(FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
- socket_protocol_info,
+ &socket_info_ex->socket_info,
0,
WSA_FLAG_OVERLAPPED);
@@ -1126,7 +1144,7 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info,
err = uv_tcp_set_socket(tcp->loop,
tcp,
socket,
- socket_protocol_info->iAddressFamily,
+ socket_info_ex->socket_info.iAddressFamily,
1);
if (err) {
closesocket(socket);
@@ -1141,6 +1159,8 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info,
tcp->flags |= UV_HANDLE_BOUND;
tcp->flags |= UV_HANDLE_SHARED_TCP_SOCKET;
+ tcp->delayed_error = socket_info_ex->delayed_error;
+
tcp->loop->active_tcp_streams++;
return 0;
}
@@ -1201,13 +1221,10 @@ int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
return ERROR_INVALID_PARAMETER;
}
- /* Report any deferred bind errors now. */
- if (handle->flags & UV_HANDLE_BIND_ERROR) {
- return handle->bind_error;
- }
-
- if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) {
- return WSAGetLastError();
+ if (!(handle->delayed_error)) {
+ if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) {
+ handle->delayed_error = WSAGetLastError();
+ }
}
}
}
diff --git a/deps/uv/src/win/threadpool.c b/deps/uv/src/win/threadpool.c
deleted file mode 100644
index 9539844c66..0000000000
--- a/deps/uv/src/win/threadpool.c
+++ /dev/null
@@ -1,81 +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 <assert.h>
-
-#include "uv.h"
-#include "internal.h"
-#include "req-inl.h"
-
-
-static void uv_work_req_init(uv_loop_t* loop, uv_work_t* req,
- uv_work_cb work_cb, uv_after_work_cb after_work_cb) {
- uv_req_init(loop, (uv_req_t*) req);
- req->type = UV_WORK;
- req->loop = loop;
- req->work_cb = work_cb;
- req->after_work_cb = after_work_cb;
- memset(&req->overlapped, 0, sizeof(req->overlapped));
-}
-
-
-static DWORD WINAPI uv_work_thread_proc(void* parameter) {
- uv_work_t* req = (uv_work_t*)parameter;
- uv_loop_t* loop = req->loop;
-
- assert(req != NULL);
- assert(req->type == UV_WORK);
- assert(req->work_cb);
-
- req->work_cb(req);
-
- POST_COMPLETION_FOR_REQ(loop, req);
-
- return 0;
-}
-
-
-int uv_queue_work(uv_loop_t* loop, uv_work_t* req, uv_work_cb work_cb,
- uv_after_work_cb after_work_cb) {
- if (work_cb == NULL)
- return UV_EINVAL;
-
- uv_work_req_init(loop, req, work_cb, after_work_cb);
-
- if (!QueueUserWorkItem(&uv_work_thread_proc, req, WT_EXECUTELONGFUNCTION)) {
- return uv_translate_sys_error(GetLastError());
- }
-
- uv__req_register(loop, req);
- return 0;
-}
-
-
-int uv_cancel(uv_req_t* req) {
- return UV_ENOSYS;
-}
-
-
-void uv_process_work_req(uv_loop_t* loop, uv_work_t* req) {
- uv__req_unregister(loop, req);
- if(req->after_work_cb)
- req->after_work_cb(req, 0);
-}
diff --git a/deps/uv/src/win/timer.c b/deps/uv/src/win/timer.c
index 16a2fc5f5f..c229d4c897 100644
--- a/deps/uv/src/win/timer.c
+++ b/deps/uv/src/win/timer.c
@@ -36,10 +36,11 @@ void uv_update_time(uv_loop_t* loop) {
time.QuadPart = loop->time;
- /* GetTickCount() can conceivably wrap around, so when the current tick */
- /* count is lower than the last tick count, we'll assume it has wrapped. */
- /* uv_poll must make sure that the timer can never overflow more than */
- /* once between two subsequent uv_update_time calls. */
+ /* GetTickCount() can conceivably wrap around, so when the current tick
+ * count is lower than the last tick count, we'll assume it has wrapped.
+ * uv_poll must make sure that the timer can never overflow more than
+ * once between two subsequent uv_update_time calls.
+ */
time.LowPart = ticks;
if (ticks < loop->last_tick_count)
time.HighPart++;
@@ -47,13 +48,14 @@ void uv_update_time(uv_loop_t* loop) {
/* Remember the last tick count. */
loop->last_tick_count = ticks;
- /* The GetTickCount() resolution isn't too good. Sometimes it'll happen */
- /* that GetQueuedCompletionStatus() or GetQueuedCompletionStatusEx() has */
- /* waited for a couple of ms but this is not reflected in the GetTickCount */
- /* result yet. Therefore whenever GetQueuedCompletionStatus times out */
- /* we'll add the number of ms that it has waited to the current loop time. */
- /* When that happened the loop time might be a little ms farther than what */
- /* we've just computed, and we shouldn't update the loop time. */
+ /* The GetTickCount() resolution isn't too good. Sometimes it'll happen
+ * that GetQueuedCompletionStatus() or GetQueuedCompletionStatusEx() has
+ * waited for a couple of ms but this is not reflected in the GetTickCount
+ * result yet. Therefore whenever GetQueuedCompletionStatus times out
+ * we'll add the number of ms that it has waited to the current loop time.
+ * When that happened the loop time might be a little ms farther than what
+ * we've just computed, and we shouldn't update the loop time.
+ */
if (loop->time < time.QuadPart)
loop->time = time.QuadPart;
}
@@ -193,24 +195,26 @@ uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
}
-DWORD uv_get_poll_timeout(uv_loop_t* loop) {
+DWORD uv__next_timeout(const uv_loop_t* loop) {
uv_timer_t* timer;
int64_t delta;
- /* Check if there are any running timers */
- timer = RB_MIN(uv_timer_tree_s, &loop->timers);
+ /* Check if there are any running timers
+ * Need to cast away const first, since RB_MIN doesn't know what we are
+ * going to do with this return value, it can't be marked const
+ */
+ timer = RB_MIN(uv_timer_tree_s, &((uv_loop_t*)loop)->timers);
if (timer) {
- uv_update_time(loop);
-
delta = timer->due - loop->time;
if (delta >= UINT_MAX >> 1) {
- /* A timeout value of UINT_MAX means infinite, so that's no good. But */
- /* more importantly, there's always the risk that GetTickCount wraps. */
- /* uv_update_time can detect this, but we must make sure that the */
- /* tick counter never overflows twice between two subsequent */
- /* uv_update_time calls. We do this by never sleeping more than half */
- /* the time it takes to wrap the counter - which is huge overkill, */
- /* but hey, it's not so bad to wake up every 25 days. */
+ /* A timeout value of UINT_MAX means infinite, so that's no good. But
+ * more importantly, there's always the risk that GetTickCount wraps.
+ * uv_update_time can detect this, but we must make sure that the
+ * tick counter never overflows twice between two subsequent
+ * uv_update_time calls. We do this by never sleeping more than half
+ * the time it takes to wrap the counter - which is huge overkill,
+ * but hey, it's not so bad to wake up every 25 days.
+ */
return UINT_MAX >> 1;
} else if (delta < 0) {
/* Negative timeout values are not allowed */
diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c
index 87e3eb5d8a..6b8297cbd9 100644
--- a/deps/uv/src/win/tty.c
+++ b/deps/uv/src/win/tty.c
@@ -30,6 +30,10 @@
# include <stdint.h>
#endif
+#ifndef COMMON_LVB_REVERSE_VIDEO
+# define COMMON_LVB_REVERSE_VIDEO 0x4000
+#endif
+
#include "uv.h"
#include "internal.h"
#include "handle-inl.h"
diff --git a/deps/uv/src/win/udp.c b/deps/uv/src/win/udp.c
index 865890455a..ef63dd73df 100644
--- a/deps/uv/src/win/udp.c
+++ b/deps/uv/src/win/udp.c
@@ -37,8 +37,9 @@ const unsigned int uv_active_udp_streams_threshold = 0;
/* A zero-size buffer for use by uv_udp_read */
static char uv_zero_[] = "";
-int uv_udp_getsockname(uv_udp_t* handle, struct sockaddr* name,
- int* namelen) {
+int uv_udp_getsockname(const uv_udp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
int result;
if (!(handle->flags & UV_HANDLE_BOUND)) {
@@ -129,6 +130,8 @@ int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
handle->activecnt = 0;
handle->func_wsarecv = WSARecv;
handle->func_wsarecvfrom = WSARecvFrom;
+ handle->send_queue_size = 0;
+ handle->send_queue_count = 0;
uv_req_init(loop, (uv_req_t*) &(handle->recv_req));
handle->recv_req.type = UV_UDP_RECV;
@@ -396,12 +399,16 @@ static int uv__send(uv_udp_send_t* req,
/* Request completed immediately. */
req->queued_bytes = 0;
handle->reqs_pending++;
+ handle->send_queue_size += req->queued_bytes;
+ handle->send_queue_count++;
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, nbufs);
+ req->queued_bytes = uv__count_bufs(bufs, nbufs);
handle->reqs_pending++;
+ handle->send_queue_size += req->queued_bytes;
+ handle->send_queue_count++;
REGISTER_HANDLE_REQ(loop, handle, req);
} else {
/* Send failed due to an error. */
@@ -524,6 +531,11 @@ void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
assert(handle->type == UV_UDP);
+ assert(handle->send_queue_size >= req->queued_bytes);
+ assert(handle->send_queue_count >= 1);
+ handle->send_queue_size -= req->queued_bytes;
+ handle->send_queue_count--;
+
UNREGISTER_HANDLE_REQ(loop, handle, req);
if (req->cb) {
@@ -860,3 +872,12 @@ int uv__udp_send(uv_udp_send_t* req,
return 0;
}
+
+
+int uv__udp_try_send(uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen) {
+ return UV_ENOSYS;
+}