static int port__poll(port_state_t* port_state, struct epoll_event* epoll_events, OVERLAPPED_ENTRY* iocp_events, DWORD maxevents, DWORD timeout) { DWORD completion_count; if (port__update_events(port_state) < 0) return -1; port_state->active_poll_count++; LeaveCriticalSection(&port_state->lock); BOOL r = GetQueuedCompletionStatusEx(port_state->iocp, iocp_events, maxevents, &completion_count, timeout, FALSE); EnterCriticalSection(&port_state->lock); port_state->active_poll_count--; if (!r) return_map_error(-1); return port__feed_events( port_state, epoll_events, iocp_events, completion_count); }
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; } }
void Dispatcher::yield() { assert(GetCurrentThreadId() == threadId); for (;;) { LARGE_INTEGER frequency; LARGE_INTEGER ticks; QueryPerformanceCounter(&ticks); QueryPerformanceFrequency(&frequency); uint64_t currentTime = ticks.QuadPart / (frequency.QuadPart / 1000); auto timerContextPair = timers.begin(); auto end = timers.end(); while (timerContextPair != end && timerContextPair->first <= currentTime) { timerContextPair->second->interruptProcedure = nullptr; pushContext(timerContextPair->second); timerContextPair = timers.erase(timerContextPair); } OVERLAPPED_ENTRY entries[16]; ULONG actual = 0; if (GetQueuedCompletionStatusEx(completionPort, entries, 16, &actual, 0, TRUE) == TRUE) { assert(actual > 0); for (ULONG i = 0; i < actual; ++i) { if (entries[i].lpOverlapped == reinterpret_cast<LPOVERLAPPED>(remoteSpawnOverlapped)) { EnterCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(criticalSection)); assert(remoteNotificationSent); assert(!remoteSpawningProcedures.empty()); do { spawn(std::move(remoteSpawningProcedures.front())); remoteSpawningProcedures.pop(); } while (!remoteSpawningProcedures.empty()); remoteNotificationSent = false; LeaveCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(criticalSection)); continue; } NativeContext* context = reinterpret_cast<DispatcherContext*>(entries[i].lpOverlapped)->context; context->interruptProcedure = nullptr; pushContext(context); } } else { DWORD lastError = GetLastError(); if (lastError == WAIT_TIMEOUT) { break; } else if (lastError != WAIT_IO_COMPLETION) { throw std::runtime_error("Dispatcher::yield, GetQueuedCompletionStatusEx failed, " + errorMessage(lastError)); } } } if (firstResumingContext != nullptr) { pushContext(currentContext); dispatch(); } }
void worker_thread_impl::loop( ) { ++data.number_threads; try { this_wthread = (thr_queue::worker_thread*) ( this ); coroutine master_cor; global_thread_pool::after_yield_f after_yield_f; master_coroutine = &master_cor; after_yield = &after_yield_f; OVERLAPPED_ENTRY olapped_entry; auto wait_cond = [&] { while ( true ) { auto wait_time = data.shutting_down ? 0 : INFINITE; ULONG removed_entries; auto wait_iocp = GetQueuedCompletionStatusEx( data.iocp, &olapped_entry, 1, &removed_entries, wait_time, true ); if ( !wait_iocp ) { auto err = GetLastError( ); if ( err == WAIT_IO_COMPLETION ) { continue; } else { if ( err != WAIT_TIMEOUT ) { LOG( ) << "GetQueuedCompletionStatus: " << err; } return false; } } else { break; } } return true; }; do { if ( olapped_entry.lpCompletionKey != data.queue_completionkey ) { handle_io_operation( olapped_entry ); } else { do_work( ); } } while ( wait_cond( ) ); } catch ( std::exception& e ) { LOG( ) << "caught when worker thread was stopping: " << e.what( ); } --data.number_threads; get_internals( ).stopped = true; }
int SelEpolKqEvPrt::getEvents() { int numEvents = -1; #if defined(USE_WIN_IOCP) #ifdef OS_MINGW_W64 IOOverlappedEntry entries[64]; ULONG nEvents = 0; if(!GetQueuedCompletionStatusEx(iocpPort, (OVERLAPPED_ENTRY*)entries, 64, &nEvents, (DWORD)this->timeoutMilis, FALSE)) { int errCd = WSAGetLastError(); if(errCd != WAIT_TIMEOUT) { std::cout << "Error occurred during GetQueuedCompletionStatusEx " << WSAGetLastError() << std::endl; } return -1; } psocks.clear(); for(long i = 0; i < (long)nEvents; i++) { DWORD qty; DWORD flags; if(WSAGetOverlappedResult(entries[i].o->sock, (LPWSAOVERLAPPED)entries[i].o, &qty, FALSE, &flags)) { psocks.push_back(entries[i].o); } } return (int)psocks.size(); #else OVERLAPPED *pOverlapped = NULL; IOOperation *lpContext = NULL; DWORD dwBytesTransfered = 0; BOOL bReturn = GetQueuedCompletionStatus(iocpPort, &dwBytesTransfered, (LPDWORD)&lpContext, &pOverlapped, (DWORD)this->timeoutMilis); if (FALSE == bReturn) { return -1; } IOOperation* iops = (IOOperation*)lpContext; psocks.clear(); psocks.push_back(iops); return 1; #endif #elif defined(USE_MINGW_SELECT) readfds = master; if(timeoutMilis>1) { struct timeval tv; tv.tv_sec = (timeoutMilis/1000); tv.tv_usec = (timeoutMilis%1000)*1000; numEvents = select(fdMax+1, &readfds, NULL, NULL, &tv); } else { numEvents = select(fdMax+1, &readfds, NULL, NULL, NULL); } if(numEvents==-1) { perror("select()"); } else { if(fdMax>0) return fdMax+1; } #elif defined(USE_SELECT) for (int var = 0; var < fdsetSize; ++var) { readfds[var] = master[var]; } if(timeoutMilis>1) { struct timeval tv; tv.tv_sec = (timeoutMilis/1000); tv.tv_usec = (timeoutMilis%1000)*1000; numEvents = select(fdMax+1, readfds, NULL, NULL, &tv); } else { numEvents = select(fdMax+1, readfds, NULL, NULL, NULL); } if(numEvents==-1) { perror("select()"); } else { if(fdMax>0) return fdMax+1; } #elif defined USE_EPOLL int ccfds = curfds; if(curfds<=0) { ccfds = 1; } numEvents = epoll_wait(epoll_handle, events, ccfds+1, timeoutMilis); #elif defined USE_KQUEUE if(timeoutMilis>1) { struct timespec tv; tv.tv_sec = (timeoutMilis/1000); tv.tv_nsec = (timeoutMilis%1000)*1000000; numEvents = kevent(kq, NULL, 0, evlist, MAXDESCRIPTORS, &tv); } else { numEvents = kevent(kq, NULL, 0, evlist, MAXDESCRIPTORS, NULL); } #elif defined USE_DEVPOLL struct dvpoll pollit; pollit.dp_timeout = timeoutMilis; pollit.dp_nfds = curfds; pollit.dp_fds = polled_fds; numEvents = ioctl(dev_poll_fd, DP_POLL, &pollit); #elif defined USE_EVPORT uint_t nevents, wevents = 0; if(timeoutMilis>1) { struct timespec tv tv.tv_sec = (timeoutMilis/1000); tv.tv_nsec = (timeoutMilis%1000)*1000000; //uint_t num = 0; if (port_getn(port, evlist, 0, &wevents, &tv) < 0) return 0; if (0 == wevents) wevents = 1; nevents = wevents; if (port_getn(port, evlist, (uint_t) MAXDESCRIPTORS, &nevents, &tv) < 0) return 0; } else { //uint_t num = 0; if (port_getn(port, evlist, 0, &wevents, NULL) < 0) return 0;
void Dispatcher::dispatch() { assert(GetCurrentThreadId() == threadId); NativeContext* context; for (;;) { if (firstResumingContext != nullptr) { context = firstResumingContext; firstResumingContext = context->next; assert(context->inExecutionQueue); context->inExecutionQueue = false; break; } LARGE_INTEGER frequency; LARGE_INTEGER ticks; QueryPerformanceCounter(&ticks); QueryPerformanceFrequency(&frequency); uint64_t currentTime = ticks.QuadPart / (frequency.QuadPart / 1000); auto timerContextPair = timers.begin(); auto end = timers.end(); while (timerContextPair != end && timerContextPair->first <= currentTime) { pushContext(timerContextPair->second); timerContextPair = timers.erase(timerContextPair); } if (firstResumingContext != nullptr) { context = firstResumingContext; firstResumingContext = context->next; assert(context->inExecutionQueue); context->inExecutionQueue = false; break; } DWORD timeout = timers.empty() ? INFINITE : static_cast<DWORD>(std::min(timers.begin()->first - currentTime, static_cast<uint64_t>(INFINITE - 1))); OVERLAPPED_ENTRY entry; ULONG actual = 0; if (GetQueuedCompletionStatusEx(completionPort, &entry, 1, &actual, timeout, TRUE) == TRUE) { if (entry.lpOverlapped == reinterpret_cast<LPOVERLAPPED>(remoteSpawnOverlapped)) { EnterCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(criticalSection)); assert(remoteNotificationSent); assert(!remoteSpawningProcedures.empty()); do { spawn(std::move(remoteSpawningProcedures.front())); remoteSpawningProcedures.pop(); } while (!remoteSpawningProcedures.empty()); remoteNotificationSent = false; LeaveCriticalSection(reinterpret_cast<LPCRITICAL_SECTION>(criticalSection)); continue; } context = reinterpret_cast<DispatcherContext*>(entry.lpOverlapped)->context; break; } DWORD lastError = GetLastError(); if (lastError == WAIT_TIMEOUT) { continue; } if (lastError != WAIT_IO_COMPLETION) { throw std::runtime_error("Dispatcher::dispatch, GetQueuedCompletionStatusEx failed, " + errorMessage(lastError)); } } if (context != currentContext) { currentContext = context; SwitchToFiber(context->fiber); } }
NET_API int net_wait(struct net_service* service, int timeout) { int ret; int err; struct iocp_data* ov_data; PULONG_PTR data; DWORD bytes; int cnt; #if _WIN32_WINNT >= 0x0600 ULONG ulCount; ULONG ulNR; ULONG i; OVERLAPPED_ENTRY entries[32]; cnt = 0; ulCount = sizeof(entries) / sizeof(OVERLAPPED_ENTRY); ulNR = 0; ov_data = 0; data = 0; bytes = 0; err = 0; while(1) { ret = GetQueuedCompletionStatusEx(service->net_service_fd, entries, ulCount, &ulNR, timeout, 0); err = net_get_error(); if (err == WAIT_TIMEOUT) { err = 0; } if (!ret) { if (err) { return -err; } return cnt; } for (i = 0; i < ulNR; ++i) { ov_data = (struct iocp_data*)entries[i].lpOverlapped; bytes = entries[i].dwNumberOfBytesTransferred; if (ov_data) { switch(ov_data->op_type) { case OP_NET_ACCEPT: handle_accept(service, ret, err, (struct accept_session*)ov_data); break; case OP_NET_READ: handle_read(service, ret, err, (struct read_session*)ov_data, bytes); break; case OP_NET_WRITE: handle_write(service, ret, err, (struct write_session*)ov_data, bytes); break; case OP_NET_CONNECT: handle_connect(service, ret, err, (struct connect_session *)ov_data, bytes); break; } } } cnt += (int)ulNR; } return cnt; #else cnt = 0; while(1) { ret = GetQueuedCompletionStatus(service->net_service_fd, &bytes, (PULONG_PTR) &data, (LPOVERLAPPED*)&ov_data, timeout); err = 0; if (!ret) { err = net_get_error(); } if (err == WAIT_TIMEOUT) { err = 0; } if(!ov_data) { if(err) { return -err; } return cnt; } else { switch(ov_data->op_type) { case OP_NET_ACCEPT: handle_accept(service, ret, err, (struct accept_session*)ov_data); break; case OP_NET_READ: handle_read(service, ret, err, (struct read_session*)ov_data, bytes); break; case OP_NET_WRITE: handle_write(service, ret, err, (struct write_session*)ov_data, bytes); break; case OP_NET_CONNECT: handle_connect(service, ret, err, (struct connect_session *)ov_data, bytes); break; } } cnt += 1; } return cnt; #endif }