diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-05 00:01:18 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-05 00:01:18 +0000 |
commit | 42995d7bf396933ee60c5f89c354ea89cf13df0d (patch) | |
tree | cfdcea0ac57420e7baf570bfe435e107bb842541 /gmcop | |
download | arts-42995d7bf396933ee60c5f89c354ea89cf13df0d.tar.gz arts-42995d7bf396933ee60c5f89c354ea89cf13df0d.zip |
Copy of aRts for Trinity modifications
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/dependencies/arts@1070145 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'gmcop')
-rw-r--r-- | gmcop/Makefile.am | 10 | ||||
-rw-r--r-- | gmcop/giomanager.cc | 506 | ||||
-rw-r--r-- | gmcop/giomanager.h | 128 |
3 files changed, 644 insertions, 0 deletions
diff --git a/gmcop/Makefile.am b/gmcop/Makefile.am new file mode 100644 index 0000000..2d86b41 --- /dev/null +++ b/gmcop/Makefile.am @@ -0,0 +1,10 @@ +lib_LTLIBRARIES = libgmcop.la + +INCLUDES = -I$(top_srcdir)/mcop -I$(top_builddir)/mcop $(GLIB_CFLAGS) $(all_includes) + +libgmcop_la_SOURCES = giomanager.cc +libgmcop_la_LIBADD = $(top_builddir)/mcop/libmcop.la $(GLIB_LIBADD) +libgmcop_la_LDFLAGS = -no-undefined -version-info 1:0 $(GLIB_LDFLAGS) $(all_libraries) + +artsincludedir = $(includedir)/arts +artsinclude_HEADERS = giomanager.h diff --git a/gmcop/giomanager.cc b/gmcop/giomanager.cc new file mode 100644 index 0000000..2518008 --- /dev/null +++ b/gmcop/giomanager.cc @@ -0,0 +1,506 @@ + /* + + Copyright (C) 2001 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. + + */ + + +#include "giomanager.h" +#include "notification.h" +#include "debug.h" +#include "dispatcher.h" +#include <glib.h> + +using namespace Arts; +using namespace std; + +/* + * Fallback for the case where we should perform blocking + */ +namespace Arts { +class GIOManagerBlocking : public StdIOManager { +public: + void setLevel(int newLevel) { level = newLevel; } +}; +} + +namespace Arts { + struct GIOManagerSource + { + GSource source; + GIOManager *ioManager; + }; + struct GIOWatch + { + GPollFD gpollfd; /* <- must be the first data member */ + + /* GPollFD = + gint fd; + gushort events; + gushort revents; + */ + GIOWatch(GIOManagerSource *source, int fd, int types, IONotify *notify) + : types(types), registered(false), notify(notify), source(source) + { + gpollfd.fd = fd; + setTypes(types); + } + void setTypes(int types) + { + this->types = types; + gpollfd.events = gpollfd.revents = 0; + + if(types & IOType::read) + gpollfd.events |= G_IO_IN | G_IO_HUP; + if(types & IOType::write) + gpollfd.events |= G_IO_OUT; + if(types & IOType::except) + gpollfd.events |= G_IO_ERR; + + } + /* prepares source for running in event loop level "level" + * removes source unconditionally if level == -1 + */ + void prepare(int level) + { + gpollfd.revents = 0; + + bool shouldRegister = true; + if(level != 1 && (types & IOType::reentrant) == 0) + shouldRegister = false; + if(level == -1) + shouldRegister = false; + + if(shouldRegister == registered) + return; + + if(shouldRegister) + { + g_source_add_poll(&source->source, &this->gpollfd); + } + else + { + g_source_remove_poll(&source->source, &this->gpollfd); + } + + registered = shouldRegister; + } + int check() + { + int result = 0; + + if(gpollfd.revents & (G_IO_IN | G_IO_HUP)) + result |= IOType::read; + if(gpollfd.revents & G_IO_OUT) + result |= IOType::write; + if(gpollfd.revents & G_IO_ERR) + result |= IOType::except; + + return result; + } + void destroy() + { + /* TODO: if active do this, else do that */ + delete this; + } + ~GIOWatch() + { + prepare(-1); + } + + int types; + bool registered; + IONotify *notify; + GIOManagerSource *source; + }; + +class GIOTimeWatch { + int milliseconds; + TimeNotify *_notify; + timeval nextNotify; + bool active, destroyed; +public: + GIOTimeWatch(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; + } + int msUntilNextNotify(const timeval& now) + { + int result = (nextNotify.tv_sec - now.tv_sec)*1000 + + (nextNotify.tv_usec - now.tv_usec)/1000; + + if(result < 0) result = 0; + return result; + } + void advance(const timeval& currentTime) + { + active = true; + while(msUntilNextNotify(currentTime) == 0) + { + 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; + return; + } + } + active = false; + } + void destroy() + { + if(active) + { + destroyed = true; + } + else + { + delete this; + } + } + TimeNotify *notify() + { + return _notify; + } +}; + +static gboolean GIOManager_prepare(GSource *source, gint *timeout) +{ + return((GIOManagerSource *)source)->ioManager->prepare(timeout); +} + +static gboolean GIOManager_check(GSource *source) +{ + return((GIOManagerSource *)source)->ioManager->check(); +} + +static gboolean GIOManager_dispatch(GSource *source, GSourceFunc callback, + gpointer user_data) +{ + return((GIOManagerSource *)source)->ioManager->dispatch(callback,user_data); +} + + +} + +GIOManager::GIOManager(GMainContext *context) + : level(0), context(context) +{ + static GSourceFuncs funcs = + { + GIOManager_prepare, + GIOManager_check, + GIOManager_dispatch, + 0 + }; + + source = (GIOManagerSource *)g_source_new(&funcs, sizeof(GIOManagerSource)); + source->ioManager = this; + g_source_set_can_recurse(&source->source, true); + g_source_attach(&source->source, context); + + gioManagerBlocking = new GIOManagerBlocking(); + _blocking = true; + fileDescriptorsNeedRecheck = false; +} + +GIOManager::~GIOManager() +{ + g_source_unref(&source->source); + delete gioManagerBlocking; +} + +void GIOManager::processOneEvent(bool blocking) +{ + if(_blocking) + { + level++; + if(level == 1) + Dispatcher::lock(); + + /* + * we explicitly take the level to gioManagerBlocking, so that it + * will process reentrant watchFDs only + */ + fileDescriptorsNeedRecheck = true; + gioManagerBlocking->setLevel(level); + gioManagerBlocking->processOneEvent(blocking); + + if(level == 1) + Dispatcher::unlock(); + level--; + } + else + { + g_main_context_iteration(context, blocking); + } +} + +void GIOManager::setBlocking(bool blocking) +{ + _blocking = blocking; +} + +void GIOManager::run() +{ + arts_warning("GIOManager::run not implemented yet"); +} + +void GIOManager::terminate() +{ + arts_warning("GIOManager::terminate not implemented yet"); +} + +void GIOManager::watchFD(int fd, int types, IONotify * notify) +{ + fdList.push_back(new GIOWatch(source, fd, types, notify)); + + if(types & IOType::reentrant) + gioManagerBlocking->watchFD(fd, types, notify); +} + +void GIOManager::remove(IONotify *notify, int types) +{ + list<GIOWatch *>::iterator i; + + i = fdList.begin(); + while(i != fdList.end()) + { + GIOWatch *w = *i; + + if(w->notify == notify) + { + int newTypes = w->types & (~types); + + if(newTypes) + { + w->setTypes(newTypes); + } + else + { + w->destroy(); + fdList.erase(i); + i = fdList.begin(); + } + } + else i++; + } + gioManagerBlocking->remove(notify, types); +} + +void GIOManager::addTimer(int milliseconds, TimeNotify *notify) +{ + timeList.push_back(new GIOTimeWatch(milliseconds,notify)); +} + +void GIOManager::removeTimer(TimeNotify *notify) +{ + list<GIOTimeWatch *>::iterator i; + + i = timeList.begin(); + while(i != timeList.end()) + { + GIOTimeWatch *w = *i; + + if(w->notify() == notify) + { + w->destroy(); + timeList.erase(i); + i = timeList.begin(); + } + else i++; + } +} + +gboolean GIOManager::prepare(gint *timeout) +{ + *timeout = 10000; + + level++; + + if(level == 1) + Dispatcher::lock(); + + /* handle timers - only at level 1 */ + if(level == 1 && timeList.size()) + { + struct timeval currenttime; + gettimeofday(¤ttime,0); + + list<GIOTimeWatch *>::iterator ti; + + ti = timeList.begin(); + while(ti != timeList.end()) + { + GIOTimeWatch *w = *ti++; + int ms = w->msUntilNextNotify(currenttime); + + if(ms < *timeout) *timeout = ms; + } + } + + list<GIOWatch *>::iterator i; + for(i = fdList.begin(); i != fdList.end(); i++) + { + GIOWatch *w = *i; + w->prepare(level); + } + fileDescriptorsNeedRecheck = false; + + if(level == 1 && NotificationManager::the()->pending()) + *timeout = 0; + + if(level == 1) + Dispatcher::unlock(); + + level--; + + return (*timeout == 0); +} + +gboolean GIOManager::check() +{ + gboolean result = false; + level++; + + if(level == 1) + Dispatcher::lock(); + + /* + * handle timers - only at level 1 + */ + if(level == 1 && timeList.size()) + { + struct timeval currenttime; + gettimeofday(¤ttime,0); + + list<GIOTimeWatch *>::iterator ti; + + ti = timeList.begin(); + while(ti != timeList.end() && !result) + { + GIOTimeWatch *w = *ti++; + if(w->msUntilNextNotify(currenttime) == 0) + result = true; + } + } + + /* + * handle filedescriptors + */ + list<GIOWatch *>::iterator i; + for(i = fdList.begin(); i != fdList.end(); i++) { + GIOWatch *w = *i; + int match = w->check(); + + if((w->types & IOType::reentrant) == 0 && level != 1) + { + arts_assert(match == 0); + } + if(match) + { + result = true; + } + } + fileDescriptorsNeedRecheck = false; + + /* + * check for notifications + */ + if(level == 1 && NotificationManager::the()->pending()) + result = true; + + if(level == 1) + Dispatcher::unlock(); + + level--; + + return result; +} + +gboolean GIOManager::dispatch(GSourceFunc /* func */, gpointer /* user_data */) +{ + bool done = false; + + level++; + + if(level == 1) + Dispatcher::lock(); + + // notifications not carried out reentrant + if(!done && level == 1 && NotificationManager::the()->pending()) + { + NotificationManager::the()->run(); + done = true; + } + + // handle filedescriptor things + if(!done && !fileDescriptorsNeedRecheck) + { + list<GIOWatch *>::iterator i; + for(i = fdList.begin(); i != fdList.end(); i++) { + GIOWatch *w = *i; + int match = w->check(); + + if((w->types & IOType::reentrant) == 0 && level != 1) + { + arts_assert(match == 0); + } + if(match) + { + w->notify->notifyIO(w->gpollfd.fd,match); + done = true; + break; + } + } + } + + // handle timers - only at level 1 + if(!done && level == 1 && timeList.size()) + { + struct timeval currenttime; + gettimeofday(¤ttime,0); + + list<GIOTimeWatch *>::iterator ti; + + ti = timeList.begin(); + while(ti != timeList.end()) + { + GIOTimeWatch *w = *ti++; + w->advance(currenttime); + } + } + + if(level == 1) + Dispatcher::unlock(); + level--; + + return true; +} diff --git a/gmcop/giomanager.h b/gmcop/giomanager.h new file mode 100644 index 0000000..4a398f8 --- /dev/null +++ b/gmcop/giomanager.h @@ -0,0 +1,128 @@ + /* + + Copyright (C) 2001 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. + + */ + +#ifndef ARTS_GIOMANAGER_H +#define ARTS_GIOMANAGER_H + +#include <glib.h> +#include <iomanager.h> +#include <list> +#include <stack> +#include <map> +#include "arts_export.h" +/* + * BC - Status (2002-03-08): GIOManager + * + * This class will be kept binary compatible (d ptr for extensions). + */ + +namespace Arts { + +class GIOWatch; +class GIOManagerPrivate; +struct GIOManagerSource; +class GIOTimeWatch; +class GIOManagerBlocking; + +/** + * GIOManager performs MCOP I/O inside the Glib event loop. This way, you will + * be able to receive requests and notifications inside Glib application. The + * usual way to set it up is: + * + * <pre> + * GMainLoop *main_loop = g_main_new(FALSE); // as usual + * + * Arts::GIOManager iomanager; + * Arts::Dispatcher dispatcher(&iomanager); + * + * g_main_run(main_loop); // as usual + * </pre> + */ +class ARTS_EXPORT GIOManager : public IOManager { +private: + GIOManagerPrivate *d; + +protected: + std::list<GIOWatch *> fdList; + std::list<GIOTimeWatch *> timeList; + int level; + bool _blocking; + bool fileDescriptorsNeedRecheck; + GMainContext *context; + GIOManagerSource *source; + GIOManagerBlocking *gioManagerBlocking; + +public: + GIOManager(GMainContext *context = 0); + ~GIOManager(); + + 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); + + /** + * This controls what GIOManager will do while waiting for the result + * of an MCOP request, the possibilities are: + * + * @li block until the request is completed (true) + * @li open a local event loop (false) + * + * It is much easier to write working and reliable code with blocking + * enabled, so this is the default. If you disable blocking, you have + * to deal with the fact that timers, user interaction and similar + * "unpredictable" things will possibly influence your code in all + * places where you make a remote MCOP call (which is quite often in + * MCOP applications). + */ + void setBlocking(bool blocking); + + /* GSource stuff: */ + + /** + * - internal - + * + * (implements the GSource prepare) + */ + gboolean prepare(gint *timeout); + + /** + * - internal - + * + * (implements the GSource check) + */ + gboolean check(); + + /** + * - internal - + * + * (implements the GSource dispatch) + */ + gboolean dispatch(GSourceFunc callback, gpointer user_data); +}; + +} + +#endif /* ARTS_GIOMANAGER_H */ |