bool KQueueEngine::AddFd(EventHandler* eh, int event_mask) { int fd = eh->GetFd(); if ((fd < 0) || (fd > GetMaxFds() - 1)) return false; if (ref[fd]) return false; // We always want to read from the socket... struct kevent ke; EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, NULL); int i = kevent(EngineHandle, &ke, 1, 0, 0, NULL); if (i == -1) { ServerInstance->Logs->Log("SOCKET", LOG_DEFAULT, "Failed to add fd: %d %s", fd, strerror(errno)); return false; } ref[fd] = eh; SocketEngine::SetEventMask(eh, event_mask); OnSetEvent(eh, 0, event_mask); CurrentSetSize++; ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d", fd); return true; }
bool SocketEngine::AddFd(EventHandler* eh, int event_mask) { int fd = eh->GetFd(); if ((fd < 0) || (fd > GetMaxFds() - 1)) return false; if (!SocketEngine::AddFdRef(eh)) return false; eh->SetEventMask(event_mask); OnSetEvent(eh, 0, event_mask); FD_SET(fd, &ErrSet); if (fd > MaxFD) MaxFD = fd; ServerInstance->Logs->Log("SOCKET", LOG_DEBUG, "New file descriptor: %d", fd); return true; }
void SocketEngine::ChangeEventMask(EventHandler* eh, int change) { int old_m = eh->event_mask; int new_m = old_m; // if we are changing read/write type, remove the previously set bit if (change & FD_WANT_READ_MASK) new_m &= ~FD_WANT_READ_MASK; if (change & FD_WANT_WRITE_MASK) new_m &= ~FD_WANT_WRITE_MASK; // if adding a trial read/write, insert it into the set if (change & FD_TRIAL_NOTE_MASK && !(old_m & FD_TRIAL_NOTE_MASK)) trials.insert(eh->GetFd()); new_m |= change; if (new_m == old_m) return; eh->event_mask = new_m; OnSetEvent(eh, old_m, new_m); }
int EPollEngine::DispatchEvents() { socklen_t codesize = sizeof(int); int errcode; int i = epoll_wait(EngineHandle, events, GetMaxFds() - 1, 1000); ServerInstance->UpdateTime(); TotalEvents += i; for (int j = 0; j < i; j++) { EventHandler* eh = ref[events[j].data.fd]; if (!eh) { ServerInstance->Logs->Log("SOCKET",LOG_DEBUG,"Got event on unknown fd: %d", events[j].data.fd); epoll_ctl(EngineHandle, EPOLL_CTL_DEL, events[j].data.fd, &events[j]); continue; } if (events[j].events & EPOLLHUP) { ErrorEvents++; eh->HandleEvent(EVENT_ERROR, 0); continue; } if (events[j].events & EPOLLERR) { ErrorEvents++; /* Get error number */ if (getsockopt(events[j].data.fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0) errcode = errno; eh->HandleEvent(EVENT_ERROR, errcode); continue; } int mask = eh->GetEventMask(); if (events[j].events & EPOLLIN) mask &= ~FD_READ_WILL_BLOCK; if (events[j].events & EPOLLOUT) { mask &= ~FD_WRITE_WILL_BLOCK; if (mask & FD_WANT_SINGLE_WRITE) { int nm = mask & ~FD_WANT_SINGLE_WRITE; OnSetEvent(eh, mask, nm); mask = nm; } } SetEventMask(eh, mask); if (events[j].events & EPOLLIN) { ReadEvents++; eh->HandleEvent(EVENT_READ); if (eh != ref[events[j].data.fd]) // whoa! we got deleted, better not give out the write event continue; } if (events[j].events & EPOLLOUT) { WriteEvents++; eh->HandleEvent(EVENT_WRITE); } } return i; }
int SocketEngine::DispatchEvents() { int i = epoll_wait(EngineHandle, &events[0], events.size(), 1000); ServerInstance->UpdateTime(); stats.TotalEvents += i; for (int j = 0; j < i; j++) { // Copy these in case the vector gets resized and ev invalidated const epoll_event ev = events[j]; EventHandler* const eh = static_cast<EventHandler*>(ev.data.ptr); const int fd = eh->GetFd(); if (fd < 0) continue; if (ev.events & EPOLLHUP) { stats.ErrorEvents++; eh->OnEventHandlerError(0); continue; } if (ev.events & EPOLLERR) { stats.ErrorEvents++; /* Get error number */ socklen_t codesize = sizeof(int); int errcode; if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &errcode, &codesize) < 0) errcode = errno; eh->OnEventHandlerError(errcode); continue; } int mask = eh->GetEventMask(); if (ev.events & EPOLLIN) mask &= ~FD_READ_WILL_BLOCK; if (ev.events & EPOLLOUT) { mask &= ~FD_WRITE_WILL_BLOCK; if (mask & FD_WANT_SINGLE_WRITE) { int nm = mask & ~FD_WANT_SINGLE_WRITE; OnSetEvent(eh, mask, nm); mask = nm; } } eh->SetEventMask(mask); if (ev.events & EPOLLIN) { stats.ReadEvents++; eh->OnEventHandlerRead(); if (eh != GetRef(fd)) // whoa! we got deleted, better not give out the write event continue; } if (ev.events & EPOLLOUT) { stats.WriteEvents++; eh->OnEventHandlerWrite(); } } return i; }