diff options
Diffstat (limited to 'deps/uv/src/win')
-rw-r--r-- | deps/uv/src/win/core.c | 161 | ||||
-rw-r--r-- | deps/uv/src/win/error.c | 1 | ||||
-rw-r--r-- | deps/uv/src/win/fs.c | 177 | ||||
-rw-r--r-- | deps/uv/src/win/getaddrinfo.c | 63 | ||||
-rw-r--r-- | deps/uv/src/win/getnameinfo.c | 61 | ||||
-rw-r--r-- | deps/uv/src/win/internal.h | 35 | ||||
-rw-r--r-- | deps/uv/src/win/pipe.c | 64 | ||||
-rw-r--r-- | deps/uv/src/win/process.c | 280 | ||||
-rw-r--r-- | deps/uv/src/win/req-inl.h | 16 | ||||
-rw-r--r-- | deps/uv/src/win/stream-inl.h | 11 | ||||
-rw-r--r-- | deps/uv/src/win/tcp.c | 65 | ||||
-rw-r--r-- | deps/uv/src/win/threadpool.c | 81 | ||||
-rw-r--r-- | deps/uv/src/win/timer.c | 50 | ||||
-rw-r--r-- | deps/uv/src/win/tty.c | 4 | ||||
-rw-r--r-- | deps/uv/src/win/udp.c | 27 |
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, ¤t_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; +} |