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_poll(uv_loop_t* loop, DWORD timeout) { DWORD bytes; ULONG_PTR key; OVERLAPPED* overlapped; uv_req_t* req; 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 is reflected in the loop time. */ uv__time_forward(loop, timeout); } }
static void uv_poll(uv_loop_t* loop, int block) { BOOL success; DWORD bytes, timeout; ULONG_PTR key; OVERLAPPED* overlapped; uv_req_t* req; if (block) { timeout = uv_get_poll_timeout(loop); } else { timeout = 0; } success = GetQueuedCompletionStatus(loop->iocp, &bytes, &key, &overlapped, timeout); if (overlapped) { /* Package was dequeued */ req = uv_overlapped_to_req(overlapped); uv_insert_pending_req(loop, req); } else if (GetLastError() != WAIT_TIMEOUT) { /* Serious error */ uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus"); } }
static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) { BOOL success; uv_req_t* req; OVERLAPPED_ENTRY overlappeds[128]; ULONG count; ULONG i; success = pGetQueuedCompletionStatusEx(loop->iocp, overlappeds, ARRAY_SIZE(overlappeds), &count, timeout, FALSE); if (success) { for (i = 0; i < count; i++) { /* Package was dequeued */ 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 is reflected in the loop time. */ uv__time_forward(loop, timeout); } }
int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb, uv_read_cb read_cb) { uv_loop_t* loop = handle->loop; handle->flags |= UV_HANDLE_READING; handle->read_cb = read_cb; handle->alloc_cb = alloc_cb; /* If reading was stopped and then started again, there could stell be a */ /* read request pending. */ if (handle->flags & UV_HANDLE_READ_PENDING) { return 0; } /* Maybe the user stopped reading half-way while processing key events. */ /* Short-circuit if this could be the case. */ if (handle->last_key_len > 0) { SET_REQ_SUCCESS(&handle->read_req); uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req); return -1; } uv_tty_queue_read(loop, handle); return 0; }
static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop, uv_fs_event_t* handle) { assert(handle->dir_handle != INVALID_HANDLE_VALUE); assert(!handle->req_pending); memset(&(handle->req.u.io.overlapped), 0, sizeof(handle->req.u.io.overlapped)); if (!ReadDirectoryChangesW(handle->dir_handle, handle->buffer, uv_directory_watcher_buffer_size, (handle->flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_SECURITY, NULL, &handle->req.u.io.overlapped, NULL)) { /* Make this req pending reporting an error. */ SET_REQ_ERROR(&handle->req, GetLastError()); uv_insert_pending_req(loop, (uv_req_t*)&handle->req); } handle->req_pending = 1; }
static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) { uv_req_t* req; BOOL r; assert(handle->flags & UV_HANDLE_READING); assert(!(handle->flags & UV_HANDLE_READ_PENDING)); assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE); handle->read_line_buffer = uv_null_buf_; req = &handle->read_req; memset(&req->overlapped, 0, sizeof(req->overlapped)); r = RegisterWaitForSingleObject(&handle->read_raw_wait, handle->handle, uv_tty_post_raw_read, (void*) req, INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE); if (!r) { handle->read_raw_wait = NULL; SET_REQ_ERROR(req, GetLastError()); uv_insert_pending_req(loop, req); } handle->flags |= UV_HANDLE_READ_PENDING; handle->reqs_pending++; }
static void uv_poll_ex(uv_loop_t* loop, int block) { BOOL success; DWORD timeout; uv_req_t* req; OVERLAPPED_ENTRY overlappeds[128]; ULONG count; ULONG i; if (block) { timeout = uv_get_poll_timeout(loop); } else { timeout = 0; } assert(pGetQueuedCompletionStatusEx); success = pGetQueuedCompletionStatusEx(loop->iocp, overlappeds, ARRAY_SIZE(overlappeds), &count, timeout, FALSE); if (success) { for (i = 0; i < count; i++) { /* Package was dequeued */ req = uv_overlapped_to_req(overlappeds[i].lpOverlapped); uv_insert_pending_req(loop, req); } } else if (GetLastError() != WAIT_TIMEOUT) { /* Serious error */ uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx"); } }
static void uv_pipe_queue_read(uv_pipe_t* handle) { uv_req_t* req; int result; assert(handle->flags & UV_HANDLE_READING); assert(!(handle->flags & UV_HANDLE_READ_PENDING)); assert(handle->handle != INVALID_HANDLE_VALUE); req = &handle->read_req; memset(&req->overlapped, 0, sizeof(req->overlapped)); /* Do 0-read */ result = ReadFile(handle->handle, &uv_zero_, 0, NULL, &req->overlapped); if (!result && GetLastError() != ERROR_IO_PENDING) { /* Make this req pending reporting an error. */ req->error = uv_new_sys_error(WSAGetLastError()); uv_insert_pending_req(req); handle->reqs_pending++; return; } handle->flags |= UV_HANDLE_READ_PENDING; handle->reqs_pending++; }
static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) { uv_req_t* req; BOOL r; assert(handle->flags & UV_HANDLE_READING); assert(!(handle->flags & UV_HANDLE_READ_PENDING)); assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE); req = &handle->read_req; memset(&req->overlapped, 0, sizeof(req->overlapped)); handle->read_line_buffer = handle->alloc_cb((uv_handle_t*) handle, 8192); assert(handle->read_line_buffer.base != NULL); assert(handle->read_line_buffer.len > 0); /* Duplicate the console handle, so if we want to cancel the read, we can */ /* just close this handle duplicate. */ if (handle->read_line_handle == NULL) { HANDLE this_process = GetCurrentProcess(); r = DuplicateHandle(this_process, handle->handle, this_process, &handle->read_line_handle, 0, 0, DUPLICATE_SAME_ACCESS); if (!r) { handle->read_line_handle = NULL; SET_REQ_ERROR(req, GetLastError()); uv_insert_pending_req(loop, req); goto out; } } r = QueueUserWorkItem(uv_tty_line_read_thread, (void*) req, WT_EXECUTELONGFUNCTION); if (!r) { SET_REQ_ERROR(req, GetLastError()); uv_insert_pending_req(loop, req); } out: handle->flags |= UV_HANDLE_READ_PENDING; handle->reqs_pending++; }
int uv__tcp_connect6(uv_connect_t* req, uv_tcp_t* handle, struct sockaddr_in6 address, uv_connect_cb cb) { uv_loop_t* loop = handle->loop; int addrsize = sizeof(struct sockaddr_in6); BOOL success; DWORD bytes; if (!uv_allow_ipv6) { uv__set_sys_error(loop, WSAEAFNOSUPPORT); return -1; } if (handle->flags & UV_HANDLE_BIND_ERROR) { uv__set_sys_error(loop, handle->bind_error); return -1; } if (!(handle->flags & UV_HANDLE_BOUND) && uv_tcp_bind6(handle, uv_addr_ip6_any_) < 0) return -1; if (!handle->func_connectex) { if(!uv_get_connectex_function(handle->socket, &handle->func_connectex)) { uv__set_sys_error(loop, WSAEAFNOSUPPORT); return -1; } } uv_req_init(loop, (uv_req_t*) req); req->type = UV_CONNECT; req->handle = (uv_stream_t*) handle; req->cb = cb; memset(&req->overlapped, 0, sizeof(req->overlapped)); success = handle->func_connectex(handle->socket, (struct sockaddr*) &address, addrsize, NULL, 0, &bytes, &req->overlapped); if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { handle->reqs_pending++; uv_ref(loop); uv_insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(success)) { handle->reqs_pending++; uv_ref(loop); } else { uv__set_sys_error(loop, WSAGetLastError()); return -1; } return 0; }
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; } }
int uv__tcp_connect(uv_connect_t* req, uv_tcp_t* handle, struct sockaddr_in address, uv_connect_cb cb) { uv_loop_t* loop = handle->loop; int addrsize = sizeof(struct sockaddr_in); BOOL success; DWORD bytes; int err; if (handle->flags & UV_HANDLE_BIND_ERROR) { return handle->bind_error; } if (!(handle->flags & UV_HANDLE_BOUND)) { err = uv_tcp_bind(handle, uv_addr_ip4_any_); if (err) return err; } if (!handle->func_connectex) { if (!uv_get_connectex_function(handle->socket, &handle->func_connectex)) { return WSAEAFNOSUPPORT; } } uv_req_init(loop, (uv_req_t*) req); req->type = UV_CONNECT; req->handle = (uv_stream_t*) handle; req->cb = cb; memset(&req->overlapped, 0, sizeof(req->overlapped)); success = handle->func_connectex(handle->socket, (struct sockaddr*) &address, addrsize, NULL, 0, &bytes, &req->overlapped); if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { /* Process the req without IOCP. */ handle->reqs_pending++; 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++; REGISTER_HANDLE_REQ(loop, handle, req); } else { return WSAGetLastError(); } return 0; }
static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) { uv_req_t* req; uv_buf_t buf; DWORD bytes, flags; int result; assert(handle->flags & UV_HANDLE_READING); assert(!(handle->flags & UV_HANDLE_READ_PENDING)); req = &handle->recv_req; memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); handle->flags |= UV_HANDLE_ZERO_READ; buf.base = ""; buf.len = 0; flags = MSG_PEEK; result = handle->func_wsarecv(handle->socket, (WSABUF*) &buf, 1, &bytes, &flags, &req->u.io.overlapped, NULL); if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { /* Process the req without IOCP. */ handle->flags |= UV_HANDLE_READ_PENDING; req->u.io.overlapped.InternalHigh = bytes; handle->reqs_pending++; uv_insert_pending_req(loop, req); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* The req will be processed with IOCP. */ handle->flags |= UV_HANDLE_READ_PENDING; handle->reqs_pending++; } else { /* Make this req pending reporting an error. */ SET_REQ_ERROR(req, WSAGetLastError()); uv_insert_pending_req(loop, req); handle->reqs_pending++; } }
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); return; } /* 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->u.io.overlapped, 0, sizeof req->u.io.overlapped); result = uv_msafd_poll((SOCKET) handle->peer_socket, afd_poll_info, afd_poll_info, &req->u.io.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); } }
int uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle, struct sockaddr_in6 address, uv_connect_cb cb) { int addrsize = sizeof(struct sockaddr_in6); BOOL success; DWORD bytes; if (!uv_allow_ipv6) { uv_new_sys_error(WSAEAFNOSUPPORT); return -1; } if (handle->flags & UV_HANDLE_BIND_ERROR) { LOOP->last_error = handle->error; return -1; } if (address.sin6_family != AF_INET6) { uv_set_sys_error(WSAEFAULT); return -1; } if (!(handle->flags & UV_HANDLE_BOUND) && uv_tcp_bind6(handle, uv_addr_ip6_any_) < 0) return -1; uv_req_init((uv_req_t*) req); req->type = UV_CONNECT; req->handle = (uv_stream_t*) handle; req->cb = cb; memset(&req->overlapped, 0, sizeof(req->overlapped)); success = pConnectEx6(handle->socket, (struct sockaddr*) &address, addrsize, NULL, 0, &bytes, &req->overlapped); if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { handle->reqs_pending++; uv_insert_pending_req((uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(success)) { handle->reqs_pending++; } else { uv_set_sys_error(WSAGetLastError()); return -1; } return 0; }
void uv_run_postwork(uv_run_state* state) { if (state->count > 0) { uv_req_t* req; ULONG i; for (i = 0; i < state->count; i++) { // Package was dequeued req = uv_overlapped_to_req(state->overlappeds[i].lpOverlapped); uv_insert_pending_req(state->loop, req); } } uv_check_invoke(state->loop); }
int uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle, struct sockaddr_in address, uv_connect_cb cb) { uv_loop_t* loop = handle->loop; int addrsize = sizeof(struct sockaddr_in); BOOL success; DWORD bytes; if (handle->flags & UV_HANDLE_BIND_ERROR) { loop->last_error = handle->bind_error; return -1; } if (address.sin_family != AF_INET) { uv_set_sys_error(loop, WSAEFAULT); return -1; } if (!(handle->flags & UV_HANDLE_BOUND) && uv_tcp_bind(handle, uv_addr_ip4_any_) < 0) return -1; uv_req_init(loop, (uv_req_t*) req); req->type = UV_CONNECT; req->handle = (uv_stream_t*) handle; req->cb = cb; memset(&req->overlapped, 0, sizeof(req->overlapped)); success = pConnectEx(handle->socket, (struct sockaddr*) &address, addrsize, NULL, 0, &bytes, &req->overlapped); if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { /* Process the req without IOCP. */ handle->reqs_pending++; 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++; } else { uv_set_sys_error(loop, WSAGetLastError()); return -1; } return 0; }
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; } }
int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle, uv_buf_t bufs[], int bufcnt, uv_write_cb cb) { int result; DWORD bytes; if (!(handle->flags & UV_HANDLE_CONNECTION)) { uv__set_sys_error(loop, WSAEINVAL); return -1; } if (handle->flags & UV_HANDLE_SHUTTING) { uv__set_sys_error(loop, WSAESHUTDOWN); return -1; } uv_req_init(loop, (uv_req_t*) req); req->type = UV_WRITE; req->handle = (uv_stream_t*) handle; req->cb = cb; memset(&req->overlapped, 0, sizeof(req->overlapped)); result = WSASend(handle->socket, (WSABUF*)bufs, bufcnt, &bytes, 0, &req->overlapped, NULL); if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { /* Request completed immediately. */ req->queued_bytes = 0; handle->reqs_pending++; handle->write_reqs_pending++; 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++; handle->write_reqs_pending++; handle->write_queue_size += req->queued_bytes; } else { /* Send failed due to an error. */ uv__set_sys_error(loop, WSAGetLastError()); return -1; } return 0; }
static int uv__send(uv_udp_send_t* req, uv_udp_t* handle, const uv_buf_t bufs[], unsigned int nbufs, const struct sockaddr* addr, unsigned int addrlen, uv_udp_send_cb cb) { uv_loop_t* loop = handle->loop; DWORD result, bytes; uv_req_init(loop, (uv_req_t*) req); req->type = UV_UDP_SEND; req->handle = handle; req->cb = cb; memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); result = WSASendTo(handle->socket, (WSABUF*)bufs, nbufs, &bytes, 0, addr, addrlen, &req->u.io.overlapped, NULL); if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { /* Request completed immediately. */ req->u.io.queued_bytes = 0; handle->reqs_pending++; handle->send_queue_size += req->u.io.queued_bytes; handle->send_queue_count++; REGISTER_HANDLE_REQ(loop, handle, req); uv_insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* Request queued by the kernel. */ req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs); handle->reqs_pending++; handle->send_queue_size += req->u.io.queued_bytes; handle->send_queue_count++; REGISTER_HANDLE_REQ(loop, handle, req); } else { /* Send failed due to an error. */ return WSAGetLastError(); } return 0; }
static int uv__udp_send(uv_udp_send_t* req, uv_udp_t* handle, uv_buf_t bufs[], int bufcnt, struct sockaddr* addr, int addr_len, uv_udp_send_cb cb) { uv_loop_t* loop = handle->loop; DWORD result, bytes; uv_req_init(loop, (uv_req_t*) req); req->type = UV_UDP_SEND; req->handle = handle; req->cb = cb; memset(&req->overlapped, 0, sizeof(req->overlapped)); result = WSASendTo(handle->socket, (WSABUF*)bufs, bufcnt, &bytes, 0, addr, addr_len, &req->overlapped, NULL); if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { /* Request completed immediately. */ req->queued_bytes = 0; handle->reqs_pending++; uv_ref(loop); uv_insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* Request queued by the kernel. */ req->queued_bytes = uv_count_bufs(bufs, bufcnt); handle->reqs_pending++; uv_ref(loop); } else { /* Send failed due to an error. */ uv__set_sys_error(loop, WSAGetLastError()); return -1; } return 0; }
static void uv_poll_ex(int block) { BOOL success; DWORD timeout; uv_req_t* req; OVERLAPPED_ENTRY overlappeds[64]; ULONG count; ULONG i; if (block) { timeout = uv_get_poll_timeout(); } else { timeout = 0; } assert(pGetQueuedCompletionStatusEx); success = pGetQueuedCompletionStatusEx(LOOP->iocp, overlappeds, COUNTOF(overlappeds), &count, timeout, FALSE); if (success) { for (i = 0; i < count; i++) { /* Package was dequeued */ req = uv_overlapped_to_req(overlappeds[i].lpOverlapped); if (overlappeds[i].lpOverlapped->Internal != STATUS_SUCCESS) { req->error = uv_new_sys_error(pRtlNtStatusToDosError( overlappeds[i].lpOverlapped->Internal)); } uv_insert_pending_req(req); } } else if (GetLastError() != WAIT_TIMEOUT) { /* Serious error */ uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx"); } }
static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) { uv_req_t* req; uv_buf_t buf; DWORD bytes, flags; int result; assert(handle->flags & UV_HANDLE_READING); assert(!(handle->flags & UV_HANDLE_READ_PENDING)); req = &handle->recv_req; memset(&req->overlapped, 0, sizeof(req->overlapped)); /* * Preallocate a read buffer if the number of active streams is below * the threshold. */ if (loop->active_udp_streams < uv_active_udp_streams_threshold) { handle->flags &= ~UV_HANDLE_ZERO_READ; handle->recv_buffer = handle->alloc_cb((uv_handle_t*) handle, 65536); assert(handle->recv_buffer.len > 0); buf = handle->recv_buffer; memset(&handle->recv_from, 0, sizeof handle->recv_from); handle->recv_from_len = sizeof handle->recv_from; flags = 0; result = handle->func_wsarecvfrom(handle->socket, (WSABUF*) &buf, 1, &bytes, &flags, (struct sockaddr*) &handle->recv_from, &handle->recv_from_len, &req->overlapped, NULL); if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { /* Process the req without IOCP. */ handle->flags |= UV_HANDLE_READ_PENDING; req->overlapped.InternalHigh = bytes; handle->reqs_pending++; uv_insert_pending_req(loop, req); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* The req will be processed with IOCP. */ handle->flags |= UV_HANDLE_READ_PENDING; handle->reqs_pending++; } else { /* Make this req pending reporting an error. */ SET_REQ_ERROR(req, WSAGetLastError()); uv_insert_pending_req(loop, req); handle->reqs_pending++; } } else { handle->flags |= UV_HANDLE_ZERO_READ; buf.base = (char*) uv_zero_; buf.len = 0; flags = MSG_PEEK; result = handle->func_wsarecv(handle->socket, (WSABUF*) &buf, 1, &bytes, &flags, &req->overlapped, NULL); if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { /* Process the req without IOCP. */ handle->flags |= UV_HANDLE_READ_PENDING; req->overlapped.InternalHigh = bytes; handle->reqs_pending++; uv_insert_pending_req(loop, req); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* The req will be processed with IOCP. */ handle->flags |= UV_HANDLE_READ_PENDING; handle->reqs_pending++; } else { /* Make this req pending reporting an error. */ SET_REQ_ERROR(req, WSAGetLastError()); uv_insert_pending_req(loop, req); handle->reqs_pending++; } } }
int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle, const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb) { int result; DWORD bytes; uv_req_init(loop, (uv_req_t*) req); req->type = UV_WRITE; req->handle = (uv_stream_t*) handle; req->cb = cb; /* Prepare the overlapped structure. */ memset(&(req->overlapped), 0, sizeof(req->overlapped)); if (handle->flags & UV_HANDLE_EMULATE_IOCP) { req->event_handle = CreateEvent(NULL, 0, 0, NULL); if (!req->event_handle) { uv_fatal_error(GetLastError(), "CreateEvent"); } req->overlapped.hEvent = (HANDLE) ((DWORD) req->event_handle | 1); req->wait_handle = INVALID_HANDLE_VALUE; } result = WSASend(handle->socket, (WSABUF*) bufs, nbufs, &bytes, 0, &req->overlapped, NULL); if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { /* Request completed immediately. */ 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); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* Request queued by the kernel. */ req->queued_bytes = uv__count_bufs(bufs, nbufs); handle->reqs_pending++; handle->write_reqs_pending++; REGISTER_HANDLE_REQ(loop, handle, req); handle->write_queue_size += req->queued_bytes; if (handle->flags & UV_HANDLE_EMULATE_IOCP && !pRegisterWaitForSingleObject(&req->wait_handle, req->event_handle, post_write_completion, (void*) req, INFINITE, WT_EXECUTEINWAITTHREAD | 0x00000008/*WT_EXECUTEONLYONCE*/)) { SET_REQ_ERROR(req, GetLastError()); uv_insert_pending_req(loop, (uv_req_t*)req); } } else { /* Send failed due to an error. */ return WSAGetLastError(); } return 0; }
static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) { uv_read_t* req; uv_buf_t buf; int result; DWORD bytes, flags; assert(handle->flags & UV_HANDLE_READING); assert(!(handle->flags & UV_HANDLE_READ_PENDING)); req = &handle->read_req; memset(&req->overlapped, 0, sizeof(req->overlapped)); /* * Preallocate a read buffer if the number of active streams is below * the threshold. */ if (loop->active_tcp_streams < uv_active_tcp_streams_threshold) { handle->flags &= ~UV_HANDLE_ZERO_READ; handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->read_buffer); if (handle->read_buffer.len == 0) { handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &handle->read_buffer); return; } assert(handle->read_buffer.base != NULL); buf = handle->read_buffer; } else { handle->flags |= UV_HANDLE_ZERO_READ; buf.base = (char*) &uv_zero_; buf.len = 0; } /* Prepare the overlapped structure. */ memset(&(req->overlapped), 0, sizeof(req->overlapped)); if (handle->flags & UV_HANDLE_EMULATE_IOCP) { assert(req->event_handle); req->overlapped.hEvent = (HANDLE) ((DWORD) req->event_handle | 1); } flags = 0; result = WSARecv(handle->socket, (WSABUF*)&buf, 1, &bytes, &flags, &req->overlapped, NULL); if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) { /* Process the req without IOCP. */ handle->flags |= UV_HANDLE_READ_PENDING; req->overlapped.InternalHigh = bytes; handle->reqs_pending++; uv_insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) { /* The req will be processed with IOCP. */ handle->flags |= UV_HANDLE_READ_PENDING; handle->reqs_pending++; if (handle->flags & UV_HANDLE_EMULATE_IOCP && req->wait_handle == INVALID_HANDLE_VALUE && !pRegisterWaitForSingleObject(&req->wait_handle, req->event_handle, post_completion, (void*) req, INFINITE, WT_EXECUTEINWAITTHREAD)) { SET_REQ_ERROR(req, GetLastError()); uv_insert_pending_req(loop, (uv_req_t*)req); } } else { /* Make this req pending reporting an error. */ SET_REQ_ERROR(req, WSAGetLastError()); uv_insert_pending_req(loop, (uv_req_t*)req); handle->reqs_pending++; } }
static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { uv_loop_t* loop = handle->loop; BOOL success; DWORD bytes; SOCKET accept_socket; short family; assert(handle->flags & UV_HANDLE_LISTENING); assert(req->accept_socket == INVALID_SOCKET); /* choose family and extension function */ if (handle->flags & UV_HANDLE_IPV6) { family = AF_INET6; } else { family = AF_INET; } /* Open a socket for the accepted connection. */ accept_socket = socket(family, SOCK_STREAM, 0); if (accept_socket == INVALID_SOCKET) { SET_REQ_ERROR(req, WSAGetLastError()); uv_insert_pending_req(loop, (uv_req_t*)req); handle->reqs_pending++; return; } /* Make the socket non-inheritable */ if (!SetHandleInformation((HANDLE) accept_socket, HANDLE_FLAG_INHERIT, 0)) { SET_REQ_ERROR(req, GetLastError()); uv_insert_pending_req(loop, (uv_req_t*)req); handle->reqs_pending++; closesocket(accept_socket); return; } /* Prepare the overlapped structure. */ memset(&(req->overlapped), 0, sizeof(req->overlapped)); if (handle->flags & UV_HANDLE_EMULATE_IOCP) { req->overlapped.hEvent = (HANDLE) ((DWORD) req->event_handle | 1); } success = handle->func_acceptex(handle->socket, accept_socket, (void*)req->accept_buffer, 0, sizeof(struct sockaddr_storage), sizeof(struct sockaddr_storage), &bytes, &req->overlapped); if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { /* Process the req without IOCP. */ req->accept_socket = accept_socket; handle->reqs_pending++; uv_insert_pending_req(loop, (uv_req_t*)req); } else if (UV_SUCCEEDED_WITH_IOCP(success)) { /* The req will be processed with IOCP. */ req->accept_socket = accept_socket; handle->reqs_pending++; if (handle->flags & UV_HANDLE_EMULATE_IOCP && req->wait_handle == INVALID_HANDLE_VALUE && !pRegisterWaitForSingleObject(&req->wait_handle, req->event_handle, post_completion, (void*) req, INFINITE, WT_EXECUTEINWAITTHREAD)) { SET_REQ_ERROR(req, GetLastError()); uv_insert_pending_req(loop, (uv_req_t*)req); handle->reqs_pending++; return; } } else { /* Make this req pending reporting an error. */ SET_REQ_ERROR(req, WSAGetLastError()); uv_insert_pending_req(loop, (uv_req_t*)req); handle->reqs_pending++; /* Destroy the preallocated client socket. */ closesocket(accept_socket); /* Destroy the event handle */ if (handle->flags & UV_HANDLE_EMULATE_IOCP) { CloseHandle(req->overlapped.hEvent); req->event_handle = NULL; } } }
int uv_spawn(uv_loop_t* loop, uv_process_t* process, uv_process_options_t options) { int i; uv_err_t err = uv_ok_; WCHAR* path = NULL; BOOL result; WCHAR* application_path = NULL, *application = NULL, *arguments = NULL, *env = NULL, *cwd = NULL; STARTUPINFOW startup; PROCESS_INFORMATION info; DWORD process_flags; if (options.flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) { uv__set_artificial_error(loop, UV_ENOTSUP); return -1; } if (options.file == NULL || options.args == NULL) { uv__set_artificial_error(loop, UV_EINVAL); return -1; } assert(options.file != NULL); assert(!(options.flags & ~(UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS | UV_PROCESS_DETACHED | UV_PROCESS_SETGID | UV_PROCESS_SETUID))); uv_process_init(loop, process); process->exit_cb = options.exit_cb; err = uv_utf8_to_utf16_alloc(options.file, &application); if (err.code != UV_OK) goto done; err = make_program_args(options.args, options.flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS, &arguments); if (err.code != UV_OK) goto done; if (options.cwd) { /* Explicit cwd */ err = uv_utf8_to_utf16_alloc(options.cwd, &cwd); if (err.code != UV_OK) goto done; } else { /* Inherit cwd */ DWORD cwd_len, r; cwd_len = GetCurrentDirectoryW(0, NULL); if (!cwd_len) { err = uv__new_sys_error(GetLastError()); goto done; } cwd = (WCHAR*) malloc(cwd_len * sizeof(WCHAR)); if (cwd == NULL) { err = uv__new_artificial_error(UV_ENOMEM); goto done; } r = GetCurrentDirectoryW(cwd_len, cwd); if (r == 0 || r >= cwd_len) { err = uv__new_sys_error(GetLastError()); goto done; } } /* Get PATH environment variable. */ { DWORD path_len, r; path_len = GetEnvironmentVariableW(L"PATH", NULL, 0); if (path_len == 0) { err = uv__new_sys_error(GetLastError()); goto done; } path = (WCHAR*) malloc(path_len * sizeof(WCHAR)); if (path == NULL) { err = uv__new_artificial_error(UV_ENOMEM); goto done; } r = GetEnvironmentVariableW(L"PATH", path, path_len); if (r == 0 || r >= path_len) { err = uv__new_sys_error(GetLastError()); goto done; } } application_path = search_path(application, cwd, path); if (application_path == NULL) { /* Not found. */ err = uv__new_artificial_error(UV_ENOENT); goto done; } err = uv__stdio_create(loop, &options, &process->child_stdio_buffer); if (err.code != UV_OK) goto done; startup.cb = sizeof(startup); startup.lpReserved = NULL; startup.lpDesktop = NULL; startup.lpTitle = NULL; startup.dwFlags = STARTF_USESTDHANDLES; startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer); startup.lpReserved2 = (BYTE*) process->child_stdio_buffer; startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0); startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1); startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2); process_flags = CREATE_UNICODE_ENVIRONMENT; if (options.flags & UV_PROCESS_DETACHED) { process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP; } if (CreateProcessW(application_path, arguments, NULL, NULL, 1, process_flags, env, cwd, &startup, &info)) { /* Spawn succeeded */ process->process_handle = info.hProcess; process->pid = info.dwProcessId; /* Set IPC pid to all IPC pipes. */ for (i = 0; i < options.stdio_count; i++) { const uv_stdio_container_t* fdopt = &options.stdio[i]; if (fdopt->flags & UV_CREATE_PIPE && fdopt->data.stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) fdopt->data.stream)->ipc) { ((uv_pipe_t*) fdopt->data.stream)->ipc_pid = info.dwProcessId; } } /* Setup notifications for when the child process exits. */ result = RegisterWaitForSingleObject(&process->wait_handle, process->process_handle, exit_wait_callback, (void*)process, INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE); if (!result) { uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject"); } CloseHandle(info.hThread); } else { /* CreateProcessW failed. */ err = uv__new_sys_error(GetLastError()); } done: free(application); free(application_path); free(arguments); free(cwd); free(env); free(path); process->spawn_error = err; if (process->child_stdio_buffer != NULL) { /* Clean up child stdio handles. */ uv__stdio_destroy(process->child_stdio_buffer); process->child_stdio_buffer = NULL; } /* Make the handle active. It will remain active until the exit callback */ /* is made or the handle is closed, whichever happens first. */ uv__handle_start(process); /* If an error happened, queue the exit req. */ if (err.code != UV_OK) { process->exit_cb_pending = 1; uv_insert_pending_req(loop, (uv_req_t*) &process->exit_req); } return 0; }
static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) { uv_read_t* req; int result; assert(handle->flags & UV_HANDLE_READING); assert(!(handle->flags & UV_HANDLE_READ_PENDING)); assert(handle->handle != INVALID_HANDLE_VALUE); req = &handle->read_req; if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) { if (!QueueUserWorkItem(&uv_pipe_zero_readfile_thread_proc, req, WT_EXECUTELONGFUNCTION)) { /* Make this req pending reporting an error. */ SET_REQ_ERROR(req, GetLastError()); goto error; } } else { memset(&req->overlapped, 0, sizeof(req->overlapped)); if (handle->flags & UV_HANDLE_EMULATE_IOCP) { req->overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1); } /* Do 0-read */ result = ReadFile(handle->handle, &uv_zero_, 0, NULL, &req->overlapped); if (!result && GetLastError() != ERROR_IO_PENDING) { /* Make this req pending reporting an error. */ SET_REQ_ERROR(req, GetLastError()); goto error; } if (handle->flags & UV_HANDLE_EMULATE_IOCP) { if (!req->event_handle) { req->event_handle = CreateEvent(NULL, 0, 0, NULL); if (!req->event_handle) { uv_fatal_error(GetLastError(), "CreateEvent"); } } if (req->wait_handle == INVALID_HANDLE_VALUE) { if (!RegisterWaitForSingleObject(&req->wait_handle, req->overlapped.hEvent, post_completion_read_wait, (void*) req, INFINITE, WT_EXECUTEINWAITTHREAD)) { SET_REQ_ERROR(req, GetLastError()); goto error; } } } } /* Start the eof timer if there is one */ eof_timer_start(handle); handle->flags |= UV_HANDLE_READ_PENDING; handle->reqs_pending++; return; error: uv_insert_pending_req(loop, (uv_req_t*)req); handle->flags |= UV_HANDLE_READ_PENDING; handle->reqs_pending++; }
void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle, const char* name, uv_connect_cb cb) { uv_loop_t* loop = handle->loop; int errorno, nameSize; HANDLE pipeHandle = INVALID_HANDLE_VALUE; DWORD duplex_flags; uv_req_init(loop, (uv_req_t*) req); req->type = UV_CONNECT; req->handle = (uv_stream_t*) handle; req->cb = cb; /* Convert name to UTF16. */ nameSize = uv_utf8_to_utf16(name, NULL, 0) * sizeof(WCHAR); handle->name = (WCHAR*)malloc(nameSize); if (!handle->name) { uv_fatal_error(ERROR_OUTOFMEMORY, "malloc"); } if (!uv_utf8_to_utf16(name, handle->name, nameSize / sizeof(WCHAR))) { errorno = GetLastError(); goto error; } pipeHandle = open_named_pipe(handle->name, &duplex_flags); if (pipeHandle == INVALID_HANDLE_VALUE) { if (GetLastError() == ERROR_PIPE_BUSY) { /* Wait for the server to make a pipe instance available. */ if (!QueueUserWorkItem(&pipe_connect_thread_proc, req, WT_EXECUTELONGFUNCTION)) { errorno = GetLastError(); goto error; } REGISTER_HANDLE_REQ(loop, handle, req); handle->reqs_pending++; return; } errorno = GetLastError(); goto error; } assert(pipeHandle != INVALID_HANDLE_VALUE); if (uv_set_pipe_handle(loop, (uv_pipe_t*) req->handle, pipeHandle, duplex_flags)) { errorno = GetLastError(); goto error; } SET_REQ_SUCCESS(req); uv_insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; REGISTER_HANDLE_REQ(loop, handle, req); return; error: if (handle->name) { free(handle->name); handle->name = NULL; } if (pipeHandle != INVALID_HANDLE_VALUE) { CloseHandle(pipeHandle); } /* Make this req pending reporting an error. */ SET_REQ_ERROR(req, errorno); uv_insert_pending_req(loop, (uv_req_t*) req); handle->reqs_pending++; REGISTER_HANDLE_REQ(loop, handle, req); return; }