DeferredMonitor: fix race condition when using GLib event loop

Turns out the lock-free code using atomics was not thread-safe.  The
given callback could be invoked by GLib before the source_id attribute
was assigned.  This commit changes the DeferredMonitor class to use a
Mutex to block the event loop until source_id is assigned.  This bug
does not exist in the 0.19 branch because it does not use the GLib
main loop anymore.
This commit is contained in:
Max Kellermann 2014-04-26 22:11:23 +02:00
parent 54ebf2a699
commit 0efb67b51e
3 changed files with 23 additions and 11 deletions

1
NEWS
View File

@ -1,4 +1,5 @@
ver 0.18.11 (not yet released) ver 0.18.11 (not yet released)
* fix race condition when using GLib event loop (non-Linux)
ver 0.18.10 (2014/04/10) ver 0.18.10 (2014/04/10)
* decoder * decoder

View File

@ -27,9 +27,11 @@ DeferredMonitor::Cancel()
#ifdef USE_EPOLL #ifdef USE_EPOLL
pending = false; pending = false;
#else #else
const auto id = source_id.exchange(0); const ScopeLock protect(mutex);
if (id != 0) if (source_id != 0) {
g_source_remove(id); g_source_remove(source_id);
source_id = 0;
}
#endif #endif
} }
@ -40,10 +42,9 @@ DeferredMonitor::Schedule()
if (!pending.exchange(true)) if (!pending.exchange(true))
fd.Write(); fd.Write();
#else #else
const unsigned id = loop.AddIdle(Callback, this); const ScopeLock protect(mutex);
const auto old_id = source_id.exchange(id); if (source_id == 0)
if (old_id != 0) source_id = loop.AddIdle(Callback, this);
g_source_remove(old_id);
#endif #endif
} }
@ -65,9 +66,16 @@ DeferredMonitor::OnSocketReady(unsigned)
void void
DeferredMonitor::Run() DeferredMonitor::Run()
{ {
const auto id = source_id.exchange(0); {
if (id != 0) const ScopeLock protect(mutex);
RunDeferred(); if (source_id == 0)
/* cancelled */
return;
source_id = 0;
}
RunDeferred();
} }
gboolean gboolean

View File

@ -27,6 +27,7 @@
#include "SocketMonitor.hxx" #include "SocketMonitor.hxx"
#include "WakeFD.hxx" #include "WakeFD.hxx"
#else #else
#include "thread/Mutex.hxx"
#include <glib.h> #include <glib.h>
#endif #endif
@ -48,7 +49,9 @@ class DeferredMonitor
#else #else
EventLoop &loop; EventLoop &loop;
std::atomic<guint> source_id; Mutex mutex;
guint source_id;
#endif #endif
public: public: