#ifndef EVENT_LOOP_H
#define EVENT_LOOP_H
#include "Device.h"
#include <functional>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
class Service
{
public:
virtual Duration frequency() = 0;
virtual void update(Duration a_dt) = 0;
};
class DeviceNotifierService : public Service
{
public:
void registerDeviceNotifier(DeviceNotifier& device) {
m_notifiers.push_back(device);
}
void update(Duration a_dt) override {
/*
POLLIN There is data to read.
POLLPRI There is urgent data to read
POLLOUT Writing now will not block.
POLLERR Error condition (output only).
POLLHUP Hang up (output only).
POLLNVAL Invalid request: fd not open (output only).
*/
WaitCanRead = 1,
WaitCanWrite = 2,
WaitForException = 4,
WaitForTimeout = 8
const int count = m_notifiers.size();
struct pollfd fds[count];
int timeoutMs = 0;
for (int i = 0; i < count; i++) {
auto notifier = m_notifiers[i];
fds[i].fd = notifier.getDeviceHandle();
fds[i].events = ((notifier.m_flags & WaitCanRead) ? POLLIN : 0) |
((notifier.m_flags & WaitCanWrite) ? POLLOUT : 0);
fds[i].revents = 0;
// TODO: need to think about if the loop should never block and go flat out
// if it can, or be limited by a rate which some task sets or if no task with
// a timeout, then it will block indefinately until there is any i/o events ('input')
// This trade off is one of power consumption vs speed
if (notifier.m_flags & WaitTimeout) {
if (!timeoutMs) {
timeoutMs = notifier.m_timeout / 1000;
} else {
int milliSec = notifier.m_timeout / 1000;
if (milliSec < timeoutMs)
timeoutMs = milliSec;
}
}
}
int res = poll(fds, count, timeoutMs);
if (res <= 0) {
if (res == 0) { // timeout
} else {
// error, in errno
}
} else {
for (int i = 0; i < count; i++) {
auto notifier = m_notifiers[i];
if (fds[i].revents & POLLIN)
notifier.readyRead();
if (fds[i].revents & POLLOUT)
notifier.readyWrite();
if (fds[i].revents & POLLERR)
notifier.error();
if (fds[i].revents & POLLHUP)
notifier.closed();
if (fds[i].revents & POLLNVAL)
notifier.invalid();
}
}
/*
fd_set rfds, wfds, xfds;
struct timeval tv = { 0, 0 };
FD_ZERO(&rfds);
FD_ZERO(&wfds);
FD_ZERO(&xfds);
int highestFd = 0;
for (auto notifier : m_notifiers) {
int fd = notifier.getDeviceHandle();
if (notifier.m_flags & (WaitCanRead | WaitCanWrite | WaitForException) && fd > highestFd)
highestFd = fd;
if (notifier.m_flags & WaitCanRead)
FD_SET(fd, &rfds);
if (notifier.m_flags & WaitCanWrite)
FD_SET(fd, &wfds);
if (notifier.m_flags & WaitForException)
FD_SET(fd, &xfds);
// TODO: merge timeouts
// tv = min(tv, notifier.m_timeout)
}
int res = select(highestFd+1, &rfds, &wfds, &xfds, &tv);
if (res == -1) {
// error
} else {
if (res == 0) {
// timeout
} else {
FD_ISSET(fd, &rfds)
for (auto notifier : m_notifiers) {
int fd = notifier.getDeviceHandle();
if (notifier.m_flags & (WaitCanRead | WaitCanWrite | WaitForException) && fd > highestFd)
highestFd = fd;
if (notifier.m_flags & WaitCanRead)
FD_SET(fd, &rfds);
if (notifier.m_flags & WaitCanWrite)
FD_SET(fd, &wfds);
if (notifier.m_flags & WaitForException)
FD_SET(fd, &xfds);
// TODO: merge timeouts
// tv = min(tv, notifier.m_timeout)
}
}
}
*/
}
// Call very frequently
Duration frequency() override { return Duration(0); }
private:
std::vector<DeviceNotifier> m_notifiers;
};
class EventLoop
{
public:
EventLoop();
~EventLoop();
// Works out dt, then calls update for all the registered services
void update();
private:
};
#endif // EVENT_LOOP_H