Commit 0efb67b5 authored by Max Kellermann's avatar Max Kellermann

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.
parent 54ebf2a6
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
......
...@@ -27,9 +27,11 @@ DeferredMonitor::Cancel() ...@@ -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() ...@@ -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,8 +66,15 @@ DeferredMonitor::OnSocketReady(unsigned) ...@@ -65,8 +66,15 @@ DeferredMonitor::OnSocketReady(unsigned)
void void
DeferredMonitor::Run() DeferredMonitor::Run()
{ {
const auto id = source_id.exchange(0); {
if (id != 0) const ScopeLock protect(mutex);
if (source_id == 0)
/* cancelled */
return;
source_id = 0;
}
RunDeferred(); RunDeferred();
} }
......
...@@ -27,6 +27,7 @@ ...@@ -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 ...@@ -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:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment