diff options
Diffstat (limited to 'mcop/iomanager.cc')
-rw-r--r-- | mcop/iomanager.cc | 494 |
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(¤ttime,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(¤ttime,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; - } -} |