Skip to content

Commit

Permalink
Use a non-GC allocator for s_threadObjects to avoid potential deadlock.
Browse files Browse the repository at this point in the history
The original deadlock situation that this change avoids:

Thread 1: GC collection (GC lock taken) -> Libevent2Object.~this -> Libevent2Driver.unregisterObject -> synchronized(s_threadObjectsMutex)
Thread 2: Libevent2Driver.registerObject -> synchronized(s_threadObejctsMutex) -> s_threadObjects.insert -> GC allocate -> acquire GC lock

Sidenote: ArraySet should be replaced by HashMap for efficiency reasons.
  • Loading branch information
s-ludwig committed May 10, 2017
1 parent b8366ee commit b7cac51
Showing 1 changed file with 5 additions and 3 deletions.
8 changes: 5 additions & 3 deletions core/vibe/core/drivers/libevent2.d
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ final class Libevent2Driver : EventDriver {

synchronized if (!s_threadObjectsMutex) {
s_threadObjectsMutex = new Mutex;
s_threadObjects.setAllocator(m_allocator);

// set the malloc/free versions of our runtime so we don't run into trouble
// because the libevent DLL uses a different one.
Expand Down Expand Up @@ -164,7 +165,9 @@ final class Libevent2Driver : EventDriver {
() @trusted { destroy(obj); } ();
}

foreach (ref key; () @trusted { return s_threadObjects; } ()) {
ref getThreadObjects() @trusted { return s_threadObjects; }

foreach (ref key; getThreadObjects()) {
assert(key);
auto obj = () @trusted { return cast(Libevent2Object)cast(void*)key; } ();
debug assert(obj.m_ownerThread !is m_ownerThread, "Live object of this thread detected after all owned mutexes have been destroyed.");
Expand Down Expand Up @@ -571,13 +574,12 @@ final class Libevent2Driver : EventDriver {

private void registerObject(Libevent2Object obj)
nothrow {
scope (failure) assert(false); // synchronized is not nothrow

debug assert(() @trusted { return Thread.getThis(); } () is m_ownerThread, "Event object created in foreign thread.");
auto key = () @trusted { return cast(size_t)cast(void*)obj; } ();
m_ownedObjects.insert(key);
if (obj.m_threadObject)
() @trusted {
scope (failure) assert(false); // synchronized is not nothrow
synchronized (s_threadObjectsMutex)
s_threadObjects.insert(key);
} ();
Expand Down

0 comments on commit b7cac51

Please sign in to comment.