summaryrefslogtreecommitdiffstats
path: root/mcop/iomanager.cc
diff options
context:
space:
mode:
Diffstat (limited to 'mcop/iomanager.cc')
-rw-r--r--mcop/iomanager.cc494
1 files changed, 0 insertions, 494 deletions
diff --git a/mcop/iomanager.cc b/mcop/iomanager.cc
deleted file mode 100644
index 263fab6..0000000
--- a/mcop/iomanager.cc
+++ /dev/null
@@ -1,494 +0,0 @@
- /*
-
- 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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA.
-
- */
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "iomanager.h"
-#include "dispatcher.h"
-#include "notification.h"
-#include "thread.h"
-#include <stdio.h>
-#include <fcntl.h>
-
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h> // Needed on some systems.
-#endif
-// WABA: NOTE!
-// sys/select.h is needed on e.g. AIX to define "fd_set".
-// However, we can not include config.h in a header file.
-// The right solution would be not to use "fd_set" in the
-// header file but to use it only in a private datastructure
-// defined in the .cc file.
-
-using namespace std;
-using namespace Arts;
-
-namespace Arts {
-/* internal data structures */
-class IOWatchFD {
- int _fd, _types;
- IONotify *_notify;
-
-public:
- int activeTypes;
-
- 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 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();
-};
-}
-
-/*
- * Enable this if you want to debug how long certain plugins / operations
- * take to perform. You'll get the times between two select() calls that are
- * done by the IOManager, which is equivalent to the time the input/output
- * remains unserved. For apps like artsd, it gives the minimum audio latency
- * users will need to specify to avoid dropouts.
- */
-#undef IOMANAGER_DEBUG_LATENCY
-
-#ifdef IOMANAGER_DEBUG_LATENCY
-static timeval iomanager_debug_latency_time = { 0, 0 };
-
-static void iomanager_debug_latency_end()
-{
- if(iomanager_debug_latency_time.tv_sec)
- {
- timeval end;
- gettimeofday(&end,0);
-
- float diff = (end.tv_usec-iomanager_debug_latency_time.tv_usec)/1000.0
- + (end.tv_sec-iomanager_debug_latency_time.tv_sec)*1000.0;
-
- /* change this value if you get your screen filled up with messages */
- if(diff >= 1.5)
- fprintf(stderr,"IOManager: latency for operation: %2.3f ms\n",diff);
- }
-}
-
-static void iomanager_debug_latency_start()
-{
- gettimeofday(&iomanager_debug_latency_time,0);
-}
-#else
-static inline void iomanager_debug_latency_end()
-{
-}
-
-static inline void iomanager_debug_latency_start()
-{
-}
-#endif
-
-IOWatchFD::IOWatchFD(int fd, int types, IONotify *notify)
-{
- _fd = fd;
- _types = types;
- _notify = notify;
- activeTypes = 0;
-}
-
-StdIOManager::StdIOManager()
-{
- // force initialization of the fd_set's
- fdListChanged = true;
- timeListChanged = false;
- level = 0;
-}
-
-void StdIOManager::processOneEvent(bool blocking)
-{
- assert(SystemThreads::the()->isMainThread());
-
- level++;
-
- // we release and acquire the lock only on level 1
- if(level == 1)
- Dispatcher::lock();
-
- // notifications not carried out reentrant
- if(level == 1)
- NotificationManager::the()->run();
-
- // FIXME: timers *could* change the file descriptors to select...
- //---
- if(fdListChanged)
- {
- FD_ZERO(&readfds);
- FD_ZERO(&writefds);
- FD_ZERO(&exceptfds);
- FD_ZERO(&reentrant_readfds);
- FD_ZERO(&reentrant_writefds);
- FD_ZERO(&reentrant_exceptfds);
-
- maxfd = 0;
-
- list<IOWatchFD *>::iterator i;
- for(i = fdList.begin(); i != fdList.end(); i++)
- {
- IOWatchFD *w = *i;
-
- if(w->types() & IOType::read) FD_SET(w->fd(),&readfds);
- if(w->types() & IOType::write) FD_SET(w->fd(),&writefds);
- if(w->types() & IOType::except) FD_SET(w->fd(),&exceptfds);
-
- if(w->types() & IOType::reentrant)
- {
- if(w->types() & IOType::read)
- FD_SET(w->fd(),&reentrant_readfds);
- if(w->types() & IOType::write)
- FD_SET(w->fd(),&reentrant_writefds);
- if(w->types() & IOType::except)
- FD_SET(w->fd(),&reentrant_exceptfds);
- }
-
- if(w->types() && w->fd() > maxfd) maxfd = w->fd();
- }
-
- fdListChanged = false;
- }
- fd_set rfd,wfd,efd;
- if(level == 1)
- {
- rfd = readfds;
- wfd = writefds;
- efd = exceptfds;
- }
- else
- {
- // watch out, this is reentrant I/O
- rfd = reentrant_readfds;
- wfd = reentrant_writefds;
- efd = reentrant_exceptfds;
- }
-
- /* default timeout 5 seconds */
- long selectabs;
-
- if(blocking)
- selectabs = 5000000;
- else
- selectabs = 0;
-
- /* prepare timers - only at level 1 */
- if(level == 1 && timeList.size())
- {
- struct timeval currenttime;
- gettimeofday(&currenttime,0);
-
- list<TimeWatcher *>::iterator ti;
-
- timeListChanged = false;
- ti = timeList.begin();
- while(ti != timeList.end())
- {
- TimeWatcher *w = *ti++;
- timeval timertime = w->advance(currenttime);
-
- // if that may happen in the next ten seconds
- if(timertime.tv_sec < currenttime.tv_sec+10)
- {
- long timerabs = (timertime.tv_sec - currenttime.tv_sec)*1000000;
- timerabs += (timertime.tv_usec - currenttime.tv_usec);
-
- if(timerabs < selectabs) selectabs = timerabs;
- }
-
- if(timeListChanged)
- {
- ti = timeList.begin();
- timeListChanged = false;
- }
- }
- }
-
- timeval select_timeout;
- select_timeout.tv_sec = selectabs / 1000000;
- select_timeout.tv_usec = selectabs % 1000000;
-
- if(level == 1) iomanager_debug_latency_end();
-
- // we release and acquire the lock only on level 1
- if(level == 1)
- Dispatcher::unlock();
-
- int retval = select(maxfd+1,&rfd,&wfd,&efd,&select_timeout);
-
- // we release and acquire the lock only on level 1
- if(level == 1)
- Dispatcher::lock();
-
- if(level == 1) iomanager_debug_latency_start();
-
- if(retval > 0)
- {
- /*
- * the problem is, that objects that are being notified may change
- * the watch list, add fds, remove fds, remove objects and whatever
- * else
- *
- * so we can' notify them from the loop - but we can make a stack
- * of "notifications to do" and send them as soon as we looked up
- * in the list what to send
- */
- long tonotify = 0;
-
- list<IOWatchFD *>::iterator i;
- for(i = fdList.begin(); i != fdList.end(); i++) {
- IOWatchFD *w = *i;
- int match = 0;
-
- if(FD_ISSET(w->fd(),&rfd) && (w->types() & IOType::read))
- match |= IOType::read;
-
- if(FD_ISSET(w->fd(),&wfd) && (w->types() & IOType::write))
- match |= IOType::write;
-
- if(FD_ISSET(w->fd(),&efd) && (w->types() & IOType::except))
- match |= IOType::except;
-
- if((w->types() & IOType::reentrant) == 0 && level != 1)
- match = 0;
-
- if(match) {
- tonotify++;
- w->activeTypes = match;
- notifyStack.push(w);
- }
- }
-
- while(tonotify != 0)
- {
- if(!fdListChanged)
- {
- IOWatchFD *w = notifyStack.top();
- int activeTypes = w->activeTypes;
- int fd = w->fd();
- IONotify *notify = w->notify();
-
- w->activeTypes = 0;
- notify->notifyIO(fd, activeTypes);
- // warning: w and notify might no longer exist here
- }
-
- notifyStack.pop();
- tonotify--;
- }
- }
- /* handle timers - only at level 1 */
- if(level == 1 && timeList.size())
- {
- struct timeval currenttime;
- gettimeofday(&currenttime,0);
-
- list<TimeWatcher *>::iterator ti;
-
- timeListChanged = false;
- ti = timeList.begin();
- while(ti != timeList.end())
- {
- TimeWatcher *w = *ti++;
- w->advance(currenttime);
- if (timeListChanged)
- {
- ti = timeList.begin();
- timeListChanged = false;
- }
- }
- }
-
- // notifications not carried out reentrant
- if(level == 1)
- NotificationManager::the()->run();
-
- // we release and acquire the lock only on level 1
- if(level == 1)
- Dispatcher::unlock();
-
- level--;
-}
-
-void StdIOManager::run()
-{
- assert(SystemThreads::the()->isMainThread());
- assert(level == 0);
-
- // FIXME: this might not be threadsafe, as there is no lock here!
- terminated = false;
- while(!terminated)
- processOneEvent(true);
-}
-
-void StdIOManager::terminate()
-{
- terminated = true;
- Dispatcher::wakeUp();
-}
-
-void StdIOManager::watchFD(int fd, int types, IONotify *notify)
-{
- /*
- IOWatchFD *watchfd = findWatch(fd,notify);
- if(watchfd)
- {
- watchfd->add(types);
- }
- else
- {
- fdList.push_back(new IOWatchFD(fd,types,notify));
- }
- */
-
- // FIXME: might want to reuse old watches
- fdList.push_back(new IOWatchFD(fd,types,notify));
- fdListChanged = true;
- Dispatcher::wakeUp();
-}
-
-void StdIOManager::remove(IONotify *notify, int types)
-{
- list<IOWatchFD *>::iterator i;
-
- i = fdList.begin();
-
- while(i != fdList.end())
- {
- IOWatchFD *w = *i;
-
- if(w->notify() == notify) w->remove(types);
-
- // nothing left to watch?
- if(w->types() == 0 || w->types() == IOType::reentrant)
- {
- i = fdList.erase(i);
- delete w; // FIXME: shouldn't we have a destroy() similar
- // to the one for timers
- }
- else i++;
- }
- fdListChanged = true;
-}
-
-void StdIOManager::addTimer(int milliseconds, TimeNotify *notify)
-{
- if (milliseconds == -1 && notify == 0) {
- // HACK: in order to not add a virtual function to IOManager we're calling addTimer with
- // magic values. This call tells the ioManager that notifications are pending and
- // NotificationManager::run() should get called soon.
- } else {
- timeList.push_back(new TimeWatcher(milliseconds,notify));
- timeListChanged = true;
- Dispatcher::wakeUp();
- }
-}
-
-void StdIOManager::removeTimer(TimeNotify *notify)
-{
- list<TimeWatcher *>::iterator i;
-
- i = timeList.begin();
-
- while(i != timeList.end())
- {
- TimeWatcher *w = *i;
-
- if(w->notify() == notify)
- {
- i = timeList.erase(i);
- timeListChanged = true;
- w->destroy();
- }
- else i++;
- }
-}
-
-TimeWatcher::TimeWatcher(int _milliseconds, TimeNotify *notify)
- : milliseconds(_milliseconds),_notify(notify),active(false),destroyed(false)
-{
- gettimeofday(&nextNotify,0);
-
- nextNotify.tv_usec += (milliseconds%1000)*1000;
- nextNotify.tv_sec += (milliseconds/1000)+(nextNotify.tv_usec/1000000);
- nextNotify.tv_usec %= 1000000;
-}
-
-timeval TimeWatcher::advance(const timeval& currentTime)
-{
- active = true;
- while(earlier(currentTime))
- {
- nextNotify.tv_usec += (milliseconds%1000)*1000;
- nextNotify.tv_sec += (milliseconds/1000)+(nextNotify.tv_usec/1000000);
- nextNotify.tv_usec %= 1000000;
-
- _notify->notifyTime();
-
- if(destroyed)
- {
- delete this;
-
- struct timeval never = { -1, 0 };
- return never;
- }
- }
- active = false;
- return nextNotify;
-}
-
-bool TimeWatcher::earlier(const timeval& reference)
-{
- if(nextNotify.tv_sec > reference.tv_sec) return false;
- if(nextNotify.tv_sec < reference.tv_sec) return true;
-
- return (nextNotify.tv_usec < reference.tv_usec);
-}
-
-void TimeWatcher::destroy()
-{
- if(active)
- {
- destroyed = true;
- }
- else
- {
- delete this;
- }
-}