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:
parent
54ebf2a699
commit
0efb67b51e
1
NEWS
1
NEWS
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue