#include "Reactor.hh"
NetworkReactor::NetworkReactor (void) :
sockets()
{
}
void NetworkReactor::poll (timeval *timeout) {
int ret;
// start counting the maximum fd from -1, so that select is given nfds=0 if our list is empty
int fd_max = 0;
// zero our fdsets
fd_set read, write;
FD_ZERO(&read);
FD_ZERO(&write);
// inspect our sockets
for (std::list<NetworkSocket*>::iterator it = sockets.begin(); it != sockets.end(); it++) {
NetworkSocket *socket = *it;
// ask socket what events it wants
NetworkPollMask mask = socket->get_poll();
// set read/write
if (mask) {
// socket file descriptor...
int fd = socket->get_socket();
// ignore invalid FDs
if (fd < 0)
continue;
// update fd_max?
if (fd > fd_max)
fd_max = fd;
// read...
if (mask & POLL_READ)
FD_SET(socket->get_socket(), &read);
// write...
if (mask & POLL_WRITE)
FD_SET(socket->get_socket(), &write);
}
}
// loop select() on EINTR
do {
// we never care about except, and pass NULL fdsets if they are empty
ret = select(
fd_max + 1,
fd_max ? &read : NULL,
fd_max ? &write : NULL,
NULL,
timeout
);
} while (ret < 0 && errno == EINTR);
// error?
if (ret < 0)
throw NetworkReactorError("select");
// ignore if we just timed out
if (ret == 0)
return;
// notify up to <ret> socket-events
for (std::list<NetworkSocket*>::iterator it = sockets.begin(); it != sockets.end() && ret > 0; it++) {
NetworkSocket *socket = *it;
// socket file descriptor...
int fd = socket->get_socket();
// ignore invalid FDs
if (fd < 0)
continue;
// mask of events detected
NetworkPollMask mask = 0;
// detect read
if (FD_ISSET(fd, &read)) {
mask |= POLL_READ;
ret--;
}
// detect write
if (FD_ISSET(fd, &write)) {
mask |= POLL_WRITE;
ret--;
}
// notify?
if (mask)
socket->notify(mask);
}
}
// the global reactor
static NetworkReactor g_reactor;
NetworkReactor *NetworkReactor::current = &g_reactor;