/*
Copyright (C) 2000 Stefan Westerfeld
stefan@space.twc.de
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
*/
/*
* BC - Status (2000-09-30):
* BINARY COMPATIBLE: IONotify, TimeNotify, IOManager
* NO BC FOR: TimeWatcher, IOWatchFD, StdIOManager
*
* Whereas the first three are part of the Interface (i.e. DEFINITELY to be
* kept binary compatible), the next three are part of the implementation
* in libmcop and subject to any kind of change.
*/
#ifndef IOMANAGER_H
#define IOMANAGER_H
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <list>
#include <stack>
namespace Arts {
// constants:
/**
* What does the reentrant flag do?
*
* The IOManager offers a processOneEvent call. This means, that you can ask
* that I/O is handled, even while in a routine that handles I/O. As a
* practical example: you may have got a remote invocation for the function
* foo. Now you are in function foo() and call function bar() on a remote
* server. When you wait for the result, you obviously will again require
* the IOManager to wait for it. Thus this is a case where you need reentrant
* I/O handling.
*
* That way, you get a multiple level stack:
*
* [...]
* |
* [ Hander for I/O ]
* |
* [ IOManager ] level 2
* |
* [ Some other function ]
* |
* [ Hander for I/O ]
* |
* [ IOManager ] level 1
* |
* [ main() ]
*
* What reentrant does, is to allow that IO Watch to be activated at levels
* higher than one.
*
* Timers and notifications, on the other hand will only be carried out at
* level 1.
*/
struct IOType {
enum { read = 1, write = 2, except = 4, reentrant = 8, all = 15 };
};
/**
* IONotify is the base class you can derive from to receive callbacks about
* IO activity. You will need to call the watchFD function of the IOManager
* to start watching a filedescriptor.
*/
class IONotify {
public:
/**
* This is the function that gets called if something relevant happened
* on the filedescriptor you watched with IOManager::watchFD.
*
* @param fd is the filedescriptor that has seen some IO activity
* @param type is the type of activity (as combination of IOType)
*/
virtual void notifyIO(int fd, int type) = 0;
};
class IOWatchFD {
int _fd, _types;
IONotify *_notify;
public:
IOWatchFD(int fd, int types, IONotify *notify);
inline int fd() { return _fd; };
inline int types() { return _types; };
inline IONotify *notify() { return _notify; };
inline void remove(int types) { _types &= ~types; }
};
class TimeNotify {
public:
virtual void notifyTime() = 0;
};
class TimeWatcher {
int milliseconds;
TimeNotify *_notify;
timeval nextNotify;
bool active, destroyed;
bool earlier(const timeval& reference);
public:
TimeWatcher(int _milliseconds, TimeNotify *notify);
inline TimeNotify *notify() { return _notify; };
timeval advance(const timeval& currentTime);
void destroy();
};
/**
* Provides services like timers and notifications when filedescriptors get
* ready to read/write.
*/
class IOManager {
public:
virtual ~IOManager() {};
/**
* processes exactly one io event
*/
virtual void processOneEvent(bool blocking) = 0;
/**
* enters a loop which processes io events, until terminate is called
*
* may only be called once (use processOneEvent for other purposes)
*/
virtual void run() = 0;
/**
* terminates the io event loop (which was started with run)
*/
virtual void terminate() = 0;
/**
* starts watching one filedescriptor for certain types of operations
*
* notifies the notify object when e.g. the fd requires (allows) reading
* and types contained IOType::read.
*/
virtual void watchFD(int fd, int types, IONotify *notify) = 0;
/**
* stops watching a filedescriptor
*/
virtual void remove(IONotify *notify, int types) = 0;
/**
* starts a periodic timer
*/
virtual void addTimer(int milliseconds, TimeNotify *notify) = 0;
/**
* stops the timer
*/
virtual void removeTimer(TimeNotify *notify) = 0;
};
class StdIOManager : public IOManager {
protected:
std::list<IOWatchFD *> fdList;
std::list<TimeWatcher *> timeList;
std::stack< std::pair<IOWatchFD *,int> > notifyStack;
bool terminated;
bool fdListChanged; // causes the fd_sets to be rebuilt before using them
fd_set readfds, writefds, exceptfds;
fd_set reentrant_readfds, reentrant_writefds, reentrant_exceptfds;
int maxfd;
int level;
public:
StdIOManager();
void processOneEvent(bool blocking);
void run();
void terminate();
void watchFD(int fd, int types, IONotify *notify);
void remove(IONotify *notify, int types);
void addTimer(int milliseconds, TimeNotify *notify);
void removeTimer(TimeNotify *notify);
};
};
#endif
| Generated by: stefan@stefan on Sat Feb 24 19:11:23 2001, using kdoc 2.0a47. |