blob: 81861f07ee5eb840667320b4e17b068527202d1d [file] [log] [blame]
/*
*
* D-Bus++ - C++ bindings for D-Bus
*
* Copyright (C) 2005-2007 Paolo Durante <shackan@gmail.com>
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <cassert>
#include <errno.h>
#include <dbus-c++/eventloop.h>
#include <dbus-c++/debug.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <dbus/dbus.h>
using namespace DBus;
static double millis(timeval tv)
{
return (tv.tv_sec *1000.0 + tv.tv_usec/1000.0);
}
DefaultTimeout::DefaultTimeout(int interval, bool repeat, DefaultMainLoop *ed)
: _enabled(true), _interval(interval), _repeat(repeat), _expiration(0), _data(0), _disp(ed)
{
timeval now;
gettimeofday(&now, NULL);
_expiration = millis(now) + interval;
_disp->_mutex_t.lock();
_disp->_timeouts.push_back(this);
_disp->_mutex_t.unlock();
}
DefaultTimeout::~DefaultTimeout()
{
_disp->_mutex_t.lock();
_disp->_timeouts.remove(this);
_disp->_mutex_t.unlock();
}
DefaultWatch::DefaultWatch(int fd, int flags, DefaultMainLoop *ed)
: _enabled(true), _fd(fd), _flags(flags), _state(0), _data(0), _disp(ed)
{
_disp->_mutex_w.lock();
_disp->_watches.push_back(this);
_disp->_mutex_w.unlock();
}
DefaultWatch::~DefaultWatch()
{
_disp->_mutex_w.lock();
_disp->_watches.remove(this);
_disp->_mutex_w.unlock();
}
DefaultMutex::DefaultMutex()
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
pthread_mutex_init(&_mutex, &attr);
}
DefaultMutex::~DefaultMutex()
{
pthread_mutex_destroy(&_mutex);
}
void DefaultMutex::lock()
{
int r = pthread_mutex_lock(&_mutex);
/* This assert is here to avoid a difficult-to-diagnose deadlock. See
* crosbug.com/8486 and crosbug.com/8596. */
assert(r != EDEADLK);
}
void DefaultMutex::unlock()
{
pthread_mutex_unlock(&_mutex);
}
DefaultMainLoop::DefaultMainLoop()
{
_fdunlock[0] = -1;
_fdunlock[1] = -1;
}
DefaultMainLoop::~DefaultMainLoop()
{
_mutex_w.lock();
DefaultWatches::iterator wi = _watches.begin();
while (wi != _watches.end())
{
DefaultWatches::iterator wmp = wi;
++wmp;
_mutex_w.unlock();
delete (*wi);
_mutex_w.lock();
wi = wmp;
}
_mutex_w.unlock();
_mutex_t.lock();
DefaultTimeouts::iterator ti = _timeouts.begin();
while (ti != _timeouts.end())
{
DefaultTimeouts::iterator tmp = ti;
++tmp;
_mutex_t.unlock();
delete (*ti);
_mutex_t.lock();
ti = tmp;
}
_mutex_t.unlock();
}
void DefaultMainLoop::dispatch()
{
_mutex_w.lock();
int nfd = _watches.size();
if (_fdunlock[0] >= 0 && _fdunlock[1] >= 0)
{
nfd=nfd+2;
}
pollfd fds[nfd];
DefaultWatches::iterator wi = _watches.begin();
for (nfd = 0; wi != _watches.end(); ++wi)
{
if ((*wi)->enabled())
{
fds[nfd].fd = (*wi)->descriptor();
fds[nfd].events = (*wi)->flags();
fds[nfd].revents = 0;
++nfd;
}
}
if (_fdunlock[0] >= 0 && _fdunlock[1] >= 0)
{
fds[nfd].fd = _fdunlock[0];
fds[nfd].events = POLLIN | POLLOUT | POLLPRI ;
fds[nfd].revents = 0;
nfd++;
fds[nfd].fd = _fdunlock[1];
fds[nfd].events = POLLIN | POLLOUT | POLLPRI ;
fds[nfd].revents = 0;
}
_mutex_w.unlock();
int wait_min = -1;
DefaultTimeouts::iterator ti;
_mutex_t.lock();
for (ti = _timeouts.begin(); ti != _timeouts.end(); ++ti)
{
if (((*ti)->enabled() && (*ti)->interval() < wait_min) || (wait_min < 0))
wait_min = (*ti)->interval();
}
_mutex_t.unlock();
poll(fds, nfd, wait_min);
timeval now;
gettimeofday(&now, NULL);
double now_millis = millis(now);
_mutex_t.lock();
ti = _timeouts.begin();
while (ti != _timeouts.end())
{
DefaultTimeouts::iterator tmp = ti;
++tmp;
if ((*ti)->enabled() && now_millis >= (*ti)->_expiration)
{
(*ti)->expired(*(*ti));
if ((*ti)->_repeat)
{
(*ti)->_expiration = now_millis + (*ti)->_interval;
}
}
ti = tmp;
}
_mutex_t.unlock();
_mutex_w.lock();
for (int j = 0; j < nfd; ++j)
{
DefaultWatches::iterator wi;
for (wi = _watches.begin(); wi != _watches.end();)
{
DefaultWatches::iterator tmp = wi;
++tmp;
if ((*wi)->enabled() && (*wi)->_fd == fds[j].fd)
{
if (fds[j].revents)
{
(*wi)->_state = fds[j].revents;
(*wi)->ready(*(*wi));
fds[j].revents = 0;
}
}
wi = tmp;
}
}
_mutex_w.unlock();
}