1 /*
2 *
3 * D-Bus++ - C++ bindings for D-Bus
4 *
5 * Copyright (C) 2005-2007 Paolo Durante <shackan@gmail.com>
6 *
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <dbus-c++/eventloop.h>
29 #include <dbus-c++/debug.h>
30
31 #include <sys/poll.h>
32 #include <sys/time.h>
33
34 #include <dbus/dbus.h>
35
36 using namespace DBus;
37 using namespace std;
38
millis(timeval tv)39 static double millis(timeval tv)
40 {
41 return (tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0);
42 }
43
DefaultTimeout(int interval,bool repeat,DefaultMainLoop * ed)44 DefaultTimeout::DefaultTimeout(int interval, bool repeat, DefaultMainLoop *ed)
45 : _enabled(true), _interval(interval), _repeat(repeat), _expiration(0), _data(0), _disp(ed)
46 {
47 timeval now;
48 gettimeofday(&now, NULL);
49
50 _expiration = millis(now) + interval;
51
52 _disp->_mutex_t.lock();
53 _disp->_timeouts.push_back(this);
54 _disp->_mutex_t.unlock();
55 }
56
~DefaultTimeout()57 DefaultTimeout::~DefaultTimeout()
58 {
59 _disp->_mutex_t.lock();
60 _disp->_timeouts.remove(this);
61 _disp->_mutex_t.unlock();
62 }
63
DefaultWatch(int fd,int flags,DefaultMainLoop * ed)64 DefaultWatch::DefaultWatch(int fd, int flags, DefaultMainLoop *ed)
65 : _enabled(true), _fd(fd), _flags(flags), _state(0), _data(0), _disp(ed)
66 {
67 _disp->_mutex_w.lock();
68 _disp->_watches.push_back(this);
69 _disp->_mutex_w.unlock();
70 }
71
~DefaultWatch()72 DefaultWatch::~DefaultWatch()
73 {
74 _disp->_mutex_w.lock();
75 _disp->_watches.remove(this);
76 _disp->_mutex_w.unlock();
77 }
78
DefaultMutex()79 DefaultMutex::DefaultMutex()
80 {
81 pthread_mutex_init(&_mutex, NULL);
82 }
83
DefaultMutex(bool recursive)84 DefaultMutex::DefaultMutex(bool recursive)
85 {
86 if (recursive)
87 {
88 pthread_mutexattr_t attr;
89
90 pthread_mutexattr_init(&attr);
91 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
92 pthread_mutex_init(&_mutex, &attr);
93 }
94 else
95 {
96 pthread_mutex_init(&_mutex, NULL);
97 }
98 }
99
~DefaultMutex()100 DefaultMutex::~DefaultMutex()
101 {
102 pthread_mutex_destroy(&_mutex);
103 }
104
lock()105 void DefaultMutex::lock()
106 {
107 pthread_mutex_lock(&_mutex);
108 }
109
unlock()110 void DefaultMutex::unlock()
111 {
112 pthread_mutex_unlock(&_mutex);
113 }
114
DefaultMainLoop()115 DefaultMainLoop::DefaultMainLoop() :
116 _mutex_w(true)
117 {
118 }
119
~DefaultMainLoop()120 DefaultMainLoop::~DefaultMainLoop()
121 {
122 _mutex_w.lock();
123
124 DefaultWatches::iterator wi = _watches.begin();
125 while (wi != _watches.end())
126 {
127 DefaultWatches::iterator wmp = wi;
128 ++wmp;
129 _mutex_w.unlock();
130 delete(*wi);
131 _mutex_w.lock();
132 wi = wmp;
133 }
134 _mutex_w.unlock();
135
136 _mutex_t.lock();
137
138 DefaultTimeouts::iterator ti = _timeouts.begin();
139 while (ti != _timeouts.end())
140 {
141 DefaultTimeouts::iterator tmp = ti;
142 ++tmp;
143 _mutex_t.unlock();
144 delete(*ti);
145 _mutex_t.lock();
146 ti = tmp;
147 }
148 _mutex_t.unlock();
149 }
150
dispatch()151 void DefaultMainLoop::dispatch()
152 {
153 _mutex_w.lock();
154
155 int nfd = _watches.size();
156
157 if (_fdunlock)
158 {
159 nfd = nfd + 2;
160 }
161
162 pollfd fds[nfd];
163
164 DefaultWatches::iterator wi = _watches.begin();
165
166 for (nfd = 0; wi != _watches.end(); ++wi)
167 {
168 if ((*wi)->enabled())
169 {
170 fds[nfd].fd = (*wi)->descriptor();
171 fds[nfd].events = (*wi)->flags();
172 fds[nfd].revents = 0;
173
174 ++nfd;
175 }
176 }
177
178 if (_fdunlock)
179 {
180 fds[nfd].fd = _fdunlock[0];
181 fds[nfd].events = POLLIN | POLLOUT | POLLPRI ;
182 fds[nfd].revents = 0;
183
184 nfd++;
185 fds[nfd].fd = _fdunlock[1];
186 fds[nfd].events = POLLIN | POLLOUT | POLLPRI ;
187 fds[nfd].revents = 0;
188 }
189
190 _mutex_w.unlock();
191
192 int wait_min = 10000;
193
194 DefaultTimeouts::iterator ti;
195
196 _mutex_t.lock();
197
198 for (ti = _timeouts.begin(); ti != _timeouts.end(); ++ti)
199 {
200 if ((*ti)->enabled() && (*ti)->interval() < wait_min)
201 wait_min = (*ti)->interval();
202 }
203
204 _mutex_t.unlock();
205
206 poll(fds, nfd, wait_min);
207
208 timeval now;
209 gettimeofday(&now, NULL);
210
211 double now_millis = millis(now);
212
213 _mutex_t.lock();
214
215 ti = _timeouts.begin();
216
217 while (ti != _timeouts.end())
218 {
219 DefaultTimeouts::iterator tmp = ti;
220 ++tmp;
221
222 if ((*ti)->enabled() && now_millis >= (*ti)->_expiration)
223 {
224 (*ti)->expired(*(*ti));
225
226 if ((*ti)->_repeat)
227 {
228 (*ti)->_expiration = now_millis + (*ti)->_interval;
229 }
230
231 }
232
233 ti = tmp;
234 }
235
236 _mutex_t.unlock();
237
238 _mutex_w.lock();
239
240 for (int j = 0; j < nfd; ++j)
241 {
242 DefaultWatches::iterator wi;
243
244 for (wi = _watches.begin(); wi != _watches.end();)
245 {
246 DefaultWatches::iterator tmp = wi;
247 ++tmp;
248
249 if ((*wi)->enabled() && (*wi)->_fd == fds[j].fd)
250 {
251 if (fds[j].revents)
252 {
253 (*wi)->_state = fds[j].revents;
254
255 (*wi)->ready(*(*wi));
256
257 fds[j].revents = 0;
258 }
259 }
260
261 wi = tmp;
262 }
263 }
264 _mutex_w.unlock();
265 }
266
267