dispatcher.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 #include <dbus-c++/dispatcher.h>
00029 
00030 #include <dbus/dbus.h>
00031 
00032 #include "dispatcher_p.h"
00033 #include "server_p.h"
00034 #include "connection_p.h"
00035 
00036 DBus::Dispatcher *DBus::default_dispatcher = NULL;
00037 
00038 using namespace DBus;
00039 
00040 Timeout::Timeout(Timeout::Internal *i)
00041   : _int(i)
00042 {
00043   dbus_timeout_set_data((DBusTimeout *)i, this, NULL);
00044 }
00045 
00046 int Timeout::interval() const
00047 {
00048   return dbus_timeout_get_interval((DBusTimeout *)_int);
00049 }
00050 
00051 bool Timeout::enabled() const
00052 {
00053   return dbus_timeout_get_enabled((DBusTimeout *)_int);
00054 }
00055 
00056 bool Timeout::handle()
00057 {
00058   return dbus_timeout_handle((DBusTimeout *)_int);
00059 }
00060 
00061 /*
00062 */
00063 
00064 Watch::Watch(Watch::Internal *i)
00065   : _int(i)
00066 {
00067   dbus_watch_set_data((DBusWatch *)i, this, NULL);
00068 }
00069 
00070 int Watch::descriptor() const
00071 {
00072 #if HAVE_WIN32
00073   return dbus_watch_get_socket((DBusWatch *)_int);
00074 #else
00075   // check dbus version and use dbus_watch_get_unix_fd() only in dbus >= 1.1.1
00076 #if (DBUS_VERSION_MAJOR == 1 && DBUS_VERSION_MINOR == 1 && DBUS_VERSION_MICRO >= 1) || \
00077     (DBUS_VERSION_MAJOR == 1 && DBUS_VERSION_MAJOR > 1) || \
00078     (DBUS_VERSION_MAJOR > 1)
00079   return dbus_watch_get_unix_fd((DBusWatch *)_int);
00080 #else
00081   return dbus_watch_get_fd((DBusWatch *)_int);
00082 #endif
00083 #endif
00084 }
00085 
00086 int Watch::flags() const
00087 {
00088   return dbus_watch_get_flags((DBusWatch *)_int);
00089 }
00090 
00091 bool Watch::enabled() const
00092 {
00093   return dbus_watch_get_enabled((DBusWatch *)_int);
00094 }
00095 
00096 bool Watch::handle(int flags)
00097 {
00098   return dbus_watch_handle((DBusWatch *)_int, flags);
00099 }
00100 
00101 /*
00102 */
00103 
00104 dbus_bool_t Dispatcher::Private::on_add_watch(DBusWatch *watch, void *data)
00105 {
00106   Dispatcher *d = static_cast<Dispatcher *>(data);
00107 
00108   Watch::Internal *w = reinterpret_cast<Watch::Internal *>(watch);
00109 
00110   d->add_watch(w);
00111 
00112   return true;
00113 }
00114 
00115 void Dispatcher::Private::on_rem_watch(DBusWatch *watch, void *data)
00116 {
00117   Dispatcher *d = static_cast<Dispatcher *>(data);
00118 
00119   Watch *w = static_cast<Watch *>(dbus_watch_get_data(watch));
00120 
00121   d->rem_watch(w);
00122 }
00123 
00124 void Dispatcher::Private::on_toggle_watch(DBusWatch *watch, void *data)
00125 {
00126   Watch *w = static_cast<Watch *>(dbus_watch_get_data(watch));
00127 
00128   w->toggle();
00129 }
00130 
00131 dbus_bool_t Dispatcher::Private::on_add_timeout(DBusTimeout *timeout, void *data)
00132 {
00133   Dispatcher *d = static_cast<Dispatcher *>(data);
00134 
00135   Timeout::Internal *t = reinterpret_cast<Timeout::Internal *>(timeout);
00136 
00137   d->add_timeout(t);
00138 
00139   return true;
00140 }
00141 
00142 void Dispatcher::Private::on_rem_timeout(DBusTimeout *timeout, void *data)
00143 {
00144   Dispatcher *d = static_cast<Dispatcher *>(data);
00145 
00146   Timeout *t = static_cast<Timeout *>(dbus_timeout_get_data(timeout));
00147 
00148   d->rem_timeout(t);
00149 }
00150 
00151 void Dispatcher::Private::on_toggle_timeout(DBusTimeout *timeout, void *data)
00152 {
00153   Timeout *t = static_cast<Timeout *>(dbus_timeout_get_data(timeout));
00154 
00155   t->toggle();
00156 }
00157 
00158 void Dispatcher::queue_connection(Connection::Private *cp)
00159 {
00160   _mutex_p.lock();
00161   _pending_queue.push_back(cp);
00162   _mutex_p.unlock();
00163 }
00164 
00165 
00166 bool Dispatcher::has_something_to_dispatch()
00167 {
00168   _mutex_p.lock();
00169   bool has_something = false;
00170   for (Connection::PrivatePList::iterator it = _pending_queue.begin();
00171        it != _pending_queue.end() && !has_something;
00172        ++it)
00173   {
00174     has_something = (*it)->has_something_to_dispatch();
00175   }
00176 
00177   _mutex_p.unlock();
00178   return has_something;
00179 }
00180 
00181 
00182 void Dispatcher::dispatch_pending()
00183 {
00184   while (1)
00185   {
00186     _mutex_p.lock();
00187     if (_pending_queue.empty())
00188     {
00189       _mutex_p.unlock();
00190       break;
00191     }
00192 
00193     Connection::PrivatePList pending_queue_copy(_pending_queue);
00194     _mutex_p.unlock();
00195 
00196     size_t copy_elem_num(pending_queue_copy.size());
00197 
00198     dispatch_pending(pending_queue_copy);
00199 
00200     //only push_back on list is mandatory!
00201     _mutex_p.lock();
00202 
00203     Connection::PrivatePList::iterator i, j;
00204     i = _pending_queue.begin();
00205     size_t counter = 0;
00206     while (counter < copy_elem_num && i != _pending_queue.end())
00207     {
00208       j = i;
00209       ++j;
00210       _pending_queue.erase(i);
00211       i = j;
00212       ++counter;
00213     }
00214 
00215     _mutex_p.unlock();
00216   }
00217 }
00218 
00219 void Dispatcher::dispatch_pending(Connection::PrivatePList &pending_queue)
00220 {
00221   // SEEME: dbus-glib is dispatching only one message at a time to not starve the loop/other things...
00222 
00223   _mutex_p_copy.lock();
00224   while (pending_queue.size() > 0)
00225   {
00226     Connection::PrivatePList::iterator i, j;
00227 
00228     i = pending_queue.begin();
00229 
00230     while (i != pending_queue.end())
00231     {
00232       j = i;
00233 
00234       ++j;
00235 
00236       if ((*i)->do_dispatch())
00237         pending_queue.erase(i);
00238       else
00239         debug_log("dispatch_pending_private: do_dispatch error");
00240 
00241       i = j;
00242     }
00243   }
00244   _mutex_p_copy.unlock();
00245 }
00246 
00247 void DBus::_init_threading()
00248 {
00249 #ifdef DBUS_HAS_THREADS_INIT_DEFAULT
00250   dbus_threads_init_default();
00251 #else
00252   debug_log("Thread support is not enabled! Your D-Bus version is too old!");
00253 #endif//DBUS_HAS_THREADS_INIT_DEFAULT
00254 }
00255 
00256 void DBus::_init_threading(
00257   MutexNewFn m1,
00258   MutexFreeFn m2,
00259   MutexLockFn m3,
00260   MutexUnlockFn m4,
00261   CondVarNewFn c1,
00262   CondVarFreeFn c2,
00263   CondVarWaitFn c3,
00264   CondVarWaitTimeoutFn c4,
00265   CondVarWakeOneFn c5,
00266   CondVarWakeAllFn c6
00267 )
00268 {
00269 #ifndef DBUS_HAS_RECURSIVE_MUTEX
00270   DBusThreadFunctions functions =
00271   {
00272     DBUS_THREAD_FUNCTIONS_MUTEX_NEW_MASK |
00273     DBUS_THREAD_FUNCTIONS_MUTEX_FREE_MASK |
00274     DBUS_THREAD_FUNCTIONS_MUTEX_LOCK_MASK |
00275     DBUS_THREAD_FUNCTIONS_MUTEX_UNLOCK_MASK |
00276     DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
00277     DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
00278     DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
00279     DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
00280     DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK |
00281     DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
00282     (DBusMutexNewFunction) m1,
00283     (DBusMutexFreeFunction) m2,
00284     (DBusMutexLockFunction) m3,
00285     (DBusMutexUnlockFunction) m4,
00286     (DBusCondVarNewFunction) c1,
00287     (DBusCondVarFreeFunction) c2,
00288     (DBusCondVarWaitFunction) c3,
00289     (DBusCondVarWaitTimeoutFunction) c4,
00290     (DBusCondVarWakeOneFunction) c5,
00291     (DBusCondVarWakeAllFunction) c6
00292   };
00293 #else
00294   DBusThreadFunctions functions =
00295   {
00296     DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_NEW_MASK |
00297     DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_FREE_MASK |
00298     DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_LOCK_MASK |
00299     DBUS_THREAD_FUNCTIONS_RECURSIVE_MUTEX_UNLOCK_MASK |
00300     DBUS_THREAD_FUNCTIONS_CONDVAR_NEW_MASK |
00301     DBUS_THREAD_FUNCTIONS_CONDVAR_FREE_MASK |
00302     DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_MASK |
00303     DBUS_THREAD_FUNCTIONS_CONDVAR_WAIT_TIMEOUT_MASK |
00304     DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ONE_MASK |
00305     DBUS_THREAD_FUNCTIONS_CONDVAR_WAKE_ALL_MASK,
00306     0, 0, 0, 0,
00307     (DBusCondVarNewFunction) c1,
00308     (DBusCondVarFreeFunction) c2,
00309     (DBusCondVarWaitFunction) c3,
00310     (DBusCondVarWaitTimeoutFunction) c4,
00311     (DBusCondVarWakeOneFunction) c5,
00312     (DBusCondVarWakeAllFunction) c6,
00313     (DBusRecursiveMutexNewFunction) m1,
00314     (DBusRecursiveMutexFreeFunction) m2,
00315     (DBusRecursiveMutexLockFunction) m3,
00316     (DBusRecursiveMutexUnlockFunction) m4
00317   };
00318 #endif//DBUS_HAS_RECURSIVE_MUTEX
00319   dbus_threads_init(&functions);
00320 }