diff options
Diffstat (limited to 'deps/uv/src/win')
-rw-r--r-- | deps/uv/src/win/async.c | 22 | ||||
-rw-r--r-- | deps/uv/src/win/cares.c | 8 | ||||
-rw-r--r-- | deps/uv/src/win/core.c | 57 | ||||
-rw-r--r-- | deps/uv/src/win/dl.c | 76 | ||||
-rw-r--r-- | deps/uv/src/win/error.c | 1 | ||||
-rw-r--r-- | deps/uv/src/win/fs-event.c | 36 | ||||
-rw-r--r-- | deps/uv/src/win/fs.c | 405 | ||||
-rw-r--r-- | deps/uv/src/win/getaddrinfo.c | 118 | ||||
-rw-r--r-- | deps/uv/src/win/handle.c | 61 | ||||
-rw-r--r-- | deps/uv/src/win/internal.h | 142 | ||||
-rw-r--r-- | deps/uv/src/win/loop-watcher.c | 13 | ||||
-rw-r--r-- | deps/uv/src/win/pipe.c | 93 | ||||
-rw-r--r-- | deps/uv/src/win/poll.c | 620 | ||||
-rw-r--r-- | deps/uv/src/win/process.c | 78 | ||||
-rw-r--r-- | deps/uv/src/win/req.c | 9 | ||||
-rw-r--r-- | deps/uv/src/win/stream.c | 15 | ||||
-rw-r--r-- | deps/uv/src/win/tcp.c | 148 | ||||
-rw-r--r-- | deps/uv/src/win/thread.c | 5 | ||||
-rw-r--r-- | deps/uv/src/win/threadpool.c | 4 | ||||
-rw-r--r-- | deps/uv/src/win/timer.c | 18 | ||||
-rw-r--r-- | deps/uv/src/win/tty.c | 32 | ||||
-rw-r--r-- | deps/uv/src/win/udp.c | 33 | ||||
-rw-r--r-- | deps/uv/src/win/util.c | 7 | ||||
-rw-r--r-- | deps/uv/src/win/winapi.c | 5 | ||||
-rw-r--r-- | deps/uv/src/win/winapi.h | 9 | ||||
-rw-r--r-- | deps/uv/src/win/winsock.c | 89 | ||||
-rw-r--r-- | deps/uv/src/win/winsock.h | 39 |
27 files changed, 1679 insertions, 464 deletions
diff --git a/deps/uv/src/win/async.c b/deps/uv/src/win/async.c index b68a868054..9df75e08e9 100644 --- a/deps/uv/src/win/async.c +++ b/deps/uv/src/win/async.c @@ -59,12 +59,11 @@ void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) { !handle->async_sent) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } - - uv_unref(loop); } } @@ -72,12 +71,8 @@ void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) { int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { uv_req_t* req; - loop->counters.handle_init++; - loop->counters.async_init++; - + uv_handle_init(loop, (uv_handle_t*) handle); handle->type = UV_ASYNC; - handle->loop = loop; - handle->flags = 0; handle->async_sent = 0; handle->async_cb = async_cb; @@ -86,12 +81,23 @@ int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) { req->type = UV_WAKEUP; req->data = handle; - uv_ref(loop); + loop->counters.async_init++; + + uv__handle_start(handle); return 0; } +void uv_async_close(uv_loop_t* loop, uv_async_t* handle) { + if (!((uv_async_t*)handle)->async_sent) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } + + uv__handle_start(handle); +} + + int uv_async_send(uv_async_t* handle) { uv_loop_t* loop = handle->loop; diff --git a/deps/uv/src/win/cares.c b/deps/uv/src/win/cares.c index 1592d12345..359bc213ed 100644 --- a/deps/uv/src/win/cares.c +++ b/deps/uv/src/win/cares.c @@ -22,7 +22,6 @@ #include <assert.h> #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -108,8 +107,6 @@ static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read, uv_loop_t* loop = (uv_loop_t*) data; uv_ares_task_t* uv_handle_ares = uv_find_ares_handle(loop, sock); - int timeoutms = 0; - if (read == 0 && write == 0) { /* if read and write are 0, cleanup existing data */ /* The code assumes that c-ares does a callback with read = 0 and */ @@ -134,6 +131,7 @@ static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read, } /* remove handle from list */ uv_remove_ares_handle(uv_handle_ares); + uv__handle_stop(uv_handle_ares); /* Post request to cleanup the Task */ uv_ares_req = &uv_handle_ares->ares_req; @@ -180,7 +178,7 @@ static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read, /* add handle to list */ uv_add_ares_handle(loop, uv_handle_ares); - uv_ref(loop); + uv__handle_start(uv_handle_ares); /* * we have a single polling timer for all ares sockets. @@ -231,7 +229,7 @@ void uv_process_ares_cleanup_req(uv_loop_t* loop, uv_ares_task_t* handle, unsigned int signaled = WaitForSingleObject(handle->h_close_event, 0); if (signaled != WAIT_TIMEOUT) { - uv_unref(loop); + uv__handle_stop(loop); /* close event handle and free uv handle memory */ CloseHandle(handle->h_close_event); diff --git a/deps/uv/src/win/core.c b/deps/uv/src/win/core.c index 1358cb29cb..27f3438b92 100644 --- a/deps/uv/src/win/core.c +++ b/deps/uv/src/win/core.c @@ -27,7 +27,6 @@ #include <string.h> #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -65,10 +64,16 @@ static void uv_loop_init(uv_loop_t* loop) { uv_fatal_error(GetLastError(), "CreateIoCompletionPort"); } - loop->refs = 0; - uv_update_time(loop); +#ifndef UV_LEAN_AND_MEAN + ngx_queue_init(&loop->active_handles); + ngx_queue_init(&loop->active_reqs); +#else + loop->active_handles = 0; + loop->active_reqs = 0; +#endif + loop->pending_reqs_tail = NULL; loop->endgame_handles = NULL; @@ -84,6 +89,8 @@ static void uv_loop_init(uv_loop_t* loop) { loop->next_check_handle = NULL; loop->next_idle_handle = NULL; + memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets); + loop->ares_active_sockets = 0; loop->ares_chan = NULL; @@ -130,26 +137,19 @@ uv_loop_t* uv_loop_new(void) { void uv_loop_delete(uv_loop_t* loop) { if (loop != &uv_default_loop_) { + int 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); + } + } + free(loop); } } -int uv_loop_refcount(const uv_loop_t* loop) { - return loop->refs; -} - - -void uv_ref(uv_loop_t* loop) { - loop->refs++; -} - - -void uv_unref(uv_loop_t* loop) { - loop->refs--; -} - - static void uv_poll(uv_loop_t* loop, int block) { BOOL success; DWORD bytes, timeout; @@ -216,6 +216,19 @@ static void uv_poll_ex(uv_loop_t* loop, int block) { } } +#ifndef UV_LEAN_AND_MEAN +# define UV_LOOP_ALIVE(loop) \ + (!ngx_queue_empty(&(loop)->active_handles) || \ + !ngx_queue_empty(&(loop)->active_reqs) || \ + (loop)->endgame_handles != NULL) +#else +# define UV_LOOP_ALIVE(loop) \ + ((loop)->active_handles > 0 && \ + (loop)->active_reqs > 0 && \ + (loop)->endgame_handles != NULL) +#endif + + #define UV_LOOP_ONCE(loop, poll) \ do { \ uv_update_time((loop)); \ @@ -230,7 +243,7 @@ static void uv_poll_ex(uv_loop_t* loop, int block) { uv_process_reqs((loop)); \ uv_process_endgames((loop)); \ \ - if ((loop)->refs <= 0) { \ + if (!UV_LOOP_ALIVE((loop))) { \ break; \ } \ \ @@ -239,13 +252,13 @@ static void uv_poll_ex(uv_loop_t* loop, int block) { poll((loop), (loop)->idle_handles == NULL && \ (loop)->pending_reqs_tail == NULL && \ (loop)->endgame_handles == NULL && \ - (loop)->refs > 0); \ + UV_LOOP_ALIVE((loop))); \ \ uv_check_invoke((loop)); \ } while (0); #define UV_LOOP(loop, poll) \ - while ((loop)->refs > 0) { \ + while (UV_LOOP_ALIVE((loop))) { \ UV_LOOP_ONCE(loop, poll) \ } @@ -267,6 +280,6 @@ int uv_run(uv_loop_t* loop) { UV_LOOP(loop, uv_poll); } - assert(loop->refs == 0); + assert(!UV_LOOP_ALIVE((loop))); return 0; } diff --git a/deps/uv/src/win/dl.c b/deps/uv/src/win/dl.c index 08374d37fb..88ddd74b54 100644 --- a/deps/uv/src/win/dl.c +++ b/deps/uv/src/win/dl.c @@ -22,61 +22,65 @@ #include "uv.h" #include "internal.h" -__declspec( thread ) DWORD saved_errno = 0; +static int uv__dlerror(uv_lib_t* lib, int errorno); -uv_err_t uv_dlopen(const char* filename, uv_lib_t* library) { + +int uv_dlopen(const char* filename, uv_lib_t* lib) { wchar_t filename_w[32768]; - HMODULE handle; - if (!uv_utf8_to_utf16(filename, - filename_w, - sizeof(filename_w) / sizeof(wchar_t))) { - saved_errno = GetLastError(); - return uv__new_sys_error(saved_errno); + lib->handle = NULL; + lib->errmsg = NULL; + + if (!uv_utf8_to_utf16(filename, filename_w, ARRAY_SIZE(filename_w))) { + return uv__dlerror(lib, GetLastError()); } - handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); - if (handle == NULL) { - saved_errno = GetLastError(); - return uv__new_sys_error(saved_errno); + lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (lib->handle == NULL) { + return uv__dlerror(lib, GetLastError()); } - *library = handle; - return uv_ok_; + return 0; } -uv_err_t uv_dlclose(uv_lib_t library) { - if (!FreeLibrary(library)) { - saved_errno = GetLastError(); - return uv__new_sys_error(saved_errno); +void uv_dlclose(uv_lib_t* lib) { + if (lib->errmsg) { + LocalFree((void*)lib->errmsg); + lib->errmsg = NULL; } - return uv_ok_; + if (lib->handle) { + /* Ignore errors. No good way to signal them without leaking memory. */ + FreeLibrary(lib->handle); + lib->handle = NULL; + } } -uv_err_t uv_dlsym(uv_lib_t library, const char* name, void** ptr) { - FARPROC proc = GetProcAddress(library, name); - if (proc == NULL) { - saved_errno = GetLastError(); - return uv__new_sys_error(saved_errno); - } - - *ptr = (void*) proc; - return uv_ok_; +int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) { + *ptr = (void*) GetProcAddress(lib->handle, name); + return uv__dlerror(lib, *ptr ? 0 : GetLastError()); } -const char *uv_dlerror(uv_lib_t library) { - char* buf = NULL; - FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, NULL, saved_errno, - MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (LPSTR)&buf, 0, NULL); - return buf; +const char* uv_dlerror(uv_lib_t* lib) { + return lib->errmsg ? lib->errmsg : "no error"; } -void uv_dlerror_free(uv_lib_t library, const char *msg) { - LocalFree((LPVOID)msg); +static int uv__dlerror(uv_lib_t* lib, int errorno) { + if (lib->errmsg) { + LocalFree((void*)lib->errmsg); + lib->errmsg = NULL; + } + + if (errorno) { + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno, + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + (LPSTR)&lib->errmsg, 0, NULL); + } + + return errorno ? -1 : 0; } diff --git a/deps/uv/src/win/error.c b/deps/uv/src/win/error.c index 294041264c..bdbb3b293e 100644 --- a/deps/uv/src/win/error.c +++ b/deps/uv/src/win/error.c @@ -26,7 +26,6 @@ #include <string.h> #include "uv.h" -#include "../uv-common.h" #include "internal.h" diff --git a/deps/uv/src/win/fs-event.c b/deps/uv/src/win/fs-event.c index 1003201f3f..61f9de23ab 100644 --- a/deps/uv/src/win/fs-event.c +++ b/deps/uv/src/win/fs-event.c @@ -19,13 +19,14 @@ * IN THE SOFTWARE. */ +#include "uv.h" +#include "internal.h" + #include <assert.h> #include <malloc.h> #include <errno.h> #include <stdio.h> #include <string.h> -#include "uv.h" -#include "internal.h" const unsigned int uv_directory_watcher_buffer_size = 4096; @@ -33,9 +34,8 @@ const unsigned int uv_directory_watcher_buffer_size = 4096; static void uv_fs_event_init_handle(uv_loop_t* loop, uv_fs_event_t* handle, const char* filename, uv_fs_event_cb cb) { + uv_handle_init(loop, (uv_handle_t*) handle); handle->type = UV_FS_EVENT; - handle->loop = loop; - handle->flags = 0; handle->cb = cb; handle->dir_handle = INVALID_HANDLE_VALUE; handle->buffer = NULL; @@ -53,10 +53,9 @@ static void uv_fs_event_init_handle(uv_loop_t* loop, uv_fs_event_t* handle, uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } - loop->counters.handle_init++; - loop->counters.fs_event_init++; + uv__handle_start(handle); - uv_ref(loop); + loop->counters.fs_event_init++; } @@ -109,7 +108,7 @@ static int uv_split_path(const wchar_t* filename, wchar_t** dir, return -1; } } - + *file = wcsdup(filename); } else { if (dir) { @@ -152,7 +151,7 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle, uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } - if (!uv_utf8_to_utf16(filename, filenamew, + if (!uv_utf8_to_utf16(filename, filenamew, name_size / sizeof(wchar_t))) { uv__set_sys_error(loop, GetLastError()); return -1; @@ -172,11 +171,11 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle, handle->dirw = filenamew; dir_to_watch = filenamew; } else { - /* + /* * filename is a file. So we split filename into dir & file parts, and * watch the dir directory. */ - + /* Convert to short path. */ if (!GetShortPathNameW(filenamew, short_path, ARRAY_SIZE(short_path))) { last_error = GetLastError(); @@ -226,7 +225,7 @@ int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle, goto error; } - handle->buffer = (char*)_aligned_malloc(uv_directory_watcher_buffer_size, + handle->buffer = (char*)_aligned_malloc(uv_directory_watcher_buffer_size, sizeof(DWORD)); if (!handle->buffer) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); @@ -317,7 +316,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, assert(!filename); assert(!long_filenamew); - /* + /* * Fire the event only if we were asked to watch a directory, * or if the filename filter matches. */ @@ -328,8 +327,8 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, file_info->FileNameLength / sizeof(wchar_t)) == 0) { if (handle->dirw) { - /* - * We attempt to convert the file name to its long form for + /* + * We attempt to convert the file name to its long form for * events that still point to valid files on disk. * For removed and renamed events, we do not provide the file name. */ @@ -382,7 +381,7 @@ void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req, } } - /* + /* * If we couldn't get the long name - just use the name * provided by ReadDirectoryChangesW. */ @@ -471,6 +470,8 @@ void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) { if (!handle->req_pending) { uv_want_endgame(loop, (uv_handle_t*)handle); } + + uv__handle_start(handle); } @@ -479,6 +480,7 @@ void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) { !handle->req_pending) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->buffer) { _aligned_free(handle->buffer); @@ -508,7 +510,5 @@ void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) { if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } - - uv_unref(loop); } } diff --git a/deps/uv/src/win/fs.c b/deps/uv/src/win/fs.c index 3cbb66f242..924554b3e7 100644 --- a/deps/uv/src/win/fs.c +++ b/deps/uv/src/win/fs.c @@ -59,7 +59,7 @@ return -1; \ } \ req->flags |= UV_FS_ASYNC_QUEUED; \ - uv_ref((loop)); + uv__req_register(loop, req); #define SET_UV_LAST_ERROR_FROM_REQ(req) \ uv__set_error(req->loop, req->errorno, req->sys_errno_); @@ -89,6 +89,16 @@ return; \ } +#define IS_SLASH(c) ((c) == L'\\' || (c) == L'/') +#define IS_LETTER(c) (((c) >= L'a' && (c) <= L'z') || \ + ((c) >= L'A' && (c) <= L'Z')) + +const wchar_t JUNCTION_PREFIX[] = L"\\??\\"; +const wchar_t JUNCTION_PREFIX_LEN = 4; + +const wchar_t LONG_PATH_PREFIX[] = L"\\\\?\\"; +const wchar_t LONG_PATH_PREFIX_LEN = 4; + void uv_fs_init() { _fmode = _O_BINARY; @@ -128,6 +138,61 @@ static void uv_fs_req_init_sync(uv_loop_t* loop, uv_fs_t* req, } +static int is_path_dir(const wchar_t* path) { + DWORD attr = GetFileAttributesW(path); + + if (attr != INVALID_FILE_ATTRIBUTES) { + return attr & FILE_ATTRIBUTE_DIRECTORY ? 1 : 0; + } else { + return 0; + } +} + + +static int get_reparse_point(HANDLE handle, int* target_length) { + void* buffer = NULL; + REPARSE_DATA_BUFFER* reparse_data; + DWORD bytes_returned; + int rv = 0; + + buffer = malloc(MAXIMUM_REPARSE_DATA_BUFFER_SIZE); + if (!buffer) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + if (!DeviceIoControl(handle, + FSCTL_GET_REPARSE_POINT, + NULL, + 0, + buffer, + MAXIMUM_REPARSE_DATA_BUFFER_SIZE, + &bytes_returned, + NULL)) { + free(buffer); + return 0; + } + + reparse_data = (REPARSE_DATA_BUFFER*)buffer; + + if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + rv = 1; + if (target_length) { + *target_length = reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / + sizeof(wchar_t); + } + } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { + rv = 1; + if (target_length) { + *target_length = reparse_data->MountPointReparseBuffer.SubstituteNameLength / + sizeof(wchar_t); + } + } + + free(buffer); + return rv; +} + + void fs__open(uv_fs_t* req, const wchar_t* path, int flags, int mode) { DWORD access; DWORD share; @@ -224,10 +289,8 @@ void fs__open(uv_fs_t* req, const wchar_t* path, int flags, int mode) { goto end; } - /* Figure out whether path is a file or a directory. */ - if (GetFileAttributesW(path) & FILE_ATTRIBUTE_DIRECTORY) { - attributes |= FILE_FLAG_BACKUP_SEMANTICS; - } + /* Setting this flag makes it possible to open a directory. */ + attributes |= FILE_FLAG_BACKUP_SEMANTICS; file = CreateFileW(path, access, @@ -349,20 +412,53 @@ void fs__write(uv_fs_t* req, uv_file file, void *buf, size_t length, } -void fs__unlink(uv_fs_t* req, const wchar_t* path) { - int result = _wunlink(path); +void fs__rmdir(uv_fs_t* req, const wchar_t* path) { + int result = _wrmdir(path); SET_REQ_RESULT(req, result); } -void fs__mkdir(uv_fs_t* req, const wchar_t* path, int mode) { - int result = _wmkdir(path); - SET_REQ_RESULT(req, result); +void fs__unlink(uv_fs_t* req, const wchar_t* path) { + int result; + HANDLE handle; + BY_HANDLE_FILE_INFORMATION info; + int is_dir_symlink; + + handle = CreateFileW(path, + 0, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, + NULL); + + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + return; + } + + if (!GetFileInformationByHandle(handle, &info)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + CloseHandle(handle); + return; + } + + is_dir_symlink = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY && + get_reparse_point(handle, NULL); + + CloseHandle(handle); + + if (is_dir_symlink) { + fs__rmdir(req, path); + } else { + result = _wunlink(path); + SET_REQ_RESULT(req, result); + } } -void fs__rmdir(uv_fs_t* req, const wchar_t* path) { - int result = _wrmdir(path); +void fs__mkdir(uv_fs_t* req, const wchar_t* path, int mode) { + int result = _wmkdir(path); SET_REQ_RESULT(req, result); } @@ -474,18 +570,26 @@ void fs__readdir(uv_fs_t* req, const wchar_t* path, int flags) { } -static void fs__stat(uv_fs_t* req, const wchar_t* path) { +static void fs__stat(uv_fs_t* req, const wchar_t* path, int link) { HANDLE handle; + int target_length; + int symlink = 0; BY_HANDLE_FILE_INFORMATION info; + DWORD flags; req->ptr = NULL; + flags = FILE_FLAG_BACKUP_SEMANTICS; + + if (link) { + flags |= FILE_FLAG_OPEN_REPARSE_POINT; + } handle = CreateFileW(path, FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, + flags, NULL); if (handle == INVALID_HANDLE_VALUE) { SET_REQ_WIN32_ERROR(req, GetLastError()); @@ -502,32 +606,37 @@ static void fs__stat(uv_fs_t* req, const wchar_t* path) { /* TODO: set st_dev and st_ino? */ - if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { - req->stat.st_mode |= (_S_IREAD + (_S_IREAD >> 3) + (_S_IREAD >> 6)); + if (link && get_reparse_point(handle, &target_length)) { + req->stat.st_mode = S_IFLNK; + /* Adjust for long path */ + req->stat.st_size = target_length - JUNCTION_PREFIX_LEN; } else { - req->stat.st_mode |= ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) + - ((_S_IREAD|_S_IWRITE) >> 6)); - } + if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) { + req->stat.st_mode |= (_S_IREAD + (_S_IREAD >> 3) + (_S_IREAD >> 6)); + } else { + req->stat.st_mode |= ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3) + + ((_S_IREAD|_S_IWRITE) >> 6)); + } - if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - req->stat.st_mode |= _S_IFDIR; - } else { - req->stat.st_mode |= _S_IFREG; + if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + req->stat.st_mode |= _S_IFDIR; + } else { + req->stat.st_mode |= _S_IFREG; + } + + req->stat.st_size = ((int64_t) info.nFileSizeHigh << 32) + + (int64_t) info.nFileSizeLow; } uv_filetime_to_time_t(&info.ftLastWriteTime, &(req->stat.st_mtime)); uv_filetime_to_time_t(&info.ftLastAccessTime, &(req->stat.st_atime)); uv_filetime_to_time_t(&info.ftCreationTime, &(req->stat.st_ctime)); - req->stat.st_size = ((int64_t) info.nFileSizeHigh << 32) + - (int64_t) info.nFileSizeLow; - req->stat.st_nlink = (info.nNumberOfLinks <= SHRT_MAX) ? (short) info.nNumberOfLinks : SHRT_MAX; req->ptr = &req->stat; req->result = 0; - CloseHandle(handle); } @@ -573,12 +682,28 @@ void fs__fsync(uv_fs_t* req, uv_file file) { void fs__ftruncate(uv_fs_t* req, uv_file file, int64_t offset) { - int result; + HANDLE handle; + NTSTATUS status; + IO_STATUS_BLOCK io_status; + FILE_END_OF_FILE_INFORMATION eof_info; VERIFY_UV_FILE(file, req); - result = _chsize_s(file, offset); - SET_REQ_RESULT(req, result); + handle = (HANDLE)_get_osfhandle(file); + + eof_info.EndOfFile.QuadPart = offset; + + status = pNtSetInformationFile(handle, + &io_status, + &eof_info, + sizeof eof_info, + FileEndOfFileInformation); + + if (NT_SUCCESS(status)) { + SET_REQ_RESULT(req, 0); + } else { + SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status)); + } } @@ -706,23 +831,193 @@ void fs__link(uv_fs_t* req, const wchar_t* path, const wchar_t* new_path) { } +void fs__create_junction(uv_fs_t* req, const wchar_t* path, const wchar_t* new_path) { + HANDLE handle = INVALID_HANDLE_VALUE; + REPARSE_DATA_BUFFER *buffer = NULL; + int created = 0; + int target_len; + int is_absolute, is_long_path; + int needed_buf_size, used_buf_size, used_data_size, path_buf_len; + int start, len, i; + int add_slash; + DWORD bytes; + wchar_t* path_buf; + + target_len = wcslen(path); + is_long_path = wcsncmp(path, LONG_PATH_PREFIX, LONG_PATH_PREFIX_LEN) == 0; + + if (is_long_path) { + is_absolute = 1; + } else { + is_absolute = target_len >= 3 && IS_LETTER(path[0]) && + path[1] == L':' && IS_SLASH(path[2]); + } + + if (!is_absolute) { + /* Not supporting relative paths */ + SET_REQ_UV_ERROR(req, EINVAL, ERROR_NOT_SUPPORTED); + return; + } + + // Do a pessimistic calculation of the required buffer size + needed_buf_size = + FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) + + JUNCTION_PREFIX_LEN * sizeof(wchar_t) + + 2 * (target_len + 2) * sizeof(wchar_t); + + // Allocate the buffer + buffer = (REPARSE_DATA_BUFFER*)malloc(needed_buf_size); + if (!buffer) { + uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); + } + + // Grab a pointer to the part of the buffer where filenames go + path_buf = (wchar_t*)&(buffer->MountPointReparseBuffer.PathBuffer); + path_buf_len = 0; + + // Copy the substitute (internal) target path + start = path_buf_len; + + wcsncpy((wchar_t*)&path_buf[path_buf_len], JUNCTION_PREFIX, + JUNCTION_PREFIX_LEN); + path_buf_len += JUNCTION_PREFIX_LEN; + + add_slash = 0; + for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) { + if (IS_SLASH(path[i])) { + add_slash = 1; + continue; + } + + if (add_slash) { + path_buf[path_buf_len++] = L'\\'; + add_slash = 0; + } + + path_buf[path_buf_len++] = path[i]; + } + path_buf[path_buf_len++] = L'\\'; + len = path_buf_len - start; + + // Set the info about the substitute name + buffer->MountPointReparseBuffer.SubstituteNameOffset = start * sizeof(wchar_t); + buffer->MountPointReparseBuffer.SubstituteNameLength = len * sizeof(wchar_t); + + // Insert null terminator + path_buf[path_buf_len++] = L'\0'; + + // Copy the print name of the target path + start = path_buf_len; + add_slash = 0; + for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) { + if (IS_SLASH(path[i])) { + add_slash = 1; + continue; + } + + if (add_slash) { + path_buf[path_buf_len++] = L'\\'; + add_slash = 0; + } + + path_buf[path_buf_len++] = path[i]; + } + len = path_buf_len - start; + if (len == 2) { + path_buf[path_buf_len++] = L'\\'; + len++; + } + + // Set the info about the print name + buffer->MountPointReparseBuffer.PrintNameOffset = start * sizeof(wchar_t); + buffer->MountPointReparseBuffer.PrintNameLength = len * sizeof(wchar_t); + + // Insert another null terminator + path_buf[path_buf_len++] = L'\0'; + + // Calculate how much buffer space was actually used + used_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) + + path_buf_len * sizeof(wchar_t); + used_data_size = used_buf_size - + FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer); + + // Put general info in the data buffer + buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; + buffer->ReparseDataLength = used_data_size; + buffer->Reserved = 0; + + // Create a new directory + if (!CreateDirectoryW(new_path, NULL)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto error; + } + created = 1; + + // Open the directory + handle = CreateFileW(new_path, + GENERIC_ALL, + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_FLAG_OPEN_REPARSE_POINT, + NULL); + if (handle == INVALID_HANDLE_VALUE) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto error; + } + + // Create the actual reparse point + if (!DeviceIoControl(handle, + FSCTL_SET_REPARSE_POINT, + buffer, + used_buf_size, + NULL, + 0, + &bytes, + NULL)) { + SET_REQ_WIN32_ERROR(req, GetLastError()); + goto error; + } + + // Clean up + CloseHandle(handle); + free(buffer); + + SET_REQ_RESULT(req, 0); + return; + +error: + free(buffer); + + if (handle != INVALID_HANDLE_VALUE) { + CloseHandle(handle); + } + + if (created) { + RemoveDirectoryW(new_path); + } +} + + void fs__symlink(uv_fs_t* req, const wchar_t* path, const wchar_t* new_path, int flags) { int result; - if (pCreateSymbolicLinkW) { + + if (flags & UV_FS_SYMLINK_JUNCTION) { + fs__create_junction(req, path, new_path); + } else if (pCreateSymbolicLinkW) { result = pCreateSymbolicLinkW(new_path, path, flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1; if (result == -1) { SET_REQ_WIN32_ERROR(req, GetLastError()); - return; + } else { + SET_REQ_RESULT(req, result); } } else { SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED); - return; } - - SET_REQ_RESULT(req, result); } @@ -772,22 +1067,31 @@ void fs__readlink(uv_fs_t* req, const wchar_t* path) { } reparse_data = (REPARSE_DATA_BUFFER*)buffer; - if (reparse_data->ReparseTag != IO_REPARSE_TAG_SYMLINK) { + if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) { + substitute_name = reparse_data->SymbolicLinkReparseBuffer.PathBuffer + + (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset / + sizeof(wchar_t)); + substitute_name_length = + reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / + sizeof(wchar_t); + } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) { + substitute_name = reparse_data->MountPointReparseBuffer.PathBuffer + + (reparse_data->MountPointReparseBuffer.SubstituteNameOffset / + sizeof(wchar_t)); + substitute_name_length = + reparse_data->MountPointReparseBuffer.SubstituteNameLength / + sizeof(wchar_t); + } else { result = -1; /* something is seriously wrong */ SET_REQ_WIN32_ERROR(req, GetLastError()); goto done; } - substitute_name = reparse_data->SymbolicLinkReparseBuffer.PathBuffer + - (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t)); - substitute_name_length = - reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t); - /* Strip off the leading \??\ from the substitute name buffer.*/ - if (memcmp(substitute_name, L"\\??\\", 8) == 0) { - substitute_name += 4; - substitute_name_length -= 4; + if (wcsncmp(substitute_name, JUNCTION_PREFIX, JUNCTION_PREFIX_LEN) == 0) { + substitute_name += JUNCTION_PREFIX_LEN; + substitute_name_length -= JUNCTION_PREFIX_LEN; } utf8size = uv_utf16_to_utf8(substitute_name, @@ -870,8 +1174,10 @@ static DWORD WINAPI uv_fs_thread_proc(void* parameter) { fs__readdir(req, req->pathw, req->file_flags); break; case UV_FS_STAT: + fs__stat(req, req->pathw, 0); + break; case UV_FS_LSTAT: - fs__stat(req, req->pathw); + fs__stat(req, req->pathw, 1); break; case UV_FS_FSTAT: fs__fstat(req, req->file); @@ -1246,7 +1552,7 @@ int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { } else { uv_fs_req_init_sync(loop, req, UV_FS_STAT); UTF8_TO_UTF16(path2 ? path2 : path, pathw); - fs__stat(req, pathw); + fs__stat(req, pathw, 0); if (path2) { free(path2); } @@ -1290,7 +1596,7 @@ int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) { } else { uv_fs_req_init_sync(loop, req, UV_FS_LSTAT); UTF8_TO_UTF16(path2 ? path2 : path, pathw); - fs__stat(req, pathw); + fs__stat(req, pathw, 1); if (path2) { free(path2); } @@ -1505,6 +1811,7 @@ int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file file, double atime, void uv_process_fs_req(uv_loop_t* loop, uv_fs_t* req) { assert(req->cb); + uv__req_unregister(loop, req); SET_UV_LAST_ERROR_FROM_REQ(req); req->cb(req); } @@ -1538,10 +1845,6 @@ void uv_fs_req_cleanup(uv_fs_t* req) { req->path = NULL; } - if (req->flags & UV_FS_ASYNC_QUEUED) { - uv_unref(loop); - } - req->flags |= UV_FS_CLEANEDUP; } diff --git a/deps/uv/src/win/getaddrinfo.c b/deps/uv/src/win/getaddrinfo.c index 5353c0b5f0..bdfe1bb93c 100644 --- a/deps/uv/src/win/getaddrinfo.c +++ b/deps/uv/src/win/getaddrinfo.c @@ -77,23 +77,21 @@ static uv_err_code uv_translate_eai_error(int eai_errno) { /* getaddrinfo worker thread implementation */ static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) { - uv_getaddrinfo_t* handle = (uv_getaddrinfo_t*) parameter; - uv_loop_t* loop = handle->loop; + uv_getaddrinfo_t* req = (uv_getaddrinfo_t*) parameter; + uv_loop_t* loop = req->loop; int ret; - assert(handle != NULL); + assert(req != NULL); - if (handle != NULL) { - /* call OS function on this thread */ - ret = GetAddrInfoW(handle->node, - handle->service, - handle->hints, - &handle->res); - handle->retcode = ret; + /* call OS function on this thread */ + ret = GetAddrInfoW(req->node, + req->service, + req->hints, + &req->res); + req->retcode = ret; - /* post getaddrinfo completed */ - POST_COMPLETION_FOR_REQ(loop, &handle->getadddrinfo_req); - } + /* post getaddrinfo completed */ + POST_COMPLETION_FOR_REQ(loop, req); return 0; } @@ -108,8 +106,7 @@ static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) { * and copy all structs and referenced strings into the one block. * Each size calculation is adjusted to avoid unaligned pointers. */ -void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* handle, - uv_req_t* req) { +void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req) { int addrinfo_len = 0; int name_len = 0; size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo)); @@ -120,15 +117,15 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* handle, int status = 0; /* release input parameter memory */ - if (handle->alloc != NULL) { - free(handle->alloc); - handle->alloc = NULL; + if (req->alloc != NULL) { + free(req->alloc); + req->alloc = NULL; } - if (handle->retcode == 0) { + if (req->retcode == 0) { /* convert addrinfoW to addrinfo */ /* first calculate required length */ - addrinfow_ptr = handle->res; + addrinfow_ptr = req->res; while (addrinfow_ptr != NULL) { addrinfo_len += addrinfo_struct_len + ALIGNED_SIZE(addrinfow_ptr->ai_addrlen); @@ -150,7 +147,7 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* handle, /* do conversions */ if (alloc_ptr != NULL) { cur_ptr = alloc_ptr; - addrinfow_ptr = handle->res; + addrinfow_ptr = req->res; while (addrinfow_ptr != NULL) { /* copy addrinfo struct data */ @@ -206,21 +203,21 @@ void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* handle, } } else { /* GetAddrInfo failed */ - uv__set_artificial_error(loop, uv_translate_eai_error(handle->retcode)); + uv__set_artificial_error(loop, uv_translate_eai_error(req->retcode)); status = -1; } /* return memory to system */ - if (handle->res != NULL) { - FreeAddrInfoW(handle->res); - handle->res = NULL; + if (req->res != NULL) { + FreeAddrInfoW(req->res); + req->res = NULL; } complete: - /* finally do callback with converted result */ - handle->getaddrinfo_cb(handle, status, (struct addrinfo*)alloc_ptr); + uv__req_unregister(loop, req); - uv_unref(loop); + /* finally do callback with converted result */ + req->getaddrinfo_cb(req, status, (struct addrinfo*)alloc_ptr); } @@ -237,7 +234,7 @@ void uv_freeaddrinfo(struct addrinfo* ai) { /* * Entry point for getaddrinfo * we convert the UTF-8 strings to UNICODE - * and save the UNICODE string pointers in the handle + * and save the UNICODE string pointers in the req * We also copy hints so that caller does not need to keep memory until the * callback. * return UV_OK if a callback will be made @@ -248,7 +245,7 @@ void uv_freeaddrinfo(struct addrinfo* ai) { * Each size calculation is adjusted to avoid unaligned pointers. */ int uv_getaddrinfo(uv_loop_t* loop, - uv_getaddrinfo_t* handle, + uv_getaddrinfo_t* req, uv_getaddrinfo_cb getaddrinfo_cb, const char* node, const char* service, @@ -258,18 +255,18 @@ int uv_getaddrinfo(uv_loop_t* loop, int hintssize = 0; char* alloc_ptr = NULL; - if (handle == NULL || getaddrinfo_cb == NULL || + if (req == NULL || getaddrinfo_cb == NULL || (node == NULL && service == NULL)) { uv__set_sys_error(loop, WSAEINVAL); goto error; } - uv_req_init(loop, (uv_req_t*)handle); + uv_req_init(loop, (uv_req_t*)req); - handle->getaddrinfo_cb = getaddrinfo_cb; - handle->res = NULL; - handle->type = UV_GETADDRINFO; - handle->loop = loop; + req->getaddrinfo_cb = getaddrinfo_cb; + req->res = NULL; + req->type = UV_GETADDRINFO; + req->loop = loop; /* calculate required memory size for all input values */ if (node != NULL) { @@ -300,12 +297,12 @@ int uv_getaddrinfo(uv_loop_t* loop, } /* save alloc_ptr now so we can free if error */ - handle->alloc = (void*)alloc_ptr; + req->alloc = (void*)alloc_ptr; /* convert node string to UTF16 into allocated memory and save pointer in */ - /* handle */ + /* the reques. */ if (node != NULL) { - handle->node = (wchar_t*)alloc_ptr; + req->node = (wchar_t*)alloc_ptr; if (uv_utf8_to_utf16(node, (wchar_t*) alloc_ptr, nodesize / sizeof(wchar_t)) == 0) { @@ -314,13 +311,13 @@ int uv_getaddrinfo(uv_loop_t* loop, } alloc_ptr += nodesize; } else { - handle->node = NULL; + req->node = NULL; } /* convert service string to UTF16 into allocated memory and save pointer */ - /* in handle */ + /* in the req. */ if (service != NULL) { - handle->service = (wchar_t*)alloc_ptr; + req->service = (wchar_t*)alloc_ptr; if (uv_utf8_to_utf16(service, (wchar_t*) alloc_ptr, servicesize / sizeof(wchar_t)) == 0) { @@ -329,44 +326,39 @@ int uv_getaddrinfo(uv_loop_t* loop, } alloc_ptr += servicesize; } else { - handle->service = NULL; + req->service = NULL; } - /* copy hints to allocated memory and save pointer in handle */ + /* copy hints to allocated memory and save pointer in req */ if (hints != NULL) { - handle->hints = (struct addrinfoW*)alloc_ptr; - handle->hints->ai_family = hints->ai_family; - handle->hints->ai_socktype = hints->ai_socktype; - handle->hints->ai_protocol = hints->ai_protocol; - handle->hints->ai_flags = hints->ai_flags; - handle->hints->ai_addrlen = 0; - handle->hints->ai_canonname = NULL; - handle->hints->ai_addr = NULL; - handle->hints->ai_next = NULL; + req->hints = (struct addrinfoW*)alloc_ptr; + req->hints->ai_family = hints->ai_family; + req->hints->ai_socktype = hints->ai_socktype; + req->hints->ai_protocol = hints->ai_protocol; + req->hints->ai_flags = hints->ai_flags; + req->hints->ai_addrlen = 0; + req->hints->ai_canonname = NULL; + req->hints->ai_addr = NULL; + req->hints->ai_next = NULL; } else { - handle->hints = NULL; + req->hints = NULL; } - /* init request for Post handling */ - uv_req_init(loop, &handle->getadddrinfo_req); - handle->getadddrinfo_req.data = handle; - handle->getadddrinfo_req.type = UV_GETADDRINFO_REQ; - /* Ask thread to run. Treat this as a long operation */ if (QueueUserWorkItem(&getaddrinfo_thread_proc, - handle, + req, WT_EXECUTELONGFUNCTION) == 0) { uv__set_sys_error(loop, GetLastError()); goto error; } - uv_ref(loop); + uv__req_register(loop, req); return 0; error: - if (handle != NULL && handle->alloc != NULL) { - free(handle->alloc); + if (req != NULL && req->alloc != NULL) { + free(req->alloc); } return -1; } diff --git a/deps/uv/src/win/handle.c b/deps/uv/src/win/handle.c index 797b0716c6..b501143857 100644 --- a/deps/uv/src/win/handle.c +++ b/deps/uv/src/win/handle.c @@ -57,27 +57,23 @@ uv_handle_type uv_guess_handle(uv_file file) { int uv_is_active(const uv_handle_t* handle) { - switch (handle->type) { - case UV_TIMER: - case UV_IDLE: - case UV_PREPARE: - case UV_CHECK: - return (handle->flags & UV_HANDLE_ACTIVE) ? 1 : 0; + return (handle->flags & UV__ACTIVE) && !(handle->flags & UV_HANDLE_CLOSING); +} - default: - return 1; - } + +void uv_handle_init(uv_loop_t* loop, uv_handle_t* handle) { + handle->loop = loop; + handle->flags = UV__REF; + + loop->counters.handle_init++; } void uv_close(uv_handle_t* handle, uv_close_cb cb) { - uv_pipe_t* pipe; - uv_udp_t* udp; - uv_process_t* process; - uv_loop_t* loop = handle->loop; if (handle->flags & UV_HANDLE_CLOSING) { + assert(0); return; } @@ -87,16 +83,11 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) { /* Handle-specific close actions */ switch (handle->type) { case UV_TCP: - uv_tcp_close((uv_tcp_t*)handle); + uv_tcp_close(loop, (uv_tcp_t*)handle); return; case UV_NAMED_PIPE: - pipe = (uv_pipe_t*)handle; - pipe->flags &= ~(UV_HANDLE_READING | UV_HANDLE_LISTENING); - close_pipe(pipe, NULL, NULL); - if (pipe->reqs_pending == 0) { - uv_want_endgame(loop, handle); - } + uv_pipe_close(loop, (uv_pipe_t*) handle); return; case UV_TTY: @@ -104,47 +95,47 @@ void uv_close(uv_handle_t* handle, uv_close_cb cb) { return; case UV_UDP: - udp = (uv_udp_t*) handle; - uv_udp_recv_stop(udp); - closesocket(udp->socket); - if (udp->reqs_pending == 0) { - uv_want_endgame(loop, handle); - } + uv_udp_close(loop, (uv_udp_t*) handle); + return; + + case UV_POLL: + uv_poll_close(loop, (uv_poll_t*) handle); return; case UV_TIMER: uv_timer_stop((uv_timer_t*)handle); + uv__handle_start(handle); uv_want_endgame(loop, handle); return; case UV_PREPARE: uv_prepare_stop((uv_prepare_t*)handle); + uv__handle_start(handle); uv_want_endgame(loop, handle); return; case UV_CHECK: uv_check_stop((uv_check_t*)handle); + uv__handle_start(handle); uv_want_endgame(loop, handle); return; case UV_IDLE: uv_idle_stop((uv_idle_t*)handle); + uv__handle_start(handle); uv_want_endgame(loop, handle); return; case UV_ASYNC: - if (!((uv_async_t*)handle)->async_sent) { - uv_want_endgame(loop, handle); - } + uv_async_close(loop, (uv_async_t*) handle); return; case UV_PROCESS: - process = (uv_process_t*)handle; - uv_process_close(loop, process); + uv_process_close(loop, (uv_process_t*) handle); return; case UV_FS_EVENT: - uv_fs_event_close(loop, (uv_fs_event_t*)handle); + uv_fs_event_close(loop, (uv_fs_event_t*) handle); return; default: @@ -172,7 +163,7 @@ void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) { void uv_process_endgames(uv_loop_t* loop) { uv_handle_t* handle; - while (loop->endgame_handles && loop->refs > 0) { + while (loop->endgame_handles) { handle = loop->endgame_handles; loop->endgame_handles = handle->endgame_next; @@ -195,6 +186,10 @@ void uv_process_endgames(uv_loop_t* loop) { uv_udp_endgame(loop, (uv_udp_t*) handle); break; + case UV_POLL: + uv_poll_endgame(loop, (uv_poll_t*) handle); + break; + case UV_TIMER: uv_timer_endgame(loop, (uv_timer_t*) handle); break; diff --git a/deps/uv/src/win/internal.h b/deps/uv/src/win/internal.h index 7cc469dcdf..362e23f2c2 100644 --- a/deps/uv/src/win/internal.h +++ b/deps/uv/src/win/internal.h @@ -31,49 +31,56 @@ /* - * Timers - */ -void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle); - -DWORD uv_get_poll_timeout(uv_loop_t* loop); -void uv_process_timers(uv_loop_t* loop); - - -/* * Handles */ -/* Private uv_handle flags */ +/* Used by all handles. */ #define UV_HANDLE_CLOSING 0x00000001 #define UV_HANDLE_CLOSED 0x00000002 -#define UV_HANDLE_BOUND 0x00000004 -#define UV_HANDLE_LISTENING 0x00000008 -#define UV_HANDLE_CONNECTION 0x00000010 -#define UV_HANDLE_CONNECTED 0x00000020 -#define UV_HANDLE_READING 0x00000040 -#define UV_HANDLE_ACTIVE 0x00000040 -#define UV_HANDLE_EOF 0x00000080 -#define UV_HANDLE_SHUTTING 0x00000100 -#define UV_HANDLE_SHUT 0x00000200 -#define UV_HANDLE_ENDGAME_QUEUED 0x00000400 -#define UV_HANDLE_BIND_ERROR 0x00001000 -#define UV_HANDLE_IPV6 0x00002000 -#define UV_HANDLE_PIPESERVER 0x00004000 -#define UV_HANDLE_READ_PENDING 0x00008000 -#define UV_HANDLE_UV_ALLOCED 0x00010000 -#define UV_HANDLE_SYNC_BYPASS_IOCP 0x00020000 -#define UV_HANDLE_ZERO_READ 0x00040000 -#define UV_HANDLE_TTY_RAW 0x00080000 +#define UV_HANDLE_ENDGAME_QUEUED 0x00000004 +#define UV_HANDLE_ACTIVE 0x00000010 + +/* Keep in sync with uv-common.h: */ +#define UV__REF 0x00000020 +#define UV__ACTIVE 0x00000040 +/* reserved: #define UV_HANDLE_INTERNAL 0x00000080 */ + +/* Used by streams and UDP handles. */ +#define UV_HANDLE_READING 0x00000100 +#define UV_HANDLE_BOUND 0x00000200 +#define UV_HANDLE_BIND_ERROR 0x00000400 +#define UV_HANDLE_LISTENING 0x00000800 +#define UV_HANDLE_CONNECTION 0x00001000 +#define UV_HANDLE_CONNECTED 0x00002000 +#define UV_HANDLE_EOF 0x00004000 +#define UV_HANDLE_SHUTTING 0x00008000 +#define UV_HANDLE_SHUT 0x00010000 +#define UV_HANDLE_READ_PENDING 0x00020000 +#define UV_HANDLE_SYNC_BYPASS_IOCP 0x00040000 +#define UV_HANDLE_ZERO_READ 0x00080000 #define UV_HANDLE_EMULATE_IOCP 0x00100000 -#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x00200000 -#define UV_HANDLE_TTY_SAVED_POSITION 0x00400000 -#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x00800000 -#define UV_HANDLE_SHARED_TCP_SOCKET 0x01000000 + +/* Only used by uv_tcp_t handles. */ +#define UV_HANDLE_IPV6 0x01000000 #define UV_HANDLE_TCP_NODELAY 0x02000000 #define UV_HANDLE_TCP_KEEPALIVE 0x04000000 #define UV_HANDLE_TCP_SINGLE_ACCEPT 0x08000000 #define UV_HANDLE_TCP_ACCEPT_STATE_CHANGING 0x10000000 #define UV_HANDLE_TCP_SOCKET_CLOSED 0x20000000 +#define UV_HANDLE_SHARED_TCP_SOCKET 0x40000000 + +/* Only used by uv_pipe_t handles. */ +#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x01000000 +#define UV_HANDLE_PIPESERVER 0x02000000 + +/* Only used by uv_tty_t handles. */ +#define UV_HANDLE_TTY_RAW 0x01000000 +#define UV_HANDLE_TTY_SAVED_POSITION 0x02000000 +#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x04000000 + +/* Only used by uv_poll_t handles. */ +#define UV_HANDLE_POLL_SLOW 0x02000000 + void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle); void uv_process_endgames(uv_loop_t* loop); @@ -95,6 +102,41 @@ void uv_process_endgames(uv_loop_t* loop); #define UV_SUCCEEDED_WITH_IOCP(result) \ ((result) || (GetLastError() == ERROR_IO_PENDING)) +#define DECREASE_ACTIVE_COUNT(loop, handle) \ + do { \ + if (--(handle)->activecnt == 0 && \ + !((handle)->flags & UV_HANDLE_CLOSING)) { \ + uv__handle_stop((handle)); \ + } \ + assert((handle)->activecnt >= 0); \ + } while (0) + +#define INCREASE_ACTIVE_COUNT(loop, handle) \ + do { \ + if ((handle)->activecnt++ == 0) { \ + uv__handle_start((handle)); \ + } \ + assert((handle)->activecnt > 0); \ + } while (0) + +#define REGISTER_HANDLE_REQ(loop, handle, req) \ + do { \ + INCREASE_ACTIVE_COUNT((loop), (handle)); \ + uv__req_register((loop), (req)); \ + } while (0) + +#define UNREGISTER_HANDLE_REQ(loop, handle, req) \ + do { \ + DECREASE_ACTIVE_COUNT((loop), (handle)); \ + uv__req_unregister((loop), (req)); \ + } while (0) + + +/* + * Handles + */ +void uv_handle_init(uv_loop_t* loop, uv_handle_t* handle); + /* * Requests @@ -142,6 +184,7 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, uv_connect_t* req); +void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp); void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle); int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info, @@ -150,8 +193,6 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info, int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, LPWSAPROTOCOL_INFOW protocol_info); -void uv_tcp_close(uv_tcp_t* tcp); - /* * UDP @@ -160,6 +201,7 @@ void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req); void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, uv_udp_send_t* req); +void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle); void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle); @@ -168,8 +210,6 @@ void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle); */ int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access, char* name, size_t nameSize); -void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err); -void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle); int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb); int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client); @@ -193,6 +233,10 @@ void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, uv_shutdown_t* req); +void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle); +void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle); +void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle); + /* * TTY @@ -221,6 +265,25 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle); /* + * Poll watchers + */ +void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, + uv_req_t* req); + +void uv_poll_close(uv_loop_t* loop, uv_poll_t* handle); +void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle); + + +/* + * Timers + */ +void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle); + +DWORD uv_get_poll_timeout(uv_loop_t* loop); +void uv_process_timers(uv_loop_t* loop); + + +/* * Loop watchers */ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle); @@ -233,6 +296,7 @@ void uv_idle_invoke(uv_loop_t* loop); /* * Async watcher */ +void uv_async_close(uv_loop_t* loop, uv_async_t* handle); void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle); void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle, @@ -261,8 +325,7 @@ void uv_process_ares_cleanup_req(uv_loop_t* loop, uv_ares_task_t* handle, /* * Getaddrinfo */ -void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* handle, - uv_req_t* req); +void uv_process_getaddrinfo_req(uv_loop_t* loop, uv_getaddrinfo_t* req); /* @@ -339,6 +402,9 @@ int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, int* addr_len, WSAOVERLAPPED *overlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); +int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info, + OVERLAPPED* overlapped); + /* Whether ipv6 is supported */ extern int uv_allow_ipv6; diff --git a/deps/uv/src/win/loop-watcher.c b/deps/uv/src/win/loop-watcher.c index c597cd99b1..46d184caf0 100644 --- a/deps/uv/src/win/loop-watcher.c +++ b/deps/uv/src/win/loop-watcher.c @@ -22,7 +22,6 @@ #include <assert.h> #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -30,25 +29,19 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { if (handle->flags & UV_HANDLE_CLOSING) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->close_cb) { handle->close_cb(handle); } - - uv_unref(loop); } } #define UV_LOOP_WATCHER_DEFINE(name, NAME) \ int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \ + uv_handle_init(loop, (uv_handle_t*) handle); \ handle->type = UV_##NAME; \ - handle->loop = loop; \ - handle->flags = 0; \ - \ - uv_ref(loop); \ - \ - loop->counters.handle_init++; \ loop->counters.name##_init++; \ \ return 0; \ @@ -77,6 +70,7 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { \ handle->name##_cb = cb; \ handle->flags |= UV_HANDLE_ACTIVE; \ + uv__handle_start(handle); \ \ return 0; \ } \ @@ -108,6 +102,7 @@ void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) { } \ \ handle->flags &= ~UV_HANDLE_ACTIVE; \ + uv__handle_stop(handle); \ \ return 0; \ } \ diff --git a/deps/uv/src/win/pipe.c b/deps/uv/src/win/pipe.c index 35da85e6ed..2b48e38f85 100644 --- a/deps/uv/src/win/pipe.c +++ b/deps/uv/src/win/pipe.c @@ -25,7 +25,6 @@ #include <stdio.h> #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -280,7 +279,6 @@ static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) { void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { - unsigned int uv_alloced; DWORD result; uv_shutdown_t* req; NTSTATUS nt_status; @@ -296,12 +294,14 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { handle->shutdown_req = NULL; if (handle->flags & UV_HANDLE_CLOSING) { + UNREGISTER_HANDLE_REQ(loop, handle, req); + /* Already closing. Cancel the shutdown. */ if (req->cb) { uv__set_sys_error(loop, WSAEINTR); req->cb(req, -1); } - uv_unref(loop); + DECREASE_PENDING_REQ_COUNT(handle); return; } @@ -315,12 +315,14 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { if (nt_status != STATUS_SUCCESS) { /* Failure */ + UNREGISTER_HANDLE_REQ(loop, handle, req); + handle->flags &= ~UV_HANDLE_SHUTTING; if (req->cb) { uv__set_sys_error(loop, pRtlNtStatusToDosError(nt_status)); req->cb(req, -1); } - uv_unref(loop); + DECREASE_PENDING_REQ_COUNT(handle); return; } @@ -340,12 +342,14 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { } else { /* Failure. */ + UNREGISTER_HANDLE_REQ(loop, handle, req); + handle->flags &= ~UV_HANDLE_SHUTTING; if (req->cb) { uv__set_sys_error(loop, GetLastError()); req->cb(req, -1); } - uv_unref(loop); + DECREASE_PENDING_REQ_COUNT(handle); return; } @@ -355,6 +359,7 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { handle->reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->flags & UV_HANDLE_CONNECTION) { if (handle->pending_ipc_info.socket_info) { @@ -380,19 +385,9 @@ void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { handle->accept_reqs = NULL; } - /* Remember the state of this flag because the close callback is */ - /* allowed to clobber or free the handle's memory */ - uv_alloced = handle->flags & UV_HANDLE_UV_ALLOCED; - if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } - - if (uv_alloced) { - free(handle); - } - - uv_unref(loop); } } @@ -573,7 +568,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, goto error; } - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); handle->reqs_pending++; return; @@ -596,7 +591,7 @@ void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, SET_REQ_SUCCESS(req); uv_insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); return; error: @@ -613,14 +608,14 @@ error: SET_REQ_ERROR(req, errorno); uv_insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); return; } /* Cleans up uv_pipe_t (server or connection) and all resources associated */ /* with it. */ -void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err) { +void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) { int i; HANDLE pipeHandle; @@ -652,6 +647,27 @@ void close_pipe(uv_pipe_t* handle, int* status, uv_err_t* err) { } +void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) { + if (handle->flags & UV_HANDLE_READING) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + } + + if (handle->flags & UV_HANDLE_LISTENING) { + handle->flags &= ~UV_HANDLE_LISTENING; + DECREASE_ACTIVE_COUNT(loop, handle); + } + + uv_pipe_cleanup(loop, handle); + + if (handle->reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } + + uv__handle_start(handle); +} + + static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle, uv_pipe_accept_t* req, BOOL firstInstance) { assert(handle->flags & UV_HANDLE_LISTENING); @@ -717,7 +733,7 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { return -1; } - return uv_tcp_import((uv_tcp_t*)client, server->pending_ipc_info.socket_info, + return uv_tcp_import((uv_tcp_t*)client, server->pending_ipc_info.socket_info, server->pending_ipc_info.tcp_connection); } else { pipe_client = (uv_pipe_t*)client; @@ -753,17 +769,19 @@ int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) { /* Starts listening for connections for the given pipe. */ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { uv_loop_t* loop = handle->loop; - int i; + if (handle->flags & UV_HANDLE_LISTENING) { + handle->connection_cb = cb; + } + if (!(handle->flags & UV_HANDLE_BOUND)) { uv__set_artificial_error(loop, UV_EINVAL); return -1; } - if (handle->flags & UV_HANDLE_LISTENING || - handle->flags & UV_HANDLE_READING) { - uv__set_artificial_error(loop, UV_EALREADY); + if (handle->flags & UV_HANDLE_READING) { + uv__set_artificial_error(loop, UV_EISCONN); return -1; } @@ -773,6 +791,7 @@ int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) { } handle->flags |= UV_HANDLE_LISTENING; + INCREASE_ACTIVE_COUNT(loop, handle); handle->connection_cb = cb; /* First pipe handle should have already been created in uv_pipe_bind */ @@ -955,17 +974,13 @@ static int uv_pipe_read_start_impl(uv_pipe_t* handle, uv_alloc_cb alloc_cb, return -1; } - if (handle->flags & UV_HANDLE_READING) { - uv__set_artificial_error(loop, UV_EALREADY); - return -1; - } - if (handle->flags & UV_HANDLE_EOF) { uv__set_artificial_error(loop, UV_EOF); return -1; } handle->flags |= UV_HANDLE_READING; + INCREASE_ACTIVE_COUNT(loop, handle); handle->read_cb = read_cb; handle->read2_cb = read2_cb; handle->alloc_cb = alloc_cb; @@ -1154,10 +1169,10 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req, /* Request queued by the kernel. */ ipc_header_req->queued_bytes = ipc_frame.header.flags & UV_IPC_TCP_SERVER ? sizeof(ipc_frame) : sizeof(ipc_frame.header); - handle->write_queue_size += req->queued_bytes; + handle->write_queue_size += ipc_header_req->queued_bytes; } - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, ipc_header_req); handle->reqs_pending++; handle->write_reqs_pending++; @@ -1212,7 +1227,7 @@ static int uv_pipe_write_impl(uv_loop_t* loop, uv_write_t* req, } } - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); handle->reqs_pending++; handle->write_reqs_pending++; @@ -1435,6 +1450,8 @@ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, assert(handle->write_queue_size >= req->queued_bytes); handle->write_queue_size -= req->queued_bytes; + UNREGISTER_HANDLE_REQ(loop, handle, req); + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { if (req->wait_handle != INVALID_HANDLE_VALUE) { UnregisterWait(req->wait_handle); @@ -1476,7 +1493,6 @@ void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle, uv_want_endgame(loop, (uv_handle_t*)handle); } - uv_unref(loop); DECREASE_PENDING_REQ_COUNT(handle); } @@ -1513,6 +1529,8 @@ void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, uv_connect_t* req) { assert(handle->type == UV_NAMED_PIPE); + UNREGISTER_HANDLE_REQ(loop, handle, req); + if (req->cb) { if (REQ_SUCCESS(req)) { uv_pipe_connection_init(handle); @@ -1523,7 +1541,6 @@ void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle, } } - uv_unref(loop); DECREASE_PENDING_REQ_COUNT(handle); } @@ -1532,6 +1549,8 @@ void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, uv_shutdown_t* req) { assert(handle->type == UV_NAMED_PIPE); + UNREGISTER_HANDLE_REQ(loop, handle, req); + /* Initialize and optionally start the eof timer. */ /* This makes no sense if we've already seen EOF. */ if (!(handle->flags & UV_HANDLE_EOF)) { @@ -1548,7 +1567,6 @@ void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle, req->cb(req, 0); } - uv_unref(loop); DECREASE_PENDING_REQ_COUNT(handle); } @@ -1564,7 +1582,7 @@ static void eof_timer_init(uv_pipe_t* pipe) { r = uv_timer_init(pipe->loop, pipe->eof_timer); assert(r == 0); /* timers can't fail */ pipe->eof_timer->data = pipe; - uv_unref(pipe->loop); + uv_unref((uv_handle_t*) pipe->eof_timer); } @@ -1598,7 +1616,7 @@ static void eof_timer_cb(uv_timer_t* timer, int status) { /* or in uv_process_pipe_shutdown_req if a read is pending, */ /* and we always immediately stop the timer in */ /* uv_process_pipe_read_req. */ - assert(pipe->flags & UV_HANDLE_READ_PENDING) ; + assert(pipe->flags & UV_HANDLE_READ_PENDING); /* If there are many packets coming off the iocp then the timer callback */ /* may be called before the read request is coming off the queue. */ @@ -1627,7 +1645,6 @@ static void eof_timer_destroy(uv_pipe_t* pipe) { assert(pipe->flags && UV_HANDLE_CONNECTION); if (pipe->eof_timer) { - uv_ref(pipe->loop); uv_close((uv_handle_t*) pipe->eof_timer, eof_timer_close_cb); pipe->eof_timer = NULL; } diff --git a/deps/uv/src/win/poll.c b/deps/uv/src/win/poll.c new file mode 100644 index 0000000000..c6d68ffd4b --- /dev/null +++ b/deps/uv/src/win/poll.c @@ -0,0 +1,620 @@ +/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + + +#include "uv.h" +#include "internal.h" + +#include <assert.h> +#include <io.h> + + +static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = { + {0xe70f1aa0, 0xab8b, 0x11cf, + {0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}, + {0xf9eab0c0, 0x26d4, 0x11d0, + {0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}}, + {0x9fc48064, 0x7298, 0x43e4, + {0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}} +}; + +typedef struct uv_single_fd_set_s { + unsigned int fd_count; + SOCKET fd_array[1]; +} uv_single_fd_set_t; + + +static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { + uv_req_t* req; + AFD_POLL_INFO* afd_poll_info; + DWORD result; + + /* Find a yet unsubmitted req to submit. */ + if (handle->submitted_events_1 == 0) { + req = &handle->poll_req_1; + afd_poll_info = &handle->afd_poll_info_1; + handle->submitted_events_1 = handle->events; + handle->mask_events_1 = 0; + handle->mask_events_2 = handle->events; + } else if (handle->submitted_events_2 == 0) { + req = &handle->poll_req_2; + afd_poll_info = &handle->afd_poll_info_2; + handle->submitted_events_2 = handle->events; + handle->mask_events_1 = handle->events; + handle->mask_events_2 = 0; + } else { + assert(0); + } + + /* Setting Exclusive to TRUE makes the other poll request return if there */ + /* is any. */ + afd_poll_info->Exclusive = TRUE; + afd_poll_info->NumberOfHandles = 1; + afd_poll_info->Timeout.QuadPart = INT64_MAX; + afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket; + afd_poll_info->Handles[0].Status = 0; + afd_poll_info->Handles[0].Events = 0; + + if (handle->events & UV_READABLE) { + afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE | + AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT; + } + if (handle->events & UV_WRITABLE) { + afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL; + } + + memset(&req->overlapped, 0, sizeof req->overlapped); + + result = uv_msafd_poll((SOCKET) handle->peer_socket, + afd_poll_info, + &req->overlapped); + if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) { + /* Queue this req, reporting an error. */ + SET_REQ_ERROR(req, WSAGetLastError()); + uv_insert_pending_req(loop, req); + } +} + + +static int uv__fast_poll_cancel_poll_reqs(uv_loop_t* loop, uv_poll_t* handle) { + AFD_POLL_INFO afd_poll_info; + DWORD result; + HANDLE event; + OVERLAPPED overlapped; + + event = CreateEvent(NULL, TRUE, FALSE, NULL); + if (event == NULL) { + uv__set_sys_error(loop, GetLastError()); + return -1; + } + + afd_poll_info.Exclusive = TRUE; + afd_poll_info.NumberOfHandles = 1; + afd_poll_info.Timeout.QuadPart = INT64_MAX; + afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket; + afd_poll_info.Handles[0].Status = 0; + afd_poll_info.Handles[0].Events = AFD_POLL_ALL; + + memset(&overlapped, 0, sizeof overlapped); + overlapped.hEvent = (HANDLE) ((uintptr_t) event & 1); + + result = uv_msafd_poll(handle->socket, + &afd_poll_info, + &overlapped); + + if (result == SOCKET_ERROR) { + DWORD error = WSAGetLastError(); + if (error != WSA_IO_PENDING) { + uv__set_sys_error(loop, WSAGetLastError()); + CloseHandle(event); + return -1; + } + } + + CloseHandle(event); + return 0; +} + + +static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, + uv_req_t* req) { + unsigned char mask_events; + AFD_POLL_INFO* afd_poll_info; + + if (req == &handle->poll_req_1) { + afd_poll_info = &handle->afd_poll_info_1; + handle->submitted_events_1 = 0; + mask_events = handle->mask_events_1; + } else if (req == &handle->poll_req_2) { + afd_poll_info = &handle->afd_poll_info_2; + handle->submitted_events_2 = 0; + mask_events = handle->mask_events_2; + } else { + assert(0); + } + + /* Report an error unless the select was just interrupted. */ + if (!REQ_SUCCESS(req)) { + DWORD error = GET_REQ_SOCK_ERROR(req); + if (error != WSAEINTR && handle->events != 0) { + handle->events = 0; /* Stop the watcher */ + uv__set_sys_error(loop, error); + handle->poll_cb(handle, -1, 0); + } + + } else if (afd_poll_info->NumberOfHandles >= 1) { + unsigned char events = 0; + + if ((afd_poll_info->Handles[0].Events & (AFD_POLL_RECEIVE | + AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT)) != 0) { + events |= UV_READABLE; + } + if ((afd_poll_info->Handles[0].Events & (AFD_POLL_SEND | + AFD_POLL_CONNECT_FAIL)) != 0) { + events |= UV_WRITABLE; + } + + events &= handle->events & ~mask_events; + + if (afd_poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) { + /* Stop polling. */ + handle->events = 0; + } + + if (events != 0) { + handle->poll_cb(handle, 0, events); + } + } + + if ((handle->events & ~(handle->submitted_events_1 | + handle->submitted_events_2)) != 0) { + uv__fast_poll_submit_poll_req(loop, handle); + } else if ((handle->flags & UV_HANDLE_CLOSING) && + handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { + assert(handle->type == UV_POLL); + assert(!(handle->flags & UV_HANDLE_CLOSING)); + assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0); + + handle->events = events; + + if (handle->events != 0) { + uv__handle_start(handle); + } else { + uv__handle_stop(handle); + } + + if ((handle->events & ~(handle->submitted_events_1 | + handle->submitted_events_2)) != 0) { + uv__fast_poll_submit_poll_req(handle->loop, handle); + } + + return 0; +} + + +static void uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) { + handle->events = 0; + uv__handle_start(handle); + + if (handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } else { + /* Try to cancel outstanding poll requests. */ + if (pCancelIoEx) { + /* Use CancelIoEx to cancel poll requests if available. */ + if (handle->submitted_events_1) + pCancelIoEx((HANDLE) handle->socket, &handle->poll_req_1.overlapped); + if (handle->submitted_events_2) + pCancelIoEx((HANDLE) handle->socket, &handle->poll_req_2.overlapped); + } else if (handle->submitted_events_1 | handle->submitted_events_2) { + /* Execute another unique poll to force the others to return. */ + uv__fast_poll_cancel_poll_reqs(loop, handle); + } + } +} + + +static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp, + WSAPROTOCOL_INFOW* protocol_info) { + SOCKET sock = 0; + + sock = WSASocketW(protocol_info->iAddressFamily, + protocol_info->iSocketType, + protocol_info->iProtocol, + protocol_info, + 0, + WSA_FLAG_OVERLAPPED); + if (sock == INVALID_SOCKET) { + return INVALID_SOCKET; + } + + if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) { + goto error; + }; + + if (CreateIoCompletionPort((HANDLE) sock, + iocp, + (ULONG_PTR) sock, + 0) == NULL) { + goto error; + } + + return sock; + + error: + closesocket(sock); + return INVALID_SOCKET; +} + + +static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop, + WSAPROTOCOL_INFOW* protocol_info) { + int index, i; + SOCKET peer_socket; + + index = -1; + for (i = 0; i < ARRAY_SIZE(uv_msafd_provider_ids); i++) { + if (memcmp((void*) &protocol_info->ProviderId, + (void*) &uv_msafd_provider_ids[i], + sizeof protocol_info->ProviderId) == 0) { + index = i; + } + } + + /* Check if the protocol uses an msafd socket. */ + if (index < 0) { + return INVALID_SOCKET; + } + + /* If we didn't (try) to create a peer socket yet, try to make one. Don't */ + /* try again if the peer socket creation failed earlier for the same */ + /* protocol. */ + peer_socket = loop->poll_peer_sockets[index]; + if (peer_socket == 0) { + peer_socket = uv__fast_poll_create_peer_socket(loop->iocp, protocol_info); + loop->poll_peer_sockets[index] = peer_socket; + } + + return peer_socket; +} + + +static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) { + uv_req_t* req = (uv_req_t*) arg; + uv_poll_t* handle = (uv_poll_t*) req->data; + unsigned char events, reported_events; + int r; + uv_single_fd_set_t rfds, wfds, efds; + struct timeval timeout; + + assert(handle->type == UV_POLL); + assert(req->type == UV_POLL_REQ); + + if (req == &handle->poll_req_1) { + events = handle->submitted_events_1; + } else if (req == &handle->poll_req_2) { + events = handle->submitted_events_2; + } else { + assert(0); + } + + if (handle->events & UV_READABLE) { + rfds.fd_count = 1; + rfds.fd_array[0] = handle->socket; + } else { + rfds.fd_count = 0; + } + + if (handle->events & UV_WRITABLE) { + wfds.fd_count = 1; + wfds.fd_array[0] = handle->socket; + efds.fd_count = 1; + efds.fd_array[0] = handle->socket; + } else { + wfds.fd_count = 0; + efds.fd_count = 0; + } + + /* Make the select() time out after 3 minutes. If select() hangs because */ + /* the user closed the socket, we will at least not hang indefinitely. */ + timeout.tv_sec = 3 * 60; + timeout.tv_usec = 0; + + r = select(1, (fd_set*) &rfds, (fd_set*) &wfds, (fd_set*) &efds, &timeout); + if (r == SOCKET_ERROR) { + /* Queue this req, reporting an error. */ + SET_REQ_ERROR(&handle->poll_req_1, WSAGetLastError()); + POST_COMPLETION_FOR_REQ(handle->loop, req); + return 0; + } + + reported_events = 0; + + if (r > 0) { + if (rfds.fd_count > 0) { + assert(rfds.fd_count == 1); + assert(rfds.fd_array[0] == handle->socket); + reported_events |= UV_READABLE; + } + + if (wfds.fd_count > 0) { + assert(wfds.fd_count == 1); + assert(wfds.fd_array[0] == handle->socket); + reported_events |= UV_WRITABLE; + } else if (efds.fd_count > 0) { + assert(efds.fd_count == 1); + assert(efds.fd_array[0] == handle->socket); + reported_events |= UV_WRITABLE; + } + } + + SET_REQ_SUCCESS(req); + req->overlapped.InternalHigh = (DWORD) reported_events; + POST_COMPLETION_FOR_REQ(handle->loop, req); + + return 0; +} + + +static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) { + uv_req_t* req; + + /* Find a yet unsubmitted req to submit. */ + if (handle->submitted_events_1 == 0) { + req = &handle->poll_req_1; + handle->submitted_events_1 = handle->events; + handle->mask_events_1 = 0; + handle->mask_events_2 = handle->events; + } else if (handle->submitted_events_2 == 0) { + req = &handle->poll_req_2; + handle->submitted_events_2 = handle->events; + handle->mask_events_1 = handle->events; + handle->mask_events_2 = 0; + } else { + assert(0); + } + + if (!QueueUserWorkItem(uv__slow_poll_thread_proc, + (void*) req, + WT_EXECUTELONGFUNCTION)) { + /* Make this req pending, reporting an error. */ + SET_REQ_ERROR(req, GetLastError()); + uv_insert_pending_req(loop, req); + } +} + + + +static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, + uv_req_t* req) { + unsigned char mask_events; + if (req == &handle->poll_req_1) { + handle->submitted_events_1 = 0; + mask_events = handle->mask_events_1; + } else if (req == &handle->poll_req_2) { + handle->submitted_events_2 = 0; + mask_events = handle->mask_events_2; + } else { + assert(0); + } + + if (!REQ_SUCCESS(req)) { + /* Error. */ + if (handle->events != 0) { + handle->events = 0; /* Stop the watcher */ + uv__set_sys_error(loop, GET_REQ_ERROR(req)); + handle->poll_cb(handle, -1, 0); + } + } else { + /* Got some events. */ + int events = req->overlapped.InternalHigh & handle->events & ~mask_events; + if (events != 0) { + handle->poll_cb(handle, 0, events); + } + } + + if ((handle->events & ~(handle->submitted_events_1 | + handle->submitted_events_2)) != 0) { + uv__slow_poll_submit_poll_req(loop, handle); + } else if ((handle->flags & UV_HANDLE_CLOSING) && + handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) { + assert(handle->type == UV_POLL); + assert(!(handle->flags & UV_HANDLE_CLOSING)); + assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0); + + handle->events = events; + + if (handle->events != 0) { + uv__handle_start(handle); + } else { + uv__handle_stop(handle); + } + + if ((handle->events & + ~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) { + uv__slow_poll_submit_poll_req(handle->loop, handle); + } + + return 0; +} + + +static void uv__slow_poll_close(uv_loop_t* loop, uv_poll_t* handle) { + handle->events = 0; + uv__handle_start(handle); + + if (handle->submitted_events_1 == 0 && + handle->submitted_events_2 == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + +int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) { + return uv_poll_init_socket(loop, handle, (SOCKET) _get_osfhandle(fd)); +} + + +int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle, + uv_os_sock_t socket) { + WSAPROTOCOL_INFOW protocol_info; + int len; + SOCKET peer_socket, base_socket; + DWORD bytes; + + /* Try to obtain a base handle for the socket. This increases this chances */ + /* that we find an AFD handle and are able to use the fast poll mechanism. */ + /* This will always fail on windows XP/2k3, since they don't support the */ + /* SIO_BASE_HANDLE ioctl. */ +#ifndef NDEBUG + base_socket = INVALID_SOCKET; +#endif + + if (WSAIoctl(socket, + SIO_BASE_HANDLE, + NULL, + 0, + &base_socket, + sizeof base_socket, + &bytes, + NULL, + NULL) == 0) { + assert(base_socket != 0 && base_socket != INVALID_SOCKET); + socket = base_socket; + } + + uv_handle_init(loop, (uv_handle_t*) handle); + handle->type = UV_POLL; + handle->socket = socket; + handle->events = 0; + + /* Obtain protocol information about the socket. */ + len = sizeof protocol_info; + if (getsockopt(socket, + SOL_SOCKET, + SO_PROTOCOL_INFOW, + (char*) &protocol_info, + &len) != 0) { + uv__set_sys_error(loop, WSAGetLastError()); + return -1; + } + + /* Get the peer socket that is needed to enable fast poll. If the returned */ + /* value is NULL, the protocol is not implemented by MSAFD and we'll have */ + /* to use slow mode. */ + peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info); + + if (peer_socket != INVALID_SOCKET) { + /* Initialize fast poll specific fields. */ + handle->peer_socket = peer_socket; + } else { + /* Initialize slow poll specific fields. */ + handle->flags |= UV_HANDLE_POLL_SLOW; + } + + /* Intialize 2 poll reqs. */ + handle->submitted_events_1 = 0; + uv_req_init(loop, (uv_req_t*) &(handle->poll_req_1)); + handle->poll_req_1.type = UV_POLL_REQ; + handle->poll_req_1.data = handle; + + handle->submitted_events_2 = 0; + uv_req_init(loop, (uv_req_t*) &(handle->poll_req_2)); + handle->poll_req_2.type = UV_POLL_REQ; + handle->poll_req_2.data = handle; + + loop->counters.poll_init++; + + return 0; +} + + +int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) { + if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { + if (uv__fast_poll_set(handle->loop, handle, events) < 0) + return -1; + } else { + if (uv__slow_poll_set(handle->loop, handle, events) < 0) + return -1; + } + + handle->poll_cb = cb; + + return 0; +} + + +int uv_poll_stop(uv_poll_t* handle) { + if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { + return uv__fast_poll_set(handle->loop, handle, 0); + } else { + return uv__slow_poll_set(handle->loop, handle, 0); + } +} + + +void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) { + if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { + uv__fast_poll_process_poll_req(loop, handle, req); + } else { + uv__slow_poll_process_poll_req(loop, handle, req); + } +} + + +void uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) { + if (!(handle->flags & UV_HANDLE_POLL_SLOW)) { + uv__fast_poll_close(loop, handle); + } else { + uv__slow_poll_close(loop, handle); + } +} + + +void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) { + assert(handle->flags & UV_HANDLE_CLOSING); + assert(!(handle->flags & UV_HANDLE_CLOSED)); + + assert(handle->submitted_events_1 == 0); + assert(handle->submitted_events_2 == 0); + + handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); + + if (handle->close_cb) { + handle->close_cb((uv_handle_t*)handle); + } +} diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c index aacb06176a..481b945c97 100644 --- a/deps/uv/src/win/process.c +++ b/deps/uv/src/win/process.c @@ -20,7 +20,6 @@ */ #include "uv.h" -#include "../uv-common.h" #include "internal.h" #include <stdio.h> @@ -55,9 +54,8 @@ typedef struct env_var { static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) { + uv_handle_init(loop, (uv_handle_t*) handle); handle->type = UV_PROCESS; - handle->loop = loop; - handle->flags = 0; handle->exit_cb = NULL; handle->pid = 0; handle->exit_signal = 0; @@ -77,8 +75,6 @@ static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) { loop->counters.handle_init++; loop->counters.process_init++; - - uv_ref(loop); } @@ -689,30 +685,28 @@ static void close_child_stdio(uv_process_t* process) { void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) { DWORD exit_code; + /* FIXME: race condition. */ + if (handle->flags & UV_HANDLE_CLOSING) { + return; + } + /* Unregister from process notification. */ if (handle->wait_handle != INVALID_HANDLE_VALUE) { UnregisterWait(handle->wait_handle); handle->wait_handle = INVALID_HANDLE_VALUE; } - if (handle->process_handle != INVALID_HANDLE_VALUE) { - /* Get the exit code. */ - if (!GetExitCodeProcess(handle->process_handle, &exit_code)) { - exit_code = 127; - } - - /* Clean-up the process handle. */ - CloseHandle(handle->process_handle); - handle->process_handle = INVALID_HANDLE_VALUE; - } else { - /* We probably left the child stdio handles open to report the error */ - /* asynchronously, so close them now. */ - close_child_stdio(handle); - - /* The process never even started in the first place. */ + if (handle->process_handle == INVALID_HANDLE_VALUE || + !GetExitCodeProcess(handle->process_handle, &exit_code)) { + /* The process never even started in the first place, or we were unable */ + /* to obtain the exit code. */ exit_code = 127; } + /* Set the handle to inactive: no callbacks will be made after the exit */ + /* callback.*/ + uv__handle_stop(handle); + /* Fire the exit callback. */ if (handle->exit_cb) { handle->exit_cb(handle, exit_code, handle->exit_signal); @@ -726,21 +720,9 @@ void uv_process_proc_close(uv_loop_t* loop, uv_process_t* handle) { } -void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) { - if (handle->flags & UV_HANDLE_CLOSING) { - assert(!(handle->flags & UV_HANDLE_CLOSED)); - handle->flags |= UV_HANDLE_CLOSED; - - if (handle->close_cb) { - handle->close_cb((uv_handle_t*)handle); - } - - uv_unref(loop); - } -} - - void uv_process_close(uv_loop_t* loop, uv_process_t* handle) { + uv__handle_start(handle); + if (handle->wait_handle != INVALID_HANDLE_VALUE) { handle->close_handle = CreateEvent(NULL, FALSE, FALSE, NULL); UnregisterWaitEx(handle->wait_handle, handle->close_handle); @@ -755,6 +737,25 @@ void uv_process_close(uv_loop_t* loop, uv_process_t* handle) { } +void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) { + if (handle->flags & UV_HANDLE_CLOSING) { + assert(!(handle->flags & UV_HANDLE_CLOSED)); + handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); + + /* Clean-up the process handle. */ + CloseHandle(handle->process_handle); + + /* Clean up the child stdio ends that may have been left open. */ + close_child_stdio(handle); + + if (handle->close_cb) { + handle->close_cb((uv_handle_t*)handle); + } + } +} + + static int uv_create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe, HANDLE* child_pipe, DWORD server_access, DWORD child_access, int overlapped) { @@ -816,7 +817,7 @@ static int uv_create_stdio_pipe_pair(uv_loop_t* loop, uv_pipe_t* server_pipe, done: if (err) { if (server_pipe->handle != INVALID_HANDLE_VALUE) { - close_pipe(server_pipe, NULL, NULL); + uv_pipe_cleanup(loop, server_pipe); } if (*child_pipe != INVALID_HANDLE_VALUE) { @@ -1058,7 +1059,12 @@ done: } } - if (err) { + if (err == 0) { + /* Spawn was succesful. The handle will be active until the exit */ + /* is made or the handle is closed, whichever happens first. */ + uv__handle_start(process); + } else { + /* Spawn was not successful. Clean up. */ if (process->wait_handle != INVALID_HANDLE_VALUE) { UnregisterWait(process->wait_handle); process->wait_handle = INVALID_HANDLE_VALUE; diff --git a/deps/uv/src/win/req.c b/deps/uv/src/win/req.c index 65aa6c1581..1aae70911c 100644 --- a/deps/uv/src/win/req.c +++ b/deps/uv/src/win/req.c @@ -22,7 +22,6 @@ #include <assert.h> #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -135,6 +134,10 @@ void uv_process_reqs(uv_loop_t* loop) { uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req); break; + case UV_POLL_REQ: + uv_process_poll_req(loop, (uv_poll_t*) req->data, req); + break; + case UV_ARES_EVENT_REQ: uv_process_ares_event_req(loop, (uv_ares_action_t*) req->data, req); break; @@ -143,8 +146,8 @@ void uv_process_reqs(uv_loop_t* loop) { uv_process_ares_cleanup_req(loop, (uv_ares_task_t*) req->data, req); break; - case UV_GETADDRINFO_REQ: - uv_process_getaddrinfo_req(loop, (uv_getaddrinfo_t*) req->data, req); + case UV_GETADDRINFO: + uv_process_getaddrinfo_req(loop, (uv_getaddrinfo_t*) req); break; case UV_PROCESS_EXIT: diff --git a/deps/uv/src/win/stream.c b/deps/uv/src/win/stream.c index 4275bce195..dad8669b1d 100644 --- a/deps/uv/src/win/stream.c +++ b/deps/uv/src/win/stream.c @@ -22,19 +22,15 @@ #include <assert.h> #include "uv.h" -#include "../uv-common.h" #include "internal.h" void uv_stream_init(uv_loop_t* loop, uv_stream_t* handle) { + uv_handle_init(loop, (uv_handle_t*) handle); handle->write_queue_size = 0; - handle->loop = loop; - handle->flags = 0; + handle->activecnt = 0; - loop->counters.handle_init++; loop->counters.stream_init++; - - uv_ref(loop); } @@ -109,8 +105,11 @@ int uv_read2_start(uv_stream_t* handle, uv_alloc_cb alloc_cb, int uv_read_stop(uv_stream_t* handle) { if (handle->type == UV_TTY) { return uv_tty_read_stop((uv_tty_t*) handle); - } else { + } else if (handle->flags & UV_HANDLE_READING) { handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(handle->loop, handle); + return 0; + } else { return 0; } } @@ -171,7 +170,7 @@ int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) { handle->flags |= UV_HANDLE_SHUTTING; handle->shutdown_req = req; handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); uv_want_endgame(loop, (uv_handle_t*)handle); diff --git a/deps/uv/src/win/tcp.c b/deps/uv/src/win/tcp.c index 51ef604eb1..fd956a09c6 100644 --- a/deps/uv/src/win/tcp.c +++ b/deps/uv/src/win/tcp.c @@ -22,7 +22,6 @@ #include <assert.h> #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -143,12 +142,12 @@ static int uv_tcp_set_socket(uv_loop_t* loop, uv_tcp_t* handle, int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) { - uv_stream_init(loop, (uv_stream_t*)handle); + uv_stream_init(loop, (uv_stream_t*) handle); + handle->type = UV_TCP; handle->accept_reqs = NULL; handle->pending_accepts = NULL; handle->socket = INVALID_SOCKET; - handle->type = UV_TCP; handle->reqs_pending = 0; handle->func_acceptex = NULL; handle->func_connectex = NULL; @@ -170,6 +169,8 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { handle->shutdown_req != NULL && handle->write_reqs_pending == 0) { + UNREGISTER_HANDLE_REQ(loop, handle, handle->shutdown_req); + if (handle->flags & UV_HANDLE_CLOSING) { status = -1; sys_error = WSAEINTR; @@ -180,6 +181,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { status = -1; sys_error = WSAGetLastError(); } + if (handle->shutdown_req->cb) { if (status == -1) { uv__set_sys_error(loop, sys_error); @@ -188,8 +190,6 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { } handle->shutdown_req = NULL; - - uv_unref(loop); DECREASE_PENDING_REQ_COUNT(handle); return; } @@ -198,6 +198,7 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { handle->reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) { closesocket(handle->socket); @@ -240,8 +241,6 @@ void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) { } loop->active_tcp_streams--; - - uv_unref(loop); } } @@ -310,10 +309,10 @@ int uv__tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6 addr) { static void CALLBACK post_completion(void* context, BOOLEAN timed_out) { - uv_tcp_accept_t* req; + uv_req_t* req; uv_tcp_t* handle; - req = (uv_tcp_accept_t*) context; + req = (uv_req_t*) context; assert(req != NULL); handle = (uv_tcp_t*)req->data; assert(handle != NULL); @@ -328,6 +327,25 @@ static void CALLBACK post_completion(void* context, BOOLEAN timed_out) { } +static void CALLBACK post_write_completion(void* context, BOOLEAN timed_out) { + uv_write_t* req; + uv_tcp_t* handle; + + req = (uv_write_t*) context; + assert(req != NULL); + handle = (uv_tcp_t*)req->handle; + assert(handle != NULL); + assert(!timed_out); + + if (!PostQueuedCompletionStatus(handle->loop->iocp, + req->overlapped.InternalHigh, + 0, + &req->overlapped)) { + uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); + } +} + + static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { uv_loop_t* loop = handle->loop; BOOL success; @@ -381,7 +399,7 @@ static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { if (handle->flags & UV_HANDLE_EMULATE_IOCP && req->wait_handle == INVALID_HANDLE_VALUE && !RegisterWaitForSingleObject(&req->wait_handle, - req->overlapped.hEvent, post_completion, (void*) req, + req->event_handle, post_completion, (void*) req, INFINITE, WT_EXECUTEINWAITTHREAD)) { SET_REQ_ERROR(req, GetLastError()); uv_insert_pending_req(loop, (uv_req_t*)req); @@ -460,7 +478,7 @@ static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) { if (handle->flags & UV_HANDLE_EMULATE_IOCP && req->wait_handle == INVALID_HANDLE_VALUE && !RegisterWaitForSingleObject(&req->wait_handle, - req->overlapped.hEvent, post_completion, (void*) req, + req->event_handle, post_completion, (void*) req, INFINITE, WT_EXECUTEINWAITTHREAD)) { SET_REQ_ERROR(req, GetLastError()); uv_insert_pending_req(loop, (uv_req_t*)req); @@ -481,6 +499,15 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { assert(backlog > 0); + if (handle->flags & UV_HANDLE_LISTENING) { + handle->connection_cb = cb; + } + + if (handle->flags & UV_HANDLE_READING) { + uv__set_artificial_error(loop, UV_EISCONN); + return -1; + } + if (handle->flags & UV_HANDLE_BIND_ERROR) { uv__set_sys_error(loop, handle->bind_error); return -1; @@ -505,6 +532,7 @@ int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { handle->flags |= UV_HANDLE_LISTENING; handle->connection_cb = cb; + INCREASE_ACTIVE_COUNT(loop, handle); simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1 : uv_simultaneous_server_accepts; @@ -623,6 +651,7 @@ int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb, handle->flags |= UV_HANDLE_READING; handle->read_cb = read_cb; handle->alloc_cb = alloc_cb; + INCREASE_ACTIVE_COUNT(loop, handle); /* If reading was stopped and then started again, there could still be a */ /* read request pending. */ @@ -683,12 +712,12 @@ int uv__tcp_connect(uv_connect_t* req, if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { /* Process the req without IOCP. */ handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); uv_insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(success)) { /* The req will be processed with IOCP. */ handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); } else { uv__set_sys_error(loop, WSAGetLastError()); return -1; @@ -744,11 +773,11 @@ int uv__tcp_connect6(uv_connect_t* req, if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); uv_insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(success)) { handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); } else { uv__set_sys_error(loop, WSAGetLastError()); return -1; @@ -837,6 +866,7 @@ int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle, uv_fatal_error(GetLastError(), "CreateEvent"); } req->overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1); + req->wait_handle = INVALID_HANDLE_VALUE; } result = WSASend(handle->socket, @@ -852,20 +882,19 @@ int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle, req->queued_bytes = 0; handle->reqs_pending++; handle->write_reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); uv_insert_pending_req(loop, (uv_req_t*) req); - uv_ref(loop); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* Request queued by the kernel. */ req->queued_bytes = uv_count_bufs(bufs, bufcnt); handle->reqs_pending++; handle->write_reqs_pending++; + REGISTER_HANDLE_REQ(loop, handle, req); handle->write_queue_size += req->queued_bytes; - uv_ref(loop); if (handle->flags & UV_HANDLE_EMULATE_IOCP && - req->wait_handle == INVALID_HANDLE_VALUE && !RegisterWaitForSingleObject(&req->wait_handle, - req->overlapped.hEvent, post_completion, (void*) req, - INFINITE, WT_EXECUTEINWAITTHREAD)) { + req->event_handle, post_write_completion, (void*) req, + INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) { SET_REQ_ERROR(req, GetLastError()); uv_insert_pending_req(loop, (uv_req_t*)req); } @@ -893,6 +922,7 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, if ((handle->flags & UV_HANDLE_READING) || !(handle->flags & UV_HANDLE_ZERO_READ)) { handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); buf = (handle->flags & UV_HANDLE_ZERO_READ) ? uv_buf_init(NULL, 0) : handle->read_buffer; @@ -923,8 +953,12 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, } } else { /* Connection closed */ - handle->flags &= ~UV_HANDLE_READING; + if (handle->flags & UV_HANDLE_READING) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + } handle->flags |= UV_HANDLE_EOF; + uv__set_error(loop, UV_EOF, ERROR_SUCCESS); buf.base = 0; buf.len = 0; @@ -955,7 +989,9 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, } else { /* Connection closed */ handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); handle->flags |= UV_HANDLE_EOF; + uv__set_error(loop, UV_EOF, ERROR_SUCCESS); handle->read_cb((uv_stream_t*)handle, -1, buf); break; @@ -967,16 +1003,18 @@ void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv__set_sys_error(loop, WSAEWOULDBLOCK); handle->read_cb((uv_stream_t*)handle, 0, buf); } else { + /* Ouch! serious error. */ + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + if (err == WSAECONNABORTED) { - /* - * Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix. - */ + /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with */ + /* Unix. */ uv__set_error(loop, UV_ECONNRESET, err); } else { - /* Ouch! serious error. */ uv__set_sys_error(loop, err); } - handle->flags &= ~UV_HANDLE_READING; + handle->read_cb((uv_stream_t*)handle, -1, buf); } break; @@ -1002,14 +1040,14 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, assert(handle->write_queue_size >= req->queued_bytes); handle->write_queue_size -= req->queued_bytes; + UNREGISTER_HANDLE_REQ(loop, handle, req); + if (handle->flags & UV_HANDLE_EMULATE_IOCP) { if (req->wait_handle != INVALID_HANDLE_VALUE) { UnregisterWait(req->wait_handle); - req->wait_handle = INVALID_HANDLE_VALUE; } if (req->event_handle) { CloseHandle(req->event_handle); - req->event_handle = NULL; } } @@ -1025,7 +1063,6 @@ void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle, } DECREASE_PENDING_REQ_COUNT(handle); - uv_unref(loop); } @@ -1042,6 +1079,7 @@ void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle, if (req->accept_socket == INVALID_SOCKET) { if (handle->flags & UV_HANDLE_LISTENING) { handle->flags &= ~UV_HANDLE_LISTENING; + DECREASE_ACTIVE_COUNT(loop, handle); if (handle->connection_cb) { uv__set_sys_error(loop, GET_REQ_SOCK_ERROR(req)); handle->connection_cb((uv_stream_t*)handle, -1); @@ -1079,28 +1117,27 @@ void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle, uv_connect_t* req) { assert(handle->type == UV_TCP); - if (req->cb) { - if (REQ_SUCCESS(req)) { - if (setsockopt(handle->socket, - SOL_SOCKET, - SO_UPDATE_CONNECT_CONTEXT, - NULL, - 0) == 0) { - uv_connection_init((uv_stream_t*)handle); - loop->active_tcp_streams++; - ((uv_connect_cb)req->cb)(req, 0); - } else { - uv__set_sys_error(loop, WSAGetLastError()); - ((uv_connect_cb)req->cb)(req, -1); - } + UNREGISTER_HANDLE_REQ(loop, handle, req); + + if (REQ_SUCCESS(req)) { + if (setsockopt(handle->socket, + SOL_SOCKET, + SO_UPDATE_CONNECT_CONTEXT, + NULL, + 0) == 0) { + uv_connection_init((uv_stream_t*)handle); + loop->active_tcp_streams++; + ((uv_connect_cb)req->cb)(req, 0); } else { - uv__set_sys_error(loop, GET_REQ_SOCK_ERROR(req)); + uv__set_sys_error(loop, WSAGetLastError()); ((uv_connect_cb)req->cb)(req, -1); } + } else { + uv__set_sys_error(loop, GET_REQ_SOCK_ERROR(req)); + ((uv_connect_cb)req->cb)(req, -1); } DECREASE_PENDING_REQ_COUNT(handle); - uv_unref(loop); } @@ -1132,7 +1169,7 @@ int uv_tcp_import(uv_tcp_t* tcp, WSAPROTOCOL_INFOW* socket_protocol_info, if (uv_tcp_set_socket(tcp->loop, tcp, socket, 1) != 0) { return -1; } - + tcp->loop->active_tcp_streams++; return 0; } @@ -1172,11 +1209,10 @@ int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) { } - int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid, LPWSAPROTOCOL_INFOW protocol_info) { if (!(handle->flags & UV_HANDLE_CONNECTION)) { - /* + /* * We're about to share the socket with another process. Because * this is a listening socket, we assume that the other process will * be accepting connections on it. So, before sharing the socket @@ -1240,7 +1276,7 @@ int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) { } -void uv_tcp_close(uv_tcp_t* tcp) { +void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) { int non_ifs_lsp; int close_socket = 1; @@ -1259,7 +1295,7 @@ void uv_tcp_close(uv_tcp_t* tcp) { uv_tcp_non_ifs_lsp_ipv4; if (!non_ifs_lsp) { - /* + /* * Shared socket with no non-IFS LSPs, request to cancel pending I/O. * The socket will be closed inside endgame. */ @@ -1269,13 +1305,23 @@ void uv_tcp_close(uv_tcp_t* tcp) { } } - tcp->flags &= ~(UV_HANDLE_READING | UV_HANDLE_LISTENING); + if (tcp->flags & UV_HANDLE_READING) { + tcp->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, tcp); + } + + if (tcp->flags & UV_HANDLE_LISTENING) { + tcp->flags &= ~UV_HANDLE_LISTENING; + DECREASE_ACTIVE_COUNT(loop, tcp); + } if (close_socket) { closesocket(tcp->socket); tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED; } + uv__handle_start(tcp); + if (tcp->reqs_pending == 0) { uv_want_endgame(tcp->loop, (uv_handle_t*)tcp); } diff --git a/deps/uv/src/win/thread.c b/deps/uv/src/win/thread.c index d6d3ce8f39..01b8140885 100644 --- a/deps/uv/src/win/thread.c +++ b/deps/uv/src/win/thread.c @@ -19,10 +19,11 @@ * IN THE SOFTWARE. */ +#include <assert.h> + #include "uv.h" -#include "../uv-common.h" #include "internal.h" -#include <assert.h> + #define HAVE_SRWLOCK_API() (pTryAcquireSRWLockShared != NULL) diff --git a/deps/uv/src/win/threadpool.c b/deps/uv/src/win/threadpool.c index 4fb20d34bc..e066810d53 100644 --- a/deps/uv/src/win/threadpool.c +++ b/deps/uv/src/win/threadpool.c @@ -61,13 +61,13 @@ int uv_queue_work(uv_loop_t* loop, uv_work_t* req, uv_work_cb work_cb, return -1; } - uv_ref(loop); + uv__req_register(loop, req); return 0; } void uv_process_work_req(uv_loop_t* loop, uv_work_t* req) { assert(req->after_work_cb); + uv__req_unregister(loop, req); req->after_work_cb(req); - uv_unref(loop); } diff --git a/deps/uv/src/win/timer.c b/deps/uv/src/win/timer.c index 555d71ea6d..fbde888d80 100644 --- a/deps/uv/src/win/timer.c +++ b/deps/uv/src/win/timer.c @@ -26,12 +26,12 @@ #include "internal.h" #include "tree.h" + #undef NANOSEC #define NANOSEC 1000000000 /* The resolution of the high-resolution clock. */ -static int64_t uv_ticks_per_msec_ = 0; static uint64_t uv_hrtime_frequency_ = 0; static uv_once_t uv_hrtime_init_guard_ = UV_ONCE_INIT; @@ -112,16 +112,12 @@ RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare); int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) { - loop->counters.handle_init++; - loop->counters.timer_init++; - + uv_handle_init(loop, (uv_handle_t*) handle); handle->type = UV_TIMER; - handle->loop = loop; - handle->flags = 0; handle->timer_cb = NULL; handle->repeat = 0; - uv_ref(loop); + loop->counters.timer_init++; return 0; } @@ -131,12 +127,11 @@ void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle) { if (handle->flags & UV_HANDLE_CLOSING) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } - - uv_unref(loop); } } @@ -153,6 +148,7 @@ int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, int64_t timeout, handle->due = loop->time + timeout; handle->repeat = repeat; handle->flags |= UV_HANDLE_ACTIVE; + uv__handle_start(handle); if (RB_INSERT(uv_timer_tree_s, &loop->timers, handle) != NULL) { uv_fatal_error(ERROR_INVALID_DATA, "RB_INSERT"); @@ -171,6 +167,7 @@ int uv_timer_stop(uv_timer_t* handle) { RB_REMOVE(uv_timer_tree_s, &loop->timers, handle); handle->flags &= ~UV_HANDLE_ACTIVE; + uv__handle_stop(handle); return 0; } @@ -188,6 +185,7 @@ int uv_timer_again(uv_timer_t* handle) { if (handle->flags & UV_HANDLE_ACTIVE) { RB_REMOVE(uv_timer_tree_s, &loop->timers, handle); handle->flags &= ~UV_HANDLE_ACTIVE; + uv__handle_stop(handle); } if (handle->repeat) { @@ -198,6 +196,7 @@ int uv_timer_again(uv_timer_t* handle) { } handle->flags |= UV_HANDLE_ACTIVE; + uv__handle_start(handle); } return 0; @@ -269,6 +268,7 @@ void uv_process_timers(uv_loop_t* loop) { } else { /* If non-repeating, mark the timer as inactive. */ timer->flags &= ~UV_HANDLE_ACTIVE; + uv__handle_stop(timer); } timer->timer_cb((uv_timer_t*) timer, 0); diff --git a/deps/uv/src/win/tty.c b/deps/uv/src/win/tty.c index 5bf90bec24..bd46215e0b 100644 --- a/deps/uv/src/win/tty.c +++ b/deps/uv/src/win/tty.c @@ -25,7 +25,6 @@ #include <stdint.h> #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -462,8 +461,9 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, /* Fetch the number of events */ if (!GetNumberOfConsoleInputEvents(handle->handle, &records_left)) { - handle->flags &= ~UV_HANDLE_READING; uv__set_sys_error(loop, GetLastError()); + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); handle->read_cb((uv_stream_t*)handle, -1, uv_null_buf_); goto out; } @@ -483,6 +483,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, &records_read)) { uv__set_sys_error(loop, GetLastError()); handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); handle->read_cb((uv_stream_t*) handle, -1, buf); goto out; } @@ -583,6 +584,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle, if (!char_len) { uv__set_sys_error(loop, GetLastError()); handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); handle->read_cb((uv_stream_t*) handle, -1, buf); goto out; } @@ -691,6 +693,7 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle, !(handle->flags & UV_HANDLE_TTY_RAW)) { /* Real error */ handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); uv__set_sys_error(loop, GET_REQ_ERROR(req)); handle->read_cb((uv_stream_t*) handle, -1, buf); } else { @@ -738,6 +741,7 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, uv_loop_t* loop = handle->loop; handle->flags |= UV_HANDLE_READING; + INCREASE_ACTIVE_COUNT(loop, handle); handle->read_cb = read_cb; handle->alloc_cb = alloc_cb; @@ -762,7 +766,12 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, int uv_tty_read_stop(uv_tty_t* handle) { - handle->flags &= ~UV_HANDLE_READING; + uv_loop_t* loop = handle->loop; + + if (handle->flags & UV_HANDLE_READING) { + handle->flags &= ~UV_HANDLE_READING; + DECREASE_ACTIVE_COUNT(loop, handle); + } /* Cancel raw read */ if ((handle->flags & UV_HANDLE_READ_PENDING) && @@ -772,7 +781,7 @@ int uv_tty_read_stop(uv_tty_t* handle) { DWORD written; memset(&record, 0, sizeof record); if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) { - uv__set_sys_error(handle->loop, GetLastError()); + uv__set_sys_error(loop, GetLastError()); return -1; } } @@ -960,9 +969,6 @@ static int uv_tty_reset(uv_tty_t* handle, DWORD* error) { static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen, DWORD* error) { - unsigned short argc = handle->ansi_csi_argc; - unsigned short* argv = handle->ansi_csi_argv; - CONSOLE_SCREEN_BUFFER_INFO info; COORD start, end; DWORD count, written; @@ -1683,7 +1689,7 @@ int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle, handle->reqs_pending++; handle->write_reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); req->queued_bytes = 0; @@ -1703,6 +1709,7 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, uv_write_t* req) { handle->write_queue_size -= req->queued_bytes; + UNREGISTER_HANDLE_REQ(loop, handle, req); if (req->cb) { uv__set_sys_error(loop, GET_REQ_ERROR(req)); @@ -1716,7 +1723,6 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle, } DECREASE_PENDING_REQ_COUNT(handle); - uv_unref(loop); } @@ -1726,6 +1732,8 @@ void uv_tty_close(uv_tty_t* handle) { uv_tty_read_stop(handle); CloseHandle(handle->handle); + uv__handle_start(handle); + if (handle->reqs_pending == 0) { uv_want_endgame(handle->loop, (uv_handle_t*) handle); } @@ -1736,6 +1744,8 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { if ((handle->flags && UV_HANDLE_CONNECTION) && handle->shutdown_req != NULL && handle->write_reqs_pending == 0) { + UNREGISTER_HANDLE_REQ(loop, handle, handle->shutdown_req); + /* TTY shutdown is really just a no-op */ if (handle->shutdown_req->cb) { if (handle->flags & UV_HANDLE_CLOSING) { @@ -1748,7 +1758,6 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { handle->shutdown_req = NULL; - uv_unref(loop); DECREASE_PENDING_REQ_COUNT(handle); return; } @@ -1765,12 +1774,11 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } - - uv_unref(loop); } } diff --git a/deps/uv/src/win/udp.c b/deps/uv/src/win/udp.c index 42069aff9c..ddd08a26e7 100644 --- a/deps/uv/src/win/udp.c +++ b/deps/uv/src/win/udp.c @@ -22,7 +22,6 @@ #include <assert.h> #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -121,11 +120,12 @@ static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { + uv_handle_init(loop, (uv_handle_t*) handle); + handle->type = UV_UDP; handle->socket = INVALID_SOCKET; handle->reqs_pending = 0; - handle->loop = loop; - handle->flags = 0; + handle->activecnt = 0; handle->func_wsarecv = WSARecv; handle->func_wsarecvfrom = WSARecvFrom; @@ -133,26 +133,34 @@ int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) { handle->recv_req.type = UV_UDP_RECV; handle->recv_req.data = handle; - uv_ref(loop); - - loop->counters.handle_init++; loop->counters.udp_init++; return 0; } +void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) { + uv_udp_recv_stop(handle); + closesocket(handle->socket); + + uv__handle_start(handle); + + if (handle->reqs_pending == 0) { + uv_want_endgame(loop, (uv_handle_t*) handle); + } +} + + void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) { if (handle->flags & UV_HANDLE_CLOSING && handle->reqs_pending == 0) { assert(!(handle->flags & UV_HANDLE_CLOSED)); handle->flags |= UV_HANDLE_CLOSED; + uv__handle_stop(handle); if (handle->close_cb) { handle->close_cb((uv_handle_t*)handle); } - - uv_unref(loop); } } @@ -350,6 +358,7 @@ int uv_udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb, } handle->flags |= UV_HANDLE_READING; + INCREASE_ACTIVE_COUNT(loop, handle); loop->active_udp_streams++; handle->recv_cb = recv_cb; @@ -368,6 +377,7 @@ int uv_udp_recv_stop(uv_udp_t* handle) { if (handle->flags & UV_HANDLE_READING) { handle->flags &= ~UV_HANDLE_READING; handle->loop->active_udp_streams--; + DECREASE_ACTIVE_COUNT(loop, handle); } return 0; @@ -399,13 +409,13 @@ static int uv__udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[], /* Request completed immediately. */ req->queued_bytes = 0; handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); uv_insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* Request queued by the kernel. */ req->queued_bytes = uv_count_bufs(bufs, bufcnt); handle->reqs_pending++; - uv_ref(loop); + REGISTER_HANDLE_REQ(loop, handle, req); } else { /* Send failed due to an error. */ uv__set_sys_error(loop, WSAGetLastError()); @@ -561,6 +571,8 @@ void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, uv_udp_send_t* req) { assert(handle->type == UV_UDP); + UNREGISTER_HANDLE_REQ(loop, handle, req); + if (req->cb) { if (REQ_SUCCESS(req)) { req->cb(req, 0); @@ -570,7 +582,6 @@ void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle, } } - uv_unref(loop); DECREASE_PENDING_REQ_COUNT(handle); } diff --git a/deps/uv/src/win/util.c b/deps/uv/src/win/util.c index f4d5fdbea9..10c2271232 100644 --- a/deps/uv/src/win/util.c +++ b/deps/uv/src/win/util.c @@ -29,9 +29,10 @@ #include "uv.h" #include "internal.h" -#include "tlhelp32.h" -#include "psapi.h" -#include "iphlpapi.h" + +#include <iphlpapi.h> +#include <psapi.h> +#include <tlhelp32.h> /* diff --git a/deps/uv/src/win/winapi.c b/deps/uv/src/win/winapi.c index ff6912d0e8..4614a3adae 100644 --- a/deps/uv/src/win/winapi.c +++ b/deps/uv/src/win/winapi.c @@ -22,7 +22,6 @@ #include <assert.h> #include "uv.h" -#include "../uv-common.h" #include "internal.h" @@ -33,6 +32,7 @@ sNtSetInformationFile pNtSetInformationFile; sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; sCreateSymbolicLinkW pCreateSymbolicLinkW; +sCancelIoEx pCancelIoEx; sInitializeSRWLock pInitializeSRWLock; sAcquireSRWLockShared pAcquireSRWLockShared; sAcquireSRWLockExclusive pAcquireSRWLockExclusive; @@ -94,6 +94,9 @@ void uv_winapi_init() { pCreateSymbolicLinkW = (sCreateSymbolicLinkW) GetProcAddress(kernel32_module, "CreateSymbolicLinkW"); + pCancelIoEx = (sCancelIoEx) + GetProcAddress(kernel32_module, "CancelIoEx"); + pInitializeSRWLock = (sInitializeSRWLock) GetProcAddress(kernel32_module, "InitializeSRWLock"); diff --git a/deps/uv/src/win/winapi.h b/deps/uv/src/win/winapi.h index 073b9e8c0c..4b1a249fb3 100644 --- a/deps/uv/src/win/winapi.h +++ b/deps/uv/src/win/winapi.h @@ -4141,6 +4141,10 @@ typedef struct _FILE_MODE_INFORMATION { ULONG Mode; } FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION; +typedef struct _FILE_END_OF_FILE_INFORMATION { + LARGE_INTEGER EndOfFile; +} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION; + #define FILE_SYNCHRONOUS_IO_ALERT 0x00000010 #define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020 @@ -4374,6 +4378,10 @@ typedef BOOLEAN (WINAPI* sCreateSymbolicLinkW) LPCWSTR lpTargetFileName, DWORD dwFlags); +typedef BOOL (WINAPI* sCancelIoEx) + (HANDLE hFile, + LPOVERLAPPED lpOverlapped); + typedef VOID (WINAPI* sInitializeSRWLock) (PSRWLOCK SRWLock); @@ -4408,6 +4416,7 @@ extern sNtSetInformationFile pNtSetInformationFile; extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx; extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes; extern sCreateSymbolicLinkW pCreateSymbolicLinkW; +extern sCancelIoEx pCancelIoEx; extern sInitializeSRWLock pInitializeSRWLock; extern sAcquireSRWLockShared pAcquireSRWLockShared; extern sAcquireSRWLockExclusive pAcquireSRWLockExclusive; diff --git a/deps/uv/src/win/winsock.c b/deps/uv/src/win/winsock.c index 667145dd96..2c3e49a103 100644 --- a/deps/uv/src/win/winsock.c +++ b/deps/uv/src/win/winsock.c @@ -22,9 +22,9 @@ #include <assert.h> #include "uv.h" -#include "../uv-common.h" #include "internal.h" + /* Whether ipv6 is supported */ int uv_allow_ipv6; @@ -468,3 +468,90 @@ int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers, return SOCKET_ERROR; } } + + +int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info, + OVERLAPPED* overlapped) { + IO_STATUS_BLOCK iosb; + IO_STATUS_BLOCK* iosb_ptr; + HANDLE event = NULL; + void* apc_context; + NTSTATUS status; + DWORD error; + + if (overlapped != NULL) { + /* Overlapped operation. */ + iosb_ptr = (IO_STATUS_BLOCK*) &overlapped->Internal; + event = overlapped->hEvent; + + /* Do not report iocp completion if hEvent is tagged. */ + if ((uintptr_t) event & 1) { + event = (HANDLE)((uintptr_t) event & ~(uintptr_t) 1); + apc_context = NULL; + } else { + apc_context = overlapped; + } + + } else { + /* Blocking operation. */ + iosb_ptr = &iosb; + event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (event == NULL) { + return SOCKET_ERROR; + } + apc_context = NULL; + } + + iosb_ptr->Status = STATUS_PENDING; + status = pNtDeviceIoControlFile((HANDLE) socket, + event, + NULL, + apc_context, + iosb_ptr, + IOCTL_AFD_POLL, + info, + sizeof *info, + info, + sizeof *info); + + if (overlapped == NULL) { + /* If this is a blocking operation, wait for the event to become */ + /* signaled, and then grab the real status from the io status block. */ + if (status == STATUS_PENDING) { + DWORD r = WaitForSingleObject(event, INFINITE); + + if (r == WAIT_FAILED) { + DWORD saved_error = GetLastError(); + CloseHandle(event); + WSASetLastError(saved_error); + return SOCKET_ERROR; + } + + status = iosb.Status; + } + + CloseHandle(event); + } + + switch (status) { + case STATUS_SUCCESS: + error = ERROR_SUCCESS; + break; + + case STATUS_PENDING: + error = WSA_IO_PENDING; + break; + + default: + error = uv_ntstatus_to_winsock_error(status); + break; + } + + WSASetLastError(error); + + if (error == ERROR_SUCCESS) { + return 0; + } else { + return SOCKET_ERROR; + } +} diff --git a/deps/uv/src/win/winsock.h b/deps/uv/src/win/winsock.h index d070d58092..957d08ec19 100644 --- a/deps/uv/src/win/winsock.h +++ b/deps/uv/src/win/winsock.h @@ -43,11 +43,15 @@ #endif #ifndef IPV6_V6ONLY - #define IPV6_V6ONLY 27 +# define IPV6_V6ONLY 27 #endif #ifndef IPV6_HOPLIMIT - #define IPV6_HOPLIMIT 21 +# define IPV6_HOPLIMIT 21 +#endif + +#ifndef SIO_BASE_HANDLE +# define SIO_BASE_HANDLE 0x48000022 #endif /* @@ -81,6 +85,32 @@ #define AFD_OVERLAPPED 0x00000002 #define AFD_IMMEDIATE 0x00000004 +#define AFD_POLL_RECEIVE_BIT 0 +#define AFD_POLL_RECEIVE (1 << AFD_POLL_RECEIVE_BIT) +#define AFD_POLL_RECEIVE_EXPEDITED_BIT 1 +#define AFD_POLL_RECEIVE_EXPEDITED (1 << AFD_POLL_RECEIVE_EXPEDITED_BIT) +#define AFD_POLL_SEND_BIT 2 +#define AFD_POLL_SEND (1 << AFD_POLL_SEND_BIT) +#define AFD_POLL_DISCONNECT_BIT 3 +#define AFD_POLL_DISCONNECT (1 << AFD_POLL_DISCONNECT_BIT) +#define AFD_POLL_ABORT_BIT 4 +#define AFD_POLL_ABORT (1 << AFD_POLL_ABORT_BIT) +#define AFD_POLL_LOCAL_CLOSE_BIT 5 +#define AFD_POLL_LOCAL_CLOSE (1 << AFD_POLL_LOCAL_CLOSE_BIT) +#define AFD_POLL_CONNECT_BIT 6 +#define AFD_POLL_CONNECT (1 << AFD_POLL_CONNECT_BIT) +#define AFD_POLL_ACCEPT_BIT 7 +#define AFD_POLL_ACCEPT (1 << AFD_POLL_ACCEPT_BIT) +#define AFD_POLL_CONNECT_FAIL_BIT 8 +#define AFD_POLL_CONNECT_FAIL (1 << AFD_POLL_CONNECT_FAIL_BIT) +#define AFD_POLL_QOS_BIT 9 +#define AFD_POLL_QOS (1 << AFD_POLL_QOS_BIT) +#define AFD_POLL_GROUP_QOS_BIT 10 +#define AFD_POLL_GROUP_QOS (1 << AFD_POLL_GROUP_QOS_BIT) + +#define AFD_NUM_POLL_EVENTS 11 +#define AFD_POLL_ALL ((1 << AFD_NUM_POLL_EVENTS) - 1) + typedef struct _AFD_RECV_DATAGRAM_INFO { LPWSABUF BufferArray; ULONG BufferCount; @@ -105,6 +135,7 @@ typedef struct _AFD_RECV_INFO { #define AFD_RECEIVE 5 #define AFD_RECEIVE_DATAGRAM 6 +#define AFD_POLL 9 #define IOCTL_AFD_RECEIVE \ _AFD_CONTROL_CODE(AFD_RECEIVE, METHOD_NEITHER) @@ -112,8 +143,10 @@ typedef struct _AFD_RECV_INFO { #define IOCTL_AFD_RECEIVE_DATAGRAM \ _AFD_CONTROL_CODE(AFD_RECEIVE_DATAGRAM, METHOD_NEITHER) -#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) +#define IOCTL_AFD_POLL \ + _AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED) +#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR) typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP { /* FIXME: __C89_NAMELESS was removed */ /* __C89_NAMELESS */ union { |