| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652 |
- /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
- #include <assert.h>
- #include <errno.h>
- #include <limits.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
- #include <crtdbg.h>
- #endif
- #include "uv.h"
- #include "internal.h"
- #include "queue.h"
- #include "handle-inl.h"
- #include "heap-inl.h"
- #include "req-inl.h"
- /* uv_once initialization guards */
- static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
- #if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
- /* Our crt debug report handler allows us to temporarily disable asserts
- * just for the current thread.
- */
- UV_THREAD_LOCAL int uv__crt_assert_enabled = TRUE;
- static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_val) {
- if (uv__crt_assert_enabled || report_type != _CRT_ASSERT)
- return FALSE;
- if (ret_val) {
- /* Set ret_val to 0 to continue with normal execution.
- * Set ret_val to 1 to trigger a breakpoint.
- */
- if(IsDebuggerPresent())
- *ret_val = 1;
- else
- *ret_val = 0;
- }
- /* Don't call _CrtDbgReport. */
- return TRUE;
- }
- #else
- UV_THREAD_LOCAL int uv__crt_assert_enabled = FALSE;
- #endif
- #if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
- static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
- const wchar_t* function, const wchar_t * file, unsigned int line,
- uintptr_t reserved) {
- /* No-op. */
- }
- #endif
- static uv_loop_t** uv__loops;
- static int uv__loops_size;
- static int uv__loops_capacity;
- #define UV__LOOPS_CHUNK_SIZE 8
- static uv_mutex_t uv__loops_lock;
- static void uv__loops_init(void) {
- uv_mutex_init(&uv__loops_lock);
- }
- static int uv__loops_add(uv_loop_t* loop) {
- uv_loop_t** new_loops;
- int new_capacity, i;
- uv_mutex_lock(&uv__loops_lock);
- if (uv__loops_size == uv__loops_capacity) {
- new_capacity = uv__loops_capacity + UV__LOOPS_CHUNK_SIZE;
- new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * new_capacity);
- if (!new_loops)
- goto failed_loops_realloc;
- uv__loops = new_loops;
- for (i = uv__loops_capacity; i < new_capacity; ++i)
- uv__loops[i] = NULL;
- uv__loops_capacity = new_capacity;
- }
- uv__loops[uv__loops_size] = loop;
- ++uv__loops_size;
- uv_mutex_unlock(&uv__loops_lock);
- return 0;
- failed_loops_realloc:
- uv_mutex_unlock(&uv__loops_lock);
- return ERROR_OUTOFMEMORY;
- }
- static void uv__loops_remove(uv_loop_t* loop) {
- int loop_index;
- int smaller_capacity;
- uv_loop_t** new_loops;
- uv_mutex_lock(&uv__loops_lock);
- for (loop_index = 0; loop_index < uv__loops_size; ++loop_index) {
- if (uv__loops[loop_index] == loop)
- break;
- }
- /* If loop was not found, ignore */
- if (loop_index == uv__loops_size)
- goto loop_removed;
- uv__loops[loop_index] = uv__loops[uv__loops_size - 1];
- uv__loops[uv__loops_size - 1] = NULL;
- --uv__loops_size;
- if (uv__loops_size == 0) {
- uv__loops_capacity = 0;
- uv__free(uv__loops);
- uv__loops = NULL;
- goto loop_removed;
- }
- /* If we didn't grow to big skip downsizing */
- if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE)
- goto loop_removed;
- /* Downsize only if more than half of buffer is free */
- smaller_capacity = uv__loops_capacity / 2;
- if (uv__loops_size >= smaller_capacity)
- goto loop_removed;
- new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * smaller_capacity);
- if (!new_loops)
- goto loop_removed;
- uv__loops = new_loops;
- uv__loops_capacity = smaller_capacity;
- loop_removed:
- uv_mutex_unlock(&uv__loops_lock);
- }
- void uv__wake_all_loops(void) {
- int i;
- uv_loop_t* loop;
- uv_mutex_lock(&uv__loops_lock);
- for (i = 0; i < uv__loops_size; ++i) {
- loop = uv__loops[i];
- assert(loop);
- if (loop->iocp != INVALID_HANDLE_VALUE)
- PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL);
- }
- uv_mutex_unlock(&uv__loops_lock);
- }
- static void uv_init(void) {
- /* Tell Windows that we will handle critical errors. */
- SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
- SEM_NOOPENFILEERRORBOX);
- /* Tell the CRT to not exit the application when an invalid parameter is
- * passed. The main issue is that invalid FDs will trigger this behavior.
- */
- #if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
- _set_invalid_parameter_handler(uv__crt_invalid_parameter_handler);
- #endif
- /* We also need to setup our debug report handler because some CRT
- * functions (eg _get_osfhandle) raise an assert when called with invalid
- * FDs even though they return the proper error code in the release build.
- */
- #if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
- _CrtSetReportHook(uv__crt_dbg_report_handler);
- #endif
- /* Initialize tracking of all uv loops */
- uv__loops_init();
- /* Fetch winapi function pointers. This must be done first because other
- * initialization code might need these function pointers to be loaded.
- */
- uv_winapi_init();
- /* Initialize winsock */
- uv_winsock_init();
- /* Initialize FS */
- uv_fs_init();
- /* Initialize signal stuff */
- uv_signals_init();
- /* Initialize console */
- uv_console_init();
- /* Initialize utilities */
- uv__util_init();
- /* Initialize system wakeup detection */
- uv__init_detect_system_wakeup();
- }
- int uv_loop_init(uv_loop_t* loop) {
- struct heap* timer_heap;
- int err;
- /* Initialize libuv itself first */
- uv__once_init();
- /* Create an I/O completion port */
- loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
- if (loop->iocp == NULL)
- return uv_translate_sys_error(GetLastError());
- /* To prevent uninitialized memory access, loop->time must be initialized
- * to zero before calling uv_update_time for the first time.
- */
- loop->time = 0;
- uv_update_time(loop);
- QUEUE_INIT(&loop->wq);
- QUEUE_INIT(&loop->handle_queue);
- loop->active_reqs.count = 0;
- loop->active_handles = 0;
- loop->pending_reqs_tail = NULL;
- loop->endgame_handles = NULL;
- loop->timer_heap = timer_heap = uv__malloc(sizeof(*timer_heap));
- if (timer_heap == NULL) {
- err = UV_ENOMEM;
- goto fail_timers_alloc;
- }
- heap_init(timer_heap);
- loop->check_handles = NULL;
- loop->prepare_handles = NULL;
- loop->idle_handles = NULL;
- loop->next_prepare_handle = NULL;
- loop->next_check_handle = NULL;
- loop->next_idle_handle = NULL;
- memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets);
- loop->active_tcp_streams = 0;
- loop->active_udp_streams = 0;
- loop->timer_counter = 0;
- loop->stop_flag = 0;
- err = uv_mutex_init(&loop->wq_mutex);
- if (err)
- goto fail_mutex_init;
- err = uv_async_init(loop, &loop->wq_async, uv__work_done);
- if (err)
- goto fail_async_init;
- uv__handle_unref(&loop->wq_async);
- loop->wq_async.flags |= UV_HANDLE_INTERNAL;
- err = uv__loops_add(loop);
- if (err)
- goto fail_async_init;
- return 0;
- fail_async_init:
- uv_mutex_destroy(&loop->wq_mutex);
- fail_mutex_init:
- uv__free(timer_heap);
- loop->timer_heap = NULL;
- fail_timers_alloc:
- CloseHandle(loop->iocp);
- loop->iocp = INVALID_HANDLE_VALUE;
- return err;
- }
- void uv_update_time(uv_loop_t* loop) {
- uint64_t new_time = uv__hrtime(1000);
- assert(new_time >= loop->time);
- loop->time = new_time;
- }
- void uv__once_init(void) {
- uv_once(&uv_init_guard_, uv_init);
- }
- void uv__loop_close(uv_loop_t* loop) {
- size_t i;
- uv__loops_remove(loop);
- /* close the async handle without needing an extra loop iteration */
- assert(!loop->wq_async.async_sent);
- loop->wq_async.close_cb = NULL;
- uv__handle_closing(&loop->wq_async);
- uv__handle_close(&loop->wq_async);
- 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);
- }
- uv_mutex_lock(&loop->wq_mutex);
- assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
- assert(!uv__has_active_reqs(loop));
- uv_mutex_unlock(&loop->wq_mutex);
- uv_mutex_destroy(&loop->wq_mutex);
- uv__free(loop->timer_heap);
- loop->timer_heap = NULL;
- CloseHandle(loop->iocp);
- }
- int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
- return UV_ENOSYS;
- }
- int uv_backend_fd(const uv_loop_t* loop) {
- return -1;
- }
- int uv_loop_fork(uv_loop_t* loop) {
- return UV_ENOSYS;
- }
- int uv_backend_timeout(const uv_loop_t* loop) {
- if (loop->stop_flag != 0)
- return 0;
- if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
- return 0;
- if (loop->pending_reqs_tail)
- return 0;
- if (loop->endgame_handles)
- return 0;
- if (loop->idle_handles)
- return 0;
- return uv__next_timeout(loop);
- }
- static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
- DWORD bytes;
- ULONG_PTR key;
- OVERLAPPED* overlapped;
- uv_req_t* req;
- int repeat;
- uint64_t timeout_time;
- timeout_time = loop->time + timeout;
- for (repeat = 0; ; repeat++) {
- GetQueuedCompletionStatus(loop->iocp,
- &bytes,
- &key,
- &overlapped,
- timeout);
- if (overlapped) {
- /* Package was dequeued */
- req = uv_overlapped_to_req(overlapped);
- uv_insert_pending_req(loop, req);
- /* Some time might have passed waiting for I/O,
- * so update the loop time here.
- */
- uv_update_time(loop);
- } else if (GetLastError() != WAIT_TIMEOUT) {
- /* Serious error */
- uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
- } else if (timeout > 0) {
- /* GetQueuedCompletionStatus can occasionally return a little early.
- * Make sure that the desired timeout target time is reached.
- */
- uv_update_time(loop);
- if (timeout_time > loop->time) {
- timeout = (DWORD)(timeout_time - loop->time);
- /* The first call to GetQueuedCompletionStatus should return very
- * close to the target time and the second should reach it, but
- * this is not stated in the documentation. To make sure a busy
- * loop cannot happen, the timeout is increased exponentially
- * starting on the third round.
- */
- timeout += repeat ? (1 << (repeat - 1)) : 0;
- continue;
- }
- }
- break;
- }
- }
- static void uv__poll(uv_loop_t* loop, DWORD timeout) {
- BOOL success;
- uv_req_t* req;
- OVERLAPPED_ENTRY overlappeds[128];
- ULONG count;
- ULONG i;
- int repeat;
- uint64_t timeout_time;
- timeout_time = loop->time + timeout;
- for (repeat = 0; ; repeat++) {
- success = GetQueuedCompletionStatusEx(loop->iocp,
- overlappeds,
- ARRAY_SIZE(overlappeds),
- &count,
- timeout,
- FALSE);
- if (success) {
- for (i = 0; i < count; i++) {
- /* Package was dequeued, but see if it is not a empty package
- * meant only to wake us up.
- */
- if (overlappeds[i].lpOverlapped) {
- req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
- uv_insert_pending_req(loop, req);
- }
- }
- /* Some time might have passed waiting for I/O,
- * so update the loop time here.
- */
- uv_update_time(loop);
- } else if (GetLastError() != WAIT_TIMEOUT) {
- /* Serious error */
- uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx");
- } else if (timeout > 0) {
- /* GetQueuedCompletionStatus can occasionally return a little early.
- * Make sure that the desired timeout target time is reached.
- */
- uv_update_time(loop);
- if (timeout_time > loop->time) {
- timeout = (DWORD)(timeout_time - loop->time);
- /* The first call to GetQueuedCompletionStatus should return very
- * close to the target time and the second should reach it, but
- * this is not stated in the documentation. To make sure a busy
- * loop cannot happen, the timeout is increased exponentially
- * starting on the third round.
- */
- timeout += repeat ? (1 << (repeat - 1)) : 0;
- continue;
- }
- }
- break;
- }
- }
- static int uv__loop_alive(const uv_loop_t* loop) {
- return uv__has_active_handles(loop) ||
- uv__has_active_reqs(loop) ||
- loop->endgame_handles != NULL;
- }
- int uv_loop_alive(const uv_loop_t* loop) {
- return uv__loop_alive(loop);
- }
- int uv_run(uv_loop_t *loop, uv_run_mode mode) {
- DWORD timeout;
- int r;
- int ran_pending;
- r = uv__loop_alive(loop);
- if (!r)
- uv_update_time(loop);
- while (r != 0 && loop->stop_flag == 0) {
- uv_update_time(loop);
- uv__run_timers(loop);
- ran_pending = uv_process_reqs(loop);
- uv_idle_invoke(loop);
- uv_prepare_invoke(loop);
- timeout = 0;
- if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
- timeout = uv_backend_timeout(loop);
- if (pGetQueuedCompletionStatusEx)
- uv__poll(loop, timeout);
- else
- uv__poll_wine(loop, timeout);
- uv_check_invoke(loop);
- uv_process_endgames(loop);
- if (mode == UV_RUN_ONCE) {
- /* UV_RUN_ONCE implies forward progress: at least one callback must have
- * been invoked when it returns. uv__io_poll() can return without doing
- * I/O (meaning: no callbacks) when its timeout expires - which means we
- * have pending timers that satisfy the forward progress constraint.
- *
- * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
- * the check.
- */
- uv__run_timers(loop);
- }
- r = uv__loop_alive(loop);
- if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
- break;
- }
- /* The if statement lets the compiler compile it to a conditional store.
- * Avoids dirtying a cache line.
- */
- if (loop->stop_flag != 0)
- loop->stop_flag = 0;
- return r;
- }
- int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
- uv_os_fd_t fd_out;
- switch (handle->type) {
- case UV_TCP:
- fd_out = (uv_os_fd_t)((uv_tcp_t*) handle)->socket;
- break;
- case UV_NAMED_PIPE:
- fd_out = ((uv_pipe_t*) handle)->handle;
- break;
- case UV_TTY:
- fd_out = ((uv_tty_t*) handle)->handle;
- break;
- case UV_UDP:
- fd_out = (uv_os_fd_t)((uv_udp_t*) handle)->socket;
- break;
- case UV_POLL:
- fd_out = (uv_os_fd_t)((uv_poll_t*) handle)->socket;
- break;
- default:
- return UV_EINVAL;
- }
- if (uv_is_closing(handle) || fd_out == INVALID_HANDLE_VALUE)
- return UV_EBADF;
- *fd = fd_out;
- return 0;
- }
- int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
- int r;
- int len;
- SOCKET socket;
- if (handle == NULL || value == NULL)
- return UV_EINVAL;
- if (handle->type == UV_TCP)
- socket = ((uv_tcp_t*) handle)->socket;
- else if (handle->type == UV_UDP)
- socket = ((uv_udp_t*) handle)->socket;
- else
- return UV_ENOTSUP;
- len = sizeof(*value);
- if (*value == 0)
- r = getsockopt(socket, SOL_SOCKET, optname, (char*) value, &len);
- else
- r = setsockopt(socket, SOL_SOCKET, optname, (const char*) value, len);
- if (r == SOCKET_ERROR)
- return uv_translate_sys_error(WSAGetLastError());
- return 0;
- }
- int uv_cpumask_size(void) {
- return (int)(sizeof(DWORD_PTR) * 8);
- }
- int uv__getsockpeername(const uv_handle_t* handle,
- uv__peersockfunc func,
- struct sockaddr* name,
- int* namelen,
- int delayed_error) {
- int result;
- uv_os_fd_t fd;
- result = uv_fileno(handle, &fd);
- if (result != 0)
- return result;
- if (delayed_error)
- return uv_translate_sys_error(delayed_error);
- result = func((SOCKET) fd, name, namelen);
- if (result != 0)
- return uv_translate_sys_error(WSAGetLastError());
- return 0;
- }
|