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 #include <unistd.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::run() 00147 { 00148 _running = true; 00149 } 00150 00151 bool BusDispatcher::is_running() 00152 { 00153 return _running; 00154 } 00155 00156 void BusDispatcher::do_iteration() 00157 { 00158 dispatch_pending(); 00159 dispatch(); 00160 } 00161 00162 Timeout *BusDispatcher::add_timeout(Timeout::Internal *ti) 00163 { 00164 BusTimeout *bt = new BusTimeout(ti, this); 00165 00166 bt->expired = new Callback<BusDispatcher, void, DefaultTimeout &>(this, &BusDispatcher::timeout_expired); 00167 bt->data(bt); 00168 00169 debug_log("added timeout %p (%s) (%d millies)", 00170 bt, 00171 ((Timeout *)bt)->enabled() ? "on" : "off", 00172 ((Timeout *)bt)->interval() 00173 ); 00174 00175 return bt; 00176 } 00177 00178 void BusDispatcher::rem_timeout(Timeout *t) 00179 { 00180 debug_log("removed timeout %p", t); 00181 00182 delete t; 00183 } 00184 00185 Watch *BusDispatcher::add_watch(Watch::Internal *wi) 00186 { 00187 BusWatch *bw = new BusWatch(wi, this); 00188 00189 bw->ready = new Callback<BusDispatcher, void, DefaultWatch &>(this, &BusDispatcher::watch_ready); 00190 bw->data(bw); 00191 00192 debug_log("added watch %p (%s) fd=%d flags=%d", 00193 bw, ((Watch *)bw)->enabled() ? "on" : "off", ((Watch *)bw)->descriptor(), ((Watch *)bw)->flags()); 00194 00195 return bw; 00196 } 00197 00198 void BusDispatcher::rem_watch(Watch *w) 00199 { 00200 debug_log("removed watch %p", w); 00201 00202 delete w; 00203 } 00204 00205 void BusDispatcher::timeout_expired(DefaultTimeout &et) 00206 { 00207 debug_log("timeout %p expired", &et); 00208 00209 BusTimeout *timeout = reinterpret_cast<BusTimeout *>(et.data()); 00210 00211 timeout->handle(); 00212 } 00213 00214 void BusDispatcher::watch_ready(DefaultWatch &ew) 00215 { 00216 BusWatch *watch = reinterpret_cast<BusWatch *>(ew.data()); 00217 00218 debug_log("watch %p ready, flags=%d state=%d", 00219 watch, ((Watch *)watch)->flags(), watch->state() 00220 ); 00221 00222 int flags = 0; 00223 00224 if (watch->state() & POLLIN) 00225 flags |= DBUS_WATCH_READABLE; 00226 if (watch->state() & POLLOUT) 00227 flags |= DBUS_WATCH_WRITABLE; 00228 if (watch->state() & POLLHUP) 00229 flags |= DBUS_WATCH_HANGUP; 00230 if (watch->state() & POLLERR) 00231 flags |= DBUS_WATCH_ERROR; 00232 00233 watch->handle(flags); 00234 } 00235