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 <unistd.h>
00038 #include <string.h>
00039 #include <cassert>
00040 #include <sys/poll.h>
00041 #include <fcntl.h>
00042 
00043 using namespace DBus;
00044 using namespace std;
00045 
00046 BusTimeout::BusTimeout(Timeout::Internal *ti, BusDispatcher *bd)
00047   : Timeout(ti), DefaultTimeout(Timeout::interval(), true, bd)
00048 {
00049   DefaultTimeout::enabled(Timeout::enabled());
00050 }
00051 
00052 void BusTimeout::toggle()
00053 {
00054   debug_log("timeout %p toggled (%s)", this, Timeout::enabled() ? "on" : "off");
00055 
00056   DefaultTimeout::enabled(Timeout::enabled());
00057 }
00058 
00059 BusWatch::BusWatch(Watch::Internal *wi, BusDispatcher *bd)
00060   : Watch(wi), DefaultWatch(Watch::descriptor(), 0, bd)
00061 {
00062   int flags = POLLHUP | POLLERR;
00063 
00064   if (Watch::flags() & DBUS_WATCH_READABLE)
00065     flags |= POLLIN;
00066   if (Watch::flags() & DBUS_WATCH_WRITABLE)
00067     flags |= POLLOUT;
00068 
00069   DefaultWatch::flags(flags);
00070   DefaultWatch::enabled(Watch::enabled());
00071 }
00072 
00073 void BusWatch::toggle()
00074 {
00075   debug_log("watch %p toggled (%s)", this, Watch::enabled() ? "on" : "off");
00076 
00077   DefaultWatch::enabled(Watch::enabled());
00078 }
00079 
00080 BusDispatcher::BusDispatcher() :
00081   _running(false)
00082 {
00083   // pipe to create a new fd used to unlock a dispatcher at any
00084   // moment (used by leave function)
00085   int ret = pipe(_pipe);
00086   if (ret == -1) throw Error("PipeError:errno", toString(errno).c_str());
00087 
00088   _fdunlock[0] = _pipe[0];
00089   _fdunlock[1] = _pipe[1];
00090 }
00091 
00092 void BusDispatcher::enter()
00093 {
00094   debug_log("entering dispatcher %p", this);
00095 
00096   _running = true;
00097 
00098   while (_running)
00099   {
00100     do_iteration();
00101 
00102     for (std::list <Pipe *>::iterator p_it = pipe_list.begin();
00103          p_it != pipe_list.end();
00104          ++p_it)
00105     {
00106       Pipe *read_pipe = *p_it;
00107       char buffer[1024]; // TODO: should be max pipe size
00108       unsigned int nbytes = 0;
00109 
00110       while (read_pipe->read(buffer, nbytes) > 0)
00111       {
00112         read_pipe->_handler(read_pipe->_data, buffer, nbytes);
00113       }
00114 
00115     }
00116   }
00117 
00118   debug_log("leaving dispatcher %p", this);
00119 }
00120 
00121 void BusDispatcher::leave()
00122 {
00123   _running = false;
00124 
00125   int ret = write(_fdunlock[1], "exit", strlen("exit"));
00126   if (ret == -1) throw Error("WriteError:errno", toString(errno).c_str());
00127 
00128   close(_fdunlock[1]);
00129   close(_fdunlock[0]);
00130 }
00131 
00132 Pipe *BusDispatcher::add_pipe(void(*handler)(const void *data, void *buffer, unsigned int nbyte), const void *data)
00133 {
00134   Pipe *new_pipe = new Pipe(handler, data);
00135   pipe_list.push_back(new_pipe);
00136 
00137   return new_pipe;
00138 }
00139 
00140 void BusDispatcher::del_pipe(Pipe *pipe)
00141 {
00142   pipe_list.remove(pipe);
00143   delete pipe;
00144 }
00145 
00146 void BusDispatcher::do_iteration()
00147 {
00148   dispatch_pending();
00149   dispatch();
00150 }
00151 
00152 Timeout *BusDispatcher::add_timeout(Timeout::Internal *ti)
00153 {
00154   BusTimeout *bt = new BusTimeout(ti, this);
00155 
00156   bt->expired = new Callback<BusDispatcher, void, DefaultTimeout &>(this, &BusDispatcher::timeout_expired);
00157   bt->data(bt);
00158 
00159   debug_log("added timeout %p (%s) (%d millies)",
00160             bt,
00161             ((Timeout *)bt)->enabled() ? "on" : "off",
00162             ((Timeout *)bt)->interval()
00163            );
00164 
00165   return bt;
00166 }
00167 
00168 void BusDispatcher::rem_timeout(Timeout *t)
00169 {
00170   debug_log("removed timeout %p", t);
00171 
00172   delete t;
00173 }
00174 
00175 Watch *BusDispatcher::add_watch(Watch::Internal *wi)
00176 {
00177   BusWatch *bw = new BusWatch(wi, this);
00178 
00179   bw->ready = new Callback<BusDispatcher, void, DefaultWatch &>(this, &BusDispatcher::watch_ready);
00180   bw->data(bw);
00181 
00182   debug_log("added watch %p (%s) fd=%d flags=%d",
00183             bw, ((Watch *)bw)->enabled() ? "on" : "off", ((Watch *)bw)->descriptor(), ((Watch *)bw)->flags());
00184 
00185   return bw;
00186 }
00187 
00188 void BusDispatcher::rem_watch(Watch *w)
00189 {
00190   debug_log("removed watch %p", w);
00191 
00192   delete w;
00193 }
00194 
00195 void BusDispatcher::timeout_expired(DefaultTimeout &et)
00196 {
00197   debug_log("timeout %p expired", &et);
00198 
00199   BusTimeout *timeout = reinterpret_cast<BusTimeout *>(et.data());
00200 
00201   timeout->handle();
00202 }
00203 
00204 void BusDispatcher::watch_ready(DefaultWatch &ew)
00205 {
00206   BusWatch *watch = reinterpret_cast<BusWatch *>(ew.data());
00207 
00208   debug_log("watch %p ready, flags=%d state=%d",
00209             watch, ((Watch *)watch)->flags(), watch->state()
00210            );
00211 
00212   int flags = 0;
00213 
00214   if (watch->state() & POLLIN)
00215     flags |= DBUS_WATCH_READABLE;
00216   if (watch->state() & POLLOUT)
00217     flags |= DBUS_WATCH_WRITABLE;
00218   if (watch->state() & POLLHUP)
00219     flags |= DBUS_WATCH_HANGUP;
00220   if (watch->state() & POLLERR)
00221     flags |= DBUS_WATCH_ERROR;
00222 
00223   watch->handle(flags);
00224 }
00225