blob: 9fd0581ec3d93edd485a140fb82ab4da54888f89 [file] [log] [blame]
Emeric Vigier2f625822012-08-06 11:09:52 -04001/*
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
36using namespace DBus;
37using namespace std;
38
39static double millis(timeval tv)
40{
41 return (tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0);
42}
43
44DefaultTimeout::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
57DefaultTimeout::~DefaultTimeout()
58{
59 _disp->_mutex_t.lock();
60 _disp->_timeouts.remove(this);
61 _disp->_mutex_t.unlock();
62}
63
64DefaultWatch::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
72DefaultWatch::~DefaultWatch()
73{
74 _disp->_mutex_w.lock();
75 _disp->_watches.remove(this);
76 _disp->_mutex_w.unlock();
77}
78
79DefaultMutex::DefaultMutex()
80{
81 pthread_mutex_init(&_mutex, NULL);
82}
83
84DefaultMutex::DefaultMutex(bool recursive)
85{
86 if (recursive)
87 {
88 /* FIXME PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP */
89 pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
90 _mutex = recmutex;
91 }
92 else
93 {
94 pthread_mutex_init(&_mutex, NULL);
95 }
96}
97
98DefaultMutex::~DefaultMutex()
99{
100 pthread_mutex_destroy(&_mutex);
101}
102
103void DefaultMutex::lock()
104{
105 pthread_mutex_lock(&_mutex);
106}
107
108void DefaultMutex::unlock()
109{
110 pthread_mutex_unlock(&_mutex);
111}
112
113DefaultMainLoop::DefaultMainLoop() :
114 _mutex_w(true)
115{
116}
117
118DefaultMainLoop::~DefaultMainLoop()
119{
120 _mutex_w.lock();
121
122 DefaultWatches::iterator wi = _watches.begin();
123 while (wi != _watches.end())
124 {
125 DefaultWatches::iterator wmp = wi;
126 ++wmp;
127 _mutex_w.unlock();
128 delete(*wi);
129 _mutex_w.lock();
130 wi = wmp;
131 }
132 _mutex_w.unlock();
133
134 _mutex_t.lock();
135
136 DefaultTimeouts::iterator ti = _timeouts.begin();
137 while (ti != _timeouts.end())
138 {
139 DefaultTimeouts::iterator tmp = ti;
140 ++tmp;
141 _mutex_t.unlock();
142 delete(*ti);
143 _mutex_t.lock();
144 ti = tmp;
145 }
146 _mutex_t.unlock();
147}
148
149void DefaultMainLoop::dispatch()
150{
151 _mutex_w.lock();
152
153 int nfd = _watches.size();
154
155 if (_fdunlock)
156 {
157 nfd = nfd + 2;
158 }
159
160 pollfd fds[nfd];
161
162 DefaultWatches::iterator wi = _watches.begin();
163
164 for (nfd = 0; wi != _watches.end(); ++wi)
165 {
166 if ((*wi)->enabled())
167 {
168 fds[nfd].fd = (*wi)->descriptor();
169 fds[nfd].events = (*wi)->flags();
170 fds[nfd].revents = 0;
171
172 ++nfd;
173 }
174 }
175
176 if (_fdunlock)
177 {
178 fds[nfd].fd = _fdunlock[0];
179 fds[nfd].events = POLLIN | POLLOUT | POLLPRI ;
180 fds[nfd].revents = 0;
181
182 nfd++;
183 fds[nfd].fd = _fdunlock[1];
184 fds[nfd].events = POLLIN | POLLOUT | POLLPRI ;
185 fds[nfd].revents = 0;
186 }
187
188 _mutex_w.unlock();
189
190 int wait_min = 10000;
191
192 DefaultTimeouts::iterator ti;
193
194 _mutex_t.lock();
195
196 for (ti = _timeouts.begin(); ti != _timeouts.end(); ++ti)
197 {
198 if ((*ti)->enabled() && (*ti)->interval() < wait_min)
199 wait_min = (*ti)->interval();
200 }
201
202 _mutex_t.unlock();
203
204 poll(fds, nfd, wait_min);
205
206 timeval now;
207 gettimeofday(&now, NULL);
208
209 double now_millis = millis(now);
210
211 _mutex_t.lock();
212
213 ti = _timeouts.begin();
214
215 while (ti != _timeouts.end())
216 {
217 DefaultTimeouts::iterator tmp = ti;
218 ++tmp;
219
220 if ((*ti)->enabled() && now_millis >= (*ti)->_expiration)
221 {
222 (*ti)->expired(*(*ti));
223
224 if ((*ti)->_repeat)
225 {
226 (*ti)->_expiration = now_millis + (*ti)->_interval;
227 }
228
229 }
230
231 ti = tmp;
232 }
233
234 _mutex_t.unlock();
235
236 _mutex_w.lock();
237
238 for (int j = 0; j < nfd; ++j)
239 {
240 DefaultWatches::iterator wi;
241
242 for (wi = _watches.begin(); wi != _watches.end();)
243 {
244 DefaultWatches::iterator tmp = wi;
245 ++tmp;
246
247 if ((*wi)->enabled() && (*wi)->_fd == fds[j].fd)
248 {
249 if (fds[j].revents)
250 {
251 (*wi)->_state = fds[j].revents;
252
253 (*wi)->ready(*(*wi));
254
255 fds[j].revents = 0;
256 }
257 }
258
259 wi = tmp;
260 }
261 }
262 _mutex_w.unlock();
263}
264