122 lines
2.4 KiB
C++
122 lines
2.4 KiB
C++
#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
|