eventloop-integration.cpp

Go to the documentation of this file.
00001 /*
00002  *
00003  *  D-Bus++ - C++ bindings for D-Bus
00004  *
00005  *  Copyright (C) 2005-2007  Paolo Durante <shackan@gmail.com>
00006  *
00007  *
00008  *  This library is free software; you can redistribute it and/or
00009  *  modify it under the terms of the GNU Lesser General Public
00010  *  License as published by the Free Software Foundation; either
00011  *  version 2.1 of the License, or (at your option) any later version.
00012  *
00013  *  This library is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  *  Lesser General Public License for more details.
00017  *
00018  *  You should have received a copy of the GNU Lesser General Public
00019  *  License along with this library; if not, write to the Free Software
00020  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 /* Project */
00029 #include <dbus-c++/eventloop-integration.h>
00030 #include <dbus-c++/debug.h>
00031 #include <dbus-c++/pipe.h>
00032 
00033 /* DBus */
00034 #include <dbus/dbus.h>
00035 
00036 /* STD */
00037 #include <string.h>
00038 #include <cassert>
00039 #include <sys/poll.h>
00040 #include <fcntl.h>
00041 
00042 using namespace DBus;
00043 using namespace std;
00044 
00045 BusTimeout::BusTimeout(Timeout::Internal *ti, BusDispatcher *bd)
00046   : Timeout(ti), DefaultTimeout(Timeout::interval(), true, bd)
00047 {
00048   DefaultTimeout::enabled(Timeout::enabled());
00049 }
00050 
00051 void BusTimeout::toggle()
00052 {
00053   debug_log("timeout %p toggled (%s)", this, Timeout::enabled() ? "on" : "off");
00054 
00055   DefaultTimeout::enabled(Timeout::enabled());
00056 }
00057 
00058 BusWatch::BusWatch(Watch::Internal *wi, BusDispatcher *bd)
00059   : Watch(wi), DefaultWatch(Watch::descriptor(), 0, bd)
00060 {
00061   int flags = POLLHUP | POLLERR;
00062 
00063   if (Watch::flags() & DBUS_WATCH_READABLE)
00064     flags |= POLLIN;
00065   if (Watch::flags() & DBUS_WATCH_WRITABLE)
00066     flags |= POLLOUT;
00067 
00068   DefaultWatch::flags(flags);
00069   DefaultWatch::enabled(Watch::enabled());
00070 }
00071 
00072 void BusWatch::toggle()
00073 {
00074   debug_log("watch %p toggled (%s)", this, Watch::enabled() ? "on" : "off");
00075 
00076   DefaultWatch::enabled(Watch::enabled());
00077 }
00078 
00079 BusDispatcher::BusDispatcher() :
00080   _running(false)
00081 {
00082   // pipe to create a new fd used to unlock a dispatcher at any
00083   // moment (used by leave function)
00084   int ret = pipe(_pipe);
00085   if (ret == -1) throw Error("PipeError:errno", toString(errno).c_str());
00086 
00087   _fdunlock[0] = _pipe[0];
00088   _fdunlock[1] = _pipe[1];
00089 }
00090 
00091 void BusDispatcher::enter()
00092 {
00093   debug_log("entering dispatcher %p", this);
00094 
00095   _running = true;
00096 
00097   while (_running)
00098   {
00099     do_iteration();
00100 
00101     for (std::list <Pipe *>::iterator p_it = pipe_list.begin();
00102          p_it != pipe_list.end();
00103          ++p_it)
00104     {
00105       Pipe *read_pipe = *p_it;
00106       char buffer[1024]; // TODO: should be max pipe size
00107       unsigned int nbytes = 0;
00108 
00109       while (read_pipe->read(buffer, nbytes) > 0)
00110       {
00111         read_pipe->_handler(read_pipe->_data, buffer, nbytes);
00112       }
00113 
00114     }
00115   }
00116 
00117   debug_log("leaving dispatcher %p", this);
00118 }
00119 
00120 void BusDispatcher::leave()
00121 {
00122   _running = false;
00123 
00124   int ret = write(_fdunlock[1], "exit", strlen("exit"));
00125   if (ret == -1) throw Error("WriteError:errno", toString(errno).c_str());
00126 
00127   close(_fdunlock[1]);
00128   close(_fdunlock[0]);
00129 }
00130 
00131 Pipe *BusDispatcher::add_pipe(void(*handler)(const void *data, void *buffer, unsigned int nbyte), const void *data)
00132 {
00133   Pipe *new_pipe = new Pipe(handler, data);
00134   pipe_list.push_back(new_pipe);
00135 
00136   return new_pipe;
00137 }
00138 
00139 void BusDispatcher::del_pipe(Pipe *pipe)
00140 {
00141   pipe_list.remove(pipe);
00142   delete pipe;
00143 }
00144 
00145 void BusDispatcher::do_iteration()
00146 {
00147   dispatch_pending();
00148   dispatch();
00149 }
00150 
00151 Timeout *BusDispatcher::add_timeout(Timeout::Internal *ti)
00152 {
00153   BusTimeout *bt = new BusTimeout(ti, this);
00154 
00155   bt->expired = new Callback<BusDispatcher, void, DefaultTimeout &>(this, &BusDispatcher::timeout_expired);
00156   bt->data(bt);
00157 
00158   debug_log("added timeout %p (%s) (%d millies)",
00159             bt,
00160             ((Timeout *)bt)->enabled() ? "on" : "off",
00161             ((Timeout *)bt)->interval()
00162            );
00163 
00164   return bt;
00165 }
00166 
00167 void BusDispatcher::rem_timeout(Timeout *t)
00168 {
00169   debug_log("removed timeout %p", t);
00170 
00171   delete t;
00172 }
00173 
00174 Watch *BusDispatcher::add_watch(Watch::Internal *wi)
00175 {
00176   BusWatch *bw = new BusWatch(wi, this);
00177 
00178   bw->ready = new Callback<BusDispatcher, void, DefaultWatch &>(this, &BusDispatcher::watch_ready);
00179   bw->data(bw);
00180 
00181   debug_log("added watch %p (%s) fd=%d flags=%d",
00182             bw, ((Watch *)bw)->enabled() ? "on" : "off", ((Watch *)bw)->descriptor(), ((Watch *)bw)->flags());
00183 
00184   return bw;
00185 }
00186 
00187 void BusDispatcher::rem_watch(Watch *w)
00188 {
00189   debug_log("removed watch %p", w);
00190 
00191   delete w;
00192 }
00193 
00194 void BusDispatcher::timeout_expired(DefaultTimeout &et)
00195 {
00196   debug_log("timeout %p expired", &et);
00197 
00198   BusTimeout *timeout = reinterpret_cast<BusTimeout *>(et.data());
00199 
00200   timeout->handle();
00201 }
00202 
00203 void BusDispatcher::watch_ready(DefaultWatch &ew)
00204 {
00205   BusWatch *watch = reinterpret_cast<BusWatch *>(ew.data());
00206 
00207   debug_log("watch %p ready, flags=%d state=%d",
00208             watch, ((Watch *)watch)->flags(), watch->state()
00209            );
00210 
00211   int flags = 0;
00212 
00213   if (watch->state() & POLLIN)
00214     flags |= DBUS_WATCH_READABLE;
00215   if (watch->state() & POLLOUT)
00216     flags |= DBUS_WATCH_WRITABLE;
00217   if (watch->state() & POLLHUP)
00218     flags |= DBUS_WATCH_HANGUP;
00219   if (watch->state() & POLLERR)
00220     flags |= DBUS_WATCH_ERROR;
00221 
00222   watch->handle(flags);
00223 }
00224