#ifndef Poller_H #define Poller_H /*-------------------------------------------------------------------------- Copyright 1999,2000, Dan Kegel http://www.kegel.com/ See the file COPYING (Also freely licensed to Disappearing, Inc. under a separate license which allows them to do absolutely anything they want with it, without regard to the GPL.) This module is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This module is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --------------------------------------------------------------------------*/ #include #include #include #include #include "dprint.h" /** * A class to monitor a set of file descriptors for readiness events. * Current an efficient wrapper around the poll() system call. * This is the code you would have written yourself if you had had the time... */ class Poller { public: class Client; /// A class to represent a readiness event struct PollEvent { /// the file descriptor that is ready for I/O (same as in struct pollfd). int fd; /// the kind of I/O this fd is currently ready for (same as in struct pollfd). short revents; /// the object to call to handle I/O on this fd. Client *client; }; /// A class to handle a particular file descriptor's readiness events. class Client { public: /** * Handle a particular file descriptor's readiness events. * @return 0 if ok, nonzero to cause client to be deleted from Poller. */ /// typ of the socket (tcp/udp) unsigned int typ; }; /// Initialize the Poller. virtual int init(); /// Release any resouces allocated internally by this Poller. virtual void shutdown(); /** Add a file descriptor to the set we monitor. @param fd file descriptor to add @param client object to handle events for this fd. May use same client with more than one fd. @param eventmask initial event mask for this fd */ virtual int add(int fd, Client *client, short eventmask,unsigned int p_typ) = 0; /// Remove a file descriptor virtual int del(int fd) = 0; /// Give a new value for the given file descriptor's eventmask. virtual int setMask(int fd, short eventmask) = 0; /// Set fd's eventmask to its present value OR'd with the given one virtual int orMask(int fd, short eventmask) = 0; /// Set fd's eventmask to its present value AND'd with the given one virtual int andMask(int fd, short eventmask) = 0; /** Sleep at most timeout_millisec waiting for an I/O readiness event on the file descriptors we're watching. Fills internal array of readiness events. Call getNextEvent() repeatedly to read its contents. @return 0 on success, EWOULDBLOCK if no events ready */ virtual int waitForEvents(int timeout_millisec) = 0; /** Get the next event that was found by waitForEvents. @return 0 on success, EWOULDBLOCK if no more events */ virtual int getNextEvent(PollEvent *e) = 0; /** Get ready for future calls to wakeUp(). Allocates a pipe internally. @return 0 on success; Unix error code on failure. */ int initWakeUpPipe(); /** Wake up a thread which is currently sleeping in a call to waitForEvents(). May be called from any thread, but you must have called initWakeUpPipe() once before the first call to waitForEvents(). @return 0 on success; Unix error code on failure. @note Threadsafe. */ int wakeUp() { // This Poller is monitoring m_wakeup_pipe[0] for readability. // Writing a byte to m_wakeup_pipe[1] will cause a readiness event, // which will cause waitForEvents() to return. QED. // See 'man pipe'. if (write(m_wakeup_pipe[1], "a", 1) == 1) return 0; int err = errno; DPRINT(("wakeUp: write fails, err %d\n", err)); return err; } private: /// Write one byte (value not important) to m_wakeup_pipe[1] to wake up this thread. int m_wakeup_pipe[2]; /// Empty client used only to break us out of poll class WakeUpClient : public Client { public: /** * Read the bytes that were written to m_wakeup_pipe[0] by wakeUp() * @return 0 always, because the wakeup pipe should never be deleted. */ /// typ of the socket (tcp/udp) unsigned int typ; }; /// Empty client used only to break us out of poll WakeUpClient m_pipe_client; }; #endif