nanosm/src/EventLoop.cpp

122 lines
2.4 KiB
C++
Raw Normal View History

#include "EventLoop.hpp"
#include <sys/epoll.h>
namespace nanosm {
/// A little ergonomic wrapper over
/// std::unique_ptr<T[]>, for a "kinda-vector"
/// that lives on the heap and is statically sized
template <class T>
struct UniqueArray final {
explicit UniqueArray(usize size)
: array(std::make_unique<T[]>(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<T[]> 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<epoll_event> 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