static DWORD WINAPI uv_pipe_writefile_thread_proc(void* parameter) { int result; DWORD bytes; uv_write_t* req = (uv_write_t*) parameter; uv_pipe_t* handle = (uv_pipe_t*) req->handle; uv_loop_t* loop = handle->loop; assert(req != NULL); assert(req->type == UV_WRITE); assert(handle->type == UV_NAMED_PIPE); assert(req->write_buffer.base); result = WriteFile(handle->handle, req->write_buffer.base, req->write_buffer.len, &bytes, NULL); if (!result) { SET_REQ_ERROR(req, GetLastError()); } POST_COMPLETION_FOR_REQ(loop, req); return 0; }
/* * Dispatches signal {signum} to all active uv_signal_t watchers in all loops. * Returns 1 if the signal was dispatched to any watcher, or 0 if there were * no active signal watchers observing this signal. */ int uv__signal_dispatch(int signum) { uv_signal_t lookup; uv_signal_t* handle; int dispatched = 0; EnterCriticalSection(&uv__signal_lock); lookup.signum = signum; lookup.loop = NULL; for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup); handle != NULL && handle->signum == signum; handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) { unsigned long previous = InterlockedExchange(&handle->pending_signum, signum); if (!previous) { POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req); } dispatched = 1; } LeaveCriticalSection(&uv__signal_lock); return dispatched; }
/* * Called on windows thread pool when CreateProcess failed. It writes an error * message to the process' intended stderr and then posts a PROCESS_EXIT * packet to the completion port. */ static DWORD WINAPI spawn_failure(void* data) { char syscall[] = "CreateProcessW: "; char unknown[] = "unknown error\n"; uv_process_t* process = (uv_process_t*) data; uv_loop_t* loop = process->loop; HANDLE child_stderr = process->child_stdio[2]; char* buf = NULL; DWORD count, written; WriteFile(child_stderr, syscall, sizeof(syscall) - 1, &written, NULL); count = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, process->spawn_errno, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &buf, 0, NULL); if (buf != NULL && count > 0) { WriteFile(child_stderr, buf, count, &written, NULL); LocalFree(buf); } else { WriteFile(child_stderr, unknown, sizeof(unknown) - 1, &written, NULL); } FlushFileBuffers(child_stderr); /* Post completed */ POST_COMPLETION_FOR_REQ(loop, &process->exit_req); return 0; }
/* * Called on Windows thread-pool thread to indicate that * UnregisterWaitEx has completed. */ static void CALLBACK close_wait_callback(void* data, BOOLEAN didTimeout) { uv_process_t* process = (uv_process_t*)data; assert(didTimeout == FALSE); assert(process); /* Post completed */ POST_COMPLETION_FOR_REQ(&process->close_req); }
/* * Called on Windows thread-pool thread to indicate that * a child process has exited. */ static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) { uv_process_t* process = (uv_process_t*)data; uv_loop_t* loop = process->loop; assert(didTimeout == FALSE); assert(process); /* Post completed */ POST_COMPLETION_FOR_REQ(loop, &process->exit_req); }
int uv_async_send(uv_async_t* handle) { /* First do a cheap read. */ if (handle->async_sent != 0) return 0; if (InterlockedExchange(&handle->async_sent, 1) == 0) { uv_loop_t* loop = handle->loop; POST_COMPLETION_FOR_REQ(loop, &loop->async_req); } return 0; }
static DWORD WINAPI uv_work_thread_proc(void* parameter) { uv_work_t* req = (uv_work_t*)parameter; uv_loop_t* loop = req->loop; assert(req != NULL); assert(req->type == UV_WORK); assert(req->work_cb); req->work_cb(req); POST_COMPLETION_FOR_REQ(loop, req); return 0; }
static DWORD WINAPI pipe_connect_thread_proc(void* parameter) { HANDLE pipeHandle = INVALID_HANDLE_VALUE; int errno; uv_loop_t* loop; uv_pipe_t* handle; uv_connect_t* req; req = (uv_connect_t*) parameter; assert(req); handle = (uv_pipe_t*) req->handle; assert(handle); loop = handle->loop; assert(loop); /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. */ /* We wait for the pipe to become available with WaitNamedPipe. */ while (WaitNamedPipeW(handle->name, 30000)) { /* The pipe is now available, try to connect. */ pipeHandle = CreateFileW(handle->name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (pipeHandle != INVALID_HANDLE_VALUE) { break; } SwitchToThread(); } if (pipeHandle != INVALID_HANDLE_VALUE && !uv_set_pipe_handle(loop, handle, pipeHandle)) { handle->handle = pipeHandle; SET_REQ_SUCCESS(req); } else { SET_REQ_ERROR(req, GetLastError()); } /* Post completed */ POST_COMPLETION_FOR_REQ(loop, req); return 0; }
static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) { int errno; uv_pipe_t* handle; uv_shutdown_t* req; req = (uv_shutdown_t*) parameter; assert(req); handle = (uv_pipe_t*) req->handle; assert(handle); FlushFileBuffers(handle->handle); /* Post completed */ POST_COMPLETION_FOR_REQ(req); return 0; }
/* thread pool callback when socket is signalled */ static void CALLBACK uv_ares_socksignal_tp(void* parameter, BOOLEAN timerfired) { WSANETWORKEVENTS network_events; uv_ares_task_t* sockhandle; uv_ares_action_t* selhandle; uv_req_t* uv_ares_req; uv_loop_t* loop; assert(parameter != NULL); if (parameter != NULL) { sockhandle = (uv_ares_task_t*) parameter; loop = sockhandle->loop; /* clear socket status for this event */ /* do not fail if error, thread may run after socket close */ /* The code assumes that c-ares will write all pending data in the */ /* callback, unless the socket would block. We can clear the state here */ /* to avoid unnecessary signals. */ WSAEnumNetworkEvents(sockhandle->sock, sockhandle->h_event, &network_events); /* setup new handle */ selhandle = (uv_ares_action_t*)malloc(sizeof(uv_ares_action_t)); if (selhandle == NULL) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } selhandle->type = UV_ARES_EVENT; selhandle->close_cb = NULL; selhandle->data = sockhandle->data; selhandle->sock = sockhandle->sock; selhandle->read = (network_events.lNetworkEvents & (FD_READ | FD_CONNECT)) ? 1 : 0; selhandle->write = (network_events.lNetworkEvents & (FD_WRITE | FD_CONNECT)) ? 1 : 0; uv_ares_req = &selhandle->ares_req; uv_req_init(loop, uv_ares_req); uv_ares_req->type = UV_ARES_EVENT_REQ; uv_ares_req->data = selhandle; /* post ares needs to called */ POST_COMPLETION_FOR_REQ(loop, uv_ares_req); } }
static void CALLBACK uv_tty_post_raw_read(void* data, BOOLEAN didTimeout) { uv_loop_t* loop; uv_tty_t* handle; uv_req_t* req; assert(data); assert(!didTimeout); req = (uv_req_t*) data; handle = (uv_tty_t*) req->data; loop = handle->loop; UnregisterWait(handle->read_raw_wait); handle->read_raw_wait = NULL; SET_REQ_SUCCESS(req); POST_COMPLETION_FOR_REQ(loop, req); }
int uv_async_send(uv_async_t* handle) { uv_loop_t* loop = handle->loop; if (handle->type != UV_ASYNC) { /* Can't set errno because that's not thread-safe. */ return -1; } /* The user should make sure never to call uv_async_send to a closing */ /* or closed handle. */ assert(!(handle->flags & UV__HANDLE_CLOSING)); if (!uv__atomic_exchange_set(&handle->async_sent)) { POST_COMPLETION_FOR_REQ(loop, &handle->async_req); } return 0; }
/* getaddrinfo worker thread implementation */ static DWORD WINAPI getaddrinfo_thread_proc(void* parameter) { uv_getaddrinfo_t* req = (uv_getaddrinfo_t*) parameter; uv_loop_t* loop = req->loop; int ret; assert(req != NULL); /* call OS function on this thread */ ret = GetAddrInfoW(req->node, req->service, req->hints, &req->res); req->retcode = ret; /* post getaddrinfo completed */ POST_COMPLETION_FOR_REQ(loop, req); return 0; }
/* getnameinfo worker thread implementation */ static DWORD WINAPI getnameinfo_thread_proc(void* parameter) { uv_getnameinfo_t* req = (uv_getnameinfo_t*)parameter; uv_loop_t* loop = req->loop; WCHAR host[NI_MAXHOST]; WCHAR service[NI_MAXSERV]; int ret = 0; assert(req != NULL); ret = GetNameInfoW((struct sockaddr*)&req->storage, sizeof(req->storage), host, sizeof(host), service, sizeof(service), req->flags); req->retcode = uv__getaddrinfo_translate_error(ret); /* convert results to UTF-8 */ WideCharToMultiByte(CP_UTF8, 0, host, -1, req->host, sizeof(req->host), NULL, NULL); WideCharToMultiByte(CP_UTF8, 0, service, -1, req->service, sizeof(req->service), NULL, NULL); /* post getnameinfo completed */ POST_COMPLETION_FOR_REQ(loop, req); return 0; }
/* 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; int ret; assert(handle != NULL); if (handle != NULL) { /* call OS function on this thread */ ret = GetAddrInfoW(handle->node, handle->service, handle->hints, &handle->res); handle->retcode = ret; /* post getaddrinfo completed */ POST_COMPLETION_FOR_REQ(loop, &handle->getadddrinfo_req); } return 0; }
static DWORD WINAPI pipe_connect_thread_proc(void* parameter) { uv_loop_t* loop; uv_pipe_t* handle; uv_connect_t* req; HANDLE pipeHandle = INVALID_HANDLE_VALUE; DWORD duplex_flags; req = (uv_connect_t*) parameter; assert(req); handle = (uv_pipe_t*) req->handle; assert(handle); loop = handle->loop; assert(loop); /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. */ /* We wait for the pipe to become available with WaitNamedPipe. */ while (WaitNamedPipeW(handle->name, 30000)) { /* The pipe is now available, try to connect. */ pipeHandle = open_named_pipe(handle->name, &duplex_flags); if (pipeHandle != INVALID_HANDLE_VALUE) { break; } SwitchToThread(); } if (pipeHandle != INVALID_HANDLE_VALUE && !uv_set_pipe_handle(loop, handle, pipeHandle, duplex_flags)) { SET_REQ_SUCCESS(req); } else { SET_REQ_ERROR(req, GetLastError()); } /* Post completed */ POST_COMPLETION_FOR_REQ(loop, req); return 0; }
static DWORD CALLBACK uv_tty_line_read_thread(void* data) { uv_loop_t* loop; uv_tty_t* handle; uv_req_t* req; DWORD bytes, read_bytes; assert(data); req = (uv_req_t*) data; handle = (uv_tty_t*) req->data; loop = handle->loop; assert(handle->read_line_buffer.base != NULL); assert(handle->read_line_buffer.len > 0); /* ReadConsole can't handle big buffers. */ if (handle->read_line_buffer.len < 8192) { bytes = handle->read_line_buffer.len; } else { bytes = 8192; } /* Todo: Unicode */ if (ReadConsoleA(handle->read_line_handle, (void*) handle->read_line_buffer.base, bytes, &read_bytes, NULL)) { SET_REQ_SUCCESS(req); req->overlapped.InternalHigh = read_bytes; } else { SET_REQ_ERROR(req, GetLastError()); } POST_COMPLETION_FOR_REQ(loop, req); return 0; }
/* called via uv_poll when ares is finished with socket */ void uv_process_ares_cleanup_req(uv_loop_t* loop, uv_ares_task_t* handle, uv_req_t* req) { /* check for event complete without waiting */ unsigned int signaled = WaitForSingleObject(handle->h_close_event, 0); if (signaled != WAIT_TIMEOUT) { uv_unref(loop); /* close event handle and free uv handle memory */ CloseHandle(handle->h_close_event); free(handle); /* decrement active count. if it becomes 0 stop polling */ if (loop->ares_active_sockets > 0) { loop->ares_active_sockets--; if (loop->ares_active_sockets == 0) { uv_close((uv_handle_t*) &loop->ares_polling_timer, NULL); } } } else { /* still busy - repost and try again */ POST_COMPLETION_FOR_REQ(loop, req); } }
static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) { int result; DWORD bytes; uv_read_t* req = (uv_read_t*) parameter; uv_pipe_t* handle = (uv_pipe_t*) req->data; uv_loop_t* loop = handle->loop; assert(req != NULL); assert(req->type == UV_READ); assert(handle->type == UV_NAMED_PIPE); result = ReadFile(handle->handle, &uv_zero_, 0, &bytes, NULL); if (!result) { SET_REQ_ERROR(req, GetLastError()); } POST_COMPLETION_FOR_REQ(loop, req); return 0; }
/* callback from ares when socket operation is started */ static void uv_ares_sockstate_cb(void *data, ares_socket_t sock, int read, int write) { /* look to see if we have a handle for this socket in our list */ uv_loop_t* loop = (uv_loop_t*) data; uv_ares_task_t* uv_handle_ares = uv_find_ares_handle(loop, sock); 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 */ /* write = 0 when the socket is closed. After we receive this we stop */ /* monitoring the socket. */ if (uv_handle_ares != NULL) { uv_req_t* uv_ares_req; uv_handle_ares->h_close_event = CreateEvent(NULL, FALSE, FALSE, NULL); /* remove Wait */ if (uv_handle_ares->h_wait) { UnregisterWaitEx(uv_handle_ares->h_wait, uv_handle_ares->h_close_event); uv_handle_ares->h_wait = NULL; } /* detach socket from the event */ WSAEventSelect(sock, NULL, 0); if (uv_handle_ares->h_event != WSA_INVALID_EVENT) { WSACloseEvent(uv_handle_ares->h_event); uv_handle_ares->h_event = WSA_INVALID_EVENT; } /* remove handle from list */ uv_remove_ares_handle(uv_handle_ares); /* Post request to cleanup the Task */ uv_ares_req = &uv_handle_ares->ares_req; uv_req_init(loop, uv_ares_req); uv_ares_req->type = UV_ARES_CLEANUP_REQ; uv_ares_req->data = uv_handle_ares; /* post ares done with socket - finish cleanup when all threads done. */ POST_COMPLETION_FOR_REQ(loop, uv_ares_req); } else { assert(0); uv_fatal_error(ERROR_INVALID_DATA, "ares_SockStateCB"); } } else { if (uv_handle_ares == NULL) { /* setup new handle */ /* The code assumes that c-ares will call us when it has an open socket. We need to call into c-ares when there is something to read, or when it becomes writable. */ uv_handle_ares = (uv_ares_task_t*)malloc(sizeof(uv_ares_task_t)); if (uv_handle_ares == NULL) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } uv_handle_ares->type = UV_ARES_TASK; uv_handle_ares->close_cb = NULL; uv_handle_ares->loop = loop; uv_handle_ares->data = loop; uv_handle_ares->sock = sock; uv_handle_ares->h_wait = NULL; uv_handle_ares->flags = 0; /* create an event to wait on socket signal */ uv_handle_ares->h_event = WSACreateEvent(); if (uv_handle_ares->h_event == WSA_INVALID_EVENT) { uv_fatal_error(WSAGetLastError(), "WSACreateEvent"); } /* tie event to socket */ if (SOCKET_ERROR == WSAEventSelect(sock, uv_handle_ares->h_event, FD_READ | FD_WRITE | FD_CONNECT)) { uv_fatal_error(WSAGetLastError(), "WSAEventSelect"); } /* add handle to list */ uv_add_ares_handle(loop, uv_handle_ares); uv_ref(loop); /* * we have a single polling timer for all ares sockets. * This is preferred to using ares_timeout. See ares_timeout.c warning. * if timer is not running start it, and keep socket count */ if (loop->ares_active_sockets == 0) { uv_timer_init(loop, &loop->ares_polling_timer); uv_timer_start(&loop->ares_polling_timer, uv_ares_poll, 1000L, 1000L); } loop->ares_active_sockets++; /* specify thread pool function to call when event is signaled */ if (RegisterWaitForSingleObject(&uv_handle_ares->h_wait, uv_handle_ares->h_event, uv_ares_socksignal_tp, (void*)uv_handle_ares, INFINITE, WT_EXECUTEINWAITTHREAD) == 0) { uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject"); } } else { /* found existing handle. */ assert(uv_handle_ares->type == UV_ARES_TASK); assert(uv_handle_ares->data != NULL); assert(uv_handle_ares->h_event != WSA_INVALID_EVENT); } } }
static DWORD WINAPI uv_fs_thread_proc(void* parameter) { uv_fs_t* req = (uv_fs_t*) parameter; uv_loop_t* loop = req->loop; assert(req != NULL); assert(req->type == UV_FS); switch (req->fs_type) { case UV_FS_OPEN: fs__open(req, req->path, (int)req->arg0, (int)req->arg1); break; case UV_FS_CLOSE: fs__close(req, (uv_file)req->arg0); break; case UV_FS_READ: fs__read(req, (uv_file) req->arg0, req->arg1, (size_t) req->arg2, (off_t) req->arg3); break; case UV_FS_WRITE: fs__write(req, (uv_file)req->arg0, req->arg1, (size_t) req->arg2, (off_t) req->arg3); break; case UV_FS_UNLINK: fs__unlink(req, req->path); break; case UV_FS_MKDIR: fs__mkdir(req, req->path, (int)req->arg0); break; case UV_FS_RMDIR: fs__rmdir(req, req->path); break; case UV_FS_READDIR: fs__readdir(req, req->path, (int)req->arg0); break; case UV_FS_STAT: case UV_FS_LSTAT: fs__stat(req, req->path); break; case UV_FS_FSTAT: fs__fstat(req, (uv_file)req->arg0); break; case UV_FS_RENAME: fs__rename(req, req->path, (const char*)req->arg0); break; case UV_FS_FSYNC: case UV_FS_FDATASYNC: fs__fsync(req, (uv_file)req->arg0); break; case UV_FS_FTRUNCATE: fs__ftruncate(req, (uv_file)req->arg0, (off_t)req->arg1); break; case UV_FS_SENDFILE: fs__sendfile(req, (uv_file) req->arg0, (uv_file) req->arg1, (off_t) req->arg2, (size_t) req->arg3); break; case UV_FS_CHMOD: fs__chmod(req, req->path, (int)req->arg0); break; case UV_FS_FCHMOD: fs__fchmod(req, (uv_file)req->arg0, (int)req->arg1); break; case UV_FS_UTIME: fs__utime(req, req->path, req->arg4, req->arg5); break; case UV_FS_FUTIME: fs__futime(req, (uv_file)req->arg0, req->arg4, req->arg5); break; case UV_FS_LINK: fs__link(req, req->path, (const char*)req->arg0); break; case UV_FS_SYMLINK: fs__symlink(req, req->path, (const char*)req->arg0, (int)req->arg1); break; case UV_FS_READLINK: fs__readlink(req, req->path); break; case UV_FS_CHOWN: case UV_FS_FCHOWN: fs__nop(req); break; default: assert(!"bad uv_fs_type"); } POST_COMPLETION_FOR_REQ(loop, req); return 0; }
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; }