void io_looper::loop_worker() { DWORD io_size; uintptr_t completion_key; LPOVERLAPPED lolp; DWORD error; while (true) { BOOL r = ::GetQueuedCompletionStatus(_io_queue, &io_size, &completion_key, &lolp, 1); // 1ms timeout for timers // everything goes fine if (r) { error = ERROR_SUCCESS; } // failed or timeout else { error = ::GetLastError(); if (error == ERROR_ABANDONED_WAIT_0) { derror("completion port loop exits"); break; } // only possible for timeout if (NULL == lolp) { handle_local_queues(); continue; } dinfo("io operation failed in iocp, err = 0x%x", error); } if (NON_IO_TASK_NOTIFICATION_KEY == completion_key) { handle_local_queues(); } else { io_loop_callback* cb = (io_loop_callback*)completion_key; (*cb)((int)error, io_size, (uintptr_t)lolp); } } }
void io_looper::loop_worker() { struct timespec ts = { 0, 1000000 }; while (true) { int nfds = kevent(_io_queue, nullptr, 0, _events, IO_LOOPER_MAX_EVENT_COUNT, &ts); // 1ms for timers if (nfds == 0) // timeout { handle_local_queues(); continue; } else if (-1 == nfds) { if (errno == EINTR) { continue; } else { derror("epoll_wait loop exits, err = %s", strerror(errno)); break; } } for (int i = 0; i < nfds; i++) { auto cb = (io_loop_callback*)_events[i].udata; dinfo("kevent get events %x, cb = %p", _events[i].filter, cb); uintptr_t cb0 = (uintptr_t)cb; // for those with ref_counter register entries if (cb0 & 0x1) { cb = (io_loop_callback*)(cb0 - 1); ref_counter* robj; { utils::auto_lock<utils::ex_lock_nr_spin> l(_io_sessions_lock); auto it = _io_sessions.find(cb); if (it != _io_sessions.end()) { robj = it->second; // make sure callback is protected by ref counting robj->add_ref(); } else { robj = nullptr; } } if (robj) { (*cb)(0, 0, (uintptr_t)&_events[i]); robj->release_ref(); } else { // context is gone (unregistered), let's skip dwarn("kevent event %x skipped as session is gone, cb = %p", _events[i].filter, cb ); } } else { (*cb)(0, 0, (uintptr_t)&_events[i]); } } } }