| /* |
| * |
| * D-Bus++ - C++ bindings for D-Bus |
| * |
| * Copyright (C) 2005-2007 Paolo Durante <[email protected]> |
| * |
| * |
| * 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() |
| { |
| } |
| |
| 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) |
| { |
| 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){ |
| 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(); |
| } |
| |