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