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