src/Network/Reactor.cc
author Tero Marttila <terom@fixme.fi>
Fri, 16 Jan 2009 22:03:49 +0200
changeset 400 d64bf28c4340
parent 384 6d387796b139
permissions -rw-r--r--
more documentation tweaking, all Network/ files now have a @file comment. Fix Platform.h -> Platform.hh, and Buffer.hh + Packet.cc

#include "Reactor.hh"

NetworkReactor::NetworkReactor (void) :
    sockets()
{

}

void NetworkReactor::poll (timeval *timeout) {
    int ret;

    // start counting the maximum fd from 0, select will be given nfds=1 if 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();

        // ignore if nothing
        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(fd, &read);
            
            // write...
            if (mask & POLL_WRITE)
                FD_SET(fd, &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;