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