summaryrefslogtreecommitdiffstats
path: root/gmcop
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-05 00:01:18 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-05 00:01:18 +0000
commit42995d7bf396933ee60c5f89c354ea89cf13df0d (patch)
treecfdcea0ac57420e7baf570bfe435e107bb842541 /gmcop
downloadarts-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.am10
-rw-r--r--gmcop/giomanager.cc506
-rw-r--r--gmcop/giomanager.h128
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(&currenttime,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(&currenttime,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(&currenttime,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 */