D-Bus server: more flexible timeouts

Added priorities and proper tracking of "activated" state. The latter
depends on having the Timeout instance valid when the callback
returns, therefore the Server must delay the deletion of the instance
until the callback is done executing.

Priorities are needed to order different tasks in the PIM manager
correctly.

The "activated" state is something that the PIM manager needs to track
reliably, which had to be done by every callback. If a callback forgot
to do that, in the worst case this might have removed an entirely
unrelated source when the tag got reused in the meantime.
This commit is contained in:
Patrick Ohly 2013-02-25 21:23:48 +01:00
parent 44d9b2c989
commit 3c21df32e0
3 changed files with 38 additions and 7 deletions

View file

@ -274,7 +274,6 @@ void FullView::onIdle()
if (isQuiescent()) {
m_quiescenceSignal();
}
m_waitForIdle.deactivate();
}
void FullView::waitForIdle()

View file

@ -739,6 +739,10 @@ void Server::passwordResponse(const InfoReq::InfoMap &response,
bool Server::callTimeout(const boost::shared_ptr<Timeout> &timeout, const boost::function<void ()> &callback)
{
callback();
// We are executing the timeout, don't invalidate the instance
// until later when our caller is no longer using the instance to
// call us.
delayDeletion(timeout);
m_timeouts.remove(timeout);
return false;
}

View file

@ -48,6 +48,14 @@ class Timeout : boost::noncopyable
boost::function<bool ()> m_callback;
public:
enum {
PRIORITY_HIGH = G_PRIORITY_HIGH,
PRIORITY_DEFAULT = G_PRIORITY_DEFAULT,
PRIORITY_HIGH_IDLE = G_PRIORITY_HIGH_IDLE,
PRIORITY_DEFAULT_IDLE = G_PRIORITY_DEFAULT_IDLE,
PRIORITY_LOW = G_PRIORITY_LOW
};
Timeout() :
m_tag(0)
{
@ -67,7 +75,8 @@ public:
* otherwise in the specified amount of time
*/
void activate(int seconds,
const boost::function<bool ()> &callback)
const boost::function<bool ()> &callback,
int priority = G_PRIORITY_DEFAULT)
{
deactivate();
@ -80,13 +89,25 @@ public:
}
}
void activate(const boost::function<bool ()> &idleCallback,
int priority = G_PRIORITY_DEFAULT_IDLE)
{
activate(-1, idleCallback, priority);
}
/**
* invoke the callback once
*/
void runOnce(int seconds,
const boost::function<void ()> &callback)
const boost::function<void ()> &callback,
int priority = G_PRIORITY_DEFAULT)
{
activate(seconds, boost::bind(&Timeout::once, callback));
activate(seconds, boost::bind(&Timeout::once, callback), priority);
}
void runOnce(const boost::function<void ()> &idleCallback,
int priority = G_PRIORITY_DEFAULT)
{
runOnce(-1, idleCallback, priority);
}
/**
@ -107,14 +128,21 @@ public:
private:
static gboolean triggered(gpointer data) throw ()
{
Timeout *me = static_cast<Timeout *>(data);
bool runAgain = false;
try {
Timeout *me = static_cast<Timeout *>(data);
return me->m_callback();
runAgain = me->m_callback();
} catch (...) {
// Something unexpected went wrong, can only shut down.
Exception::handle(HANDLE_EXCEPTION_FATAL);
}
return false;
if (!runAgain) {
// Returning false will automatically deactivate the source,
// remember that.
me->m_tag = 0;
me->m_callback = 0;
}
return runAgain;
}
static bool once(const boost::function<void ()> &callback) {