#include "EventLoop.hpp" #include namespace nanosm { /// A little ergonomic wrapper over /// std::unique_ptr, for a "kinda-vector" /// that lives on the heap and is statically sized template struct UniqueArray final { explicit UniqueArray(usize size) : array(std::make_unique(size)), size(size) { } UniqueArray(UniqueArray&& move) { array = std::move(move.array); size = move.size; // invalidate move.array = nullptr; move.size = 0; } T& operator[](usize index) { return Get()[index]; } const T& operator[](usize index) const { return Get()[index]; } T* Get() { return array.get(); } const T* Get() const { return array.get(); } usize Size() const { return size; } private: std::unique_ptr array {}; usize size {}; }; EventLoop::EventLoop() { epollFd = epoll_create1(EPOLL_CLOEXEC); if(epollFd == -1) { perror("You Banned From Epoll, Rules"); } } EventLoop::~EventLoop() { close(epollFd); } void EventLoop::Post(PostFn func) { if(!func) return; postCallbacks.push_back(func); } void EventLoop::AddObject(IoObject::Ptr obj) { if(!obj) return; if(obj->GetFD() == -1) return; ioObjects.insert(obj); epoll_event ev {}; ev.events = obj->InterestedEvents(); ev.data.fd = obj->GetFD(); epoll_ctl(epollFd, EPOLL_CTL_ADD, obj->GetFD(), &ev); } void EventLoop::RemoveObject(IoObject::Ptr obj) { if(!obj) return; ioObjects.erase(obj); epoll_event ev {}; ev.events = obj->InterestedEvents(); ev.data.fd = obj->GetFD(); epoll_ctl(epollFd, EPOLL_CTL_DEL, obj->GetFD(), &ev); } void EventLoop::Run() { UniqueArray events { 16 }; while(!shouldStop) { auto nevents = epoll_wait(epollFd, events.Get(), events.Size(), 10); if(nevents == -1) { perror("epoll_wait"); break; } // All OK, let's check for events now for(int i = 0; i < nevents; ++i) { for(auto pollable : ioObjects) { if(auto fd = pollable->GetFD(); fd != -1) { // Signal any events that occur for this if(events[i].data.fd == fd) pollable->OnReady(events[i].events); } } } // Run the topmost callback once every event loop iteration. if(!postCallbacks.empty()) { auto& frontCallback = postCallbacks.front(); frontCallback(); postCallbacks.pop_front(); } } } void EventLoop::Stop() { shouldStop = true; } } // namespace nanosm