From 45e720ad7f4c9904384bc430d2752f5318913ef7 Mon Sep 17 00:00:00 2001
From: Robert Sesek <rsesek@bluestatic.org>
Date: Mon, 18 May 2015 08:20:28 -0400
Subject: [PATCH] Fix potential crash when detaching and reattaching.

Waiting via sleep() in -[MessageQueue scheduleListenSocket] will ignore any
disconnect messages, since the run loop is not being serviced. Instead, wait by
pumping the loop.
---
 Source/DebuggerBackEnd.m | 14 ++++++++------
 Source/MessageQueue.h    |  3 +++
 Source/MessageQueue.m    | 14 ++++++++++----
 3 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/Source/DebuggerBackEnd.m b/Source/DebuggerBackEnd.m
index 81b798d..df26dd8 100644
--- a/Source/DebuggerBackEnd.m
+++ b/Source/DebuggerBackEnd.m
@@ -108,12 +108,14 @@
  * connection as appropriate.
  */
 - (void)setAttached:(BOOL)attached {
-  if (attached != attached_) {
-    if (!attached)
-      [client_ connectOnPort:port_];
-    else
-      [client_ disconnect];
-  }
+  if (attached == attached_)
+    return;
+
+  if (attached_)
+    [client_ disconnect];
+  else
+    [client_ connectOnPort:port_];
+
   attached_ = attached;
 }
 
diff --git a/Source/MessageQueue.h b/Source/MessageQueue.h
index 16961d7..a038cbd 100644
--- a/Source/MessageQueue.h
+++ b/Source/MessageQueue.h
@@ -33,6 +33,9 @@
   NSThread* _thread;
   NSRunLoop* _runLoop;
 
+  // Whether or not the run loop should quit.
+  BOOL _shouldQuit;
+
   // Whether or not the message queue is connected to a client.
   BOOL _connected;
 
diff --git a/Source/MessageQueue.m b/Source/MessageQueue.m
index 50ff99d..5778169 100644
--- a/Source/MessageQueue.m
+++ b/Source/MessageQueue.m
@@ -140,6 +140,7 @@ static void MessageQueueWriteEvent(CFWriteStreamRef stream,
     _runLoop = [NSRunLoop currentRunLoop];
 
     _connected = NO;
+    _shouldQuit = NO;
     [self scheduleListenSocket];
 
     // Use CFRunLoop instead of NSRunLoop because the latter has no programmatic
@@ -178,8 +179,12 @@ static void MessageQueueWriteEvent(CFWriteStreamRef stream,
                                           &MessageQueueSocketAccept,  // Callback function.
                                           &context);  // Context to pass to callout.
     if (!_socket) {
+      // Pump the run loop while waiting for the socket to be reusued. If told
+      // to quit while waiting, then break out of the loop.
+      if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1, FALSE) && _shouldQuit)
+        return;
+      NSLog(@"Could not open socket");
       //[connection_ errorEncountered:@"Could not open socket."];
-      sleep(1);
     }
   } while (!_socket);
 
@@ -219,6 +224,7 @@ static void MessageQueueWriteEvent(CFWriteStreamRef stream,
 }
 
 - (void)stopRunLoop {
+  _shouldQuit = YES;
   [self disconnectClient];
   CFRunLoopStop([_runLoop getCFRunLoop]);
 }
@@ -366,9 +372,9 @@ static void MessageQueueWriteEvent(CFWriteStreamRef stream,
 
   // Set the client of the write stream.
   CFOptionFlags writeFlags = kCFStreamEventOpenCompleted |
-  kCFStreamEventCanAcceptBytes |
-  kCFStreamEventErrorOccurred |
-  kCFStreamEventEndEncountered;
+                             kCFStreamEventCanAcceptBytes |
+                             kCFStreamEventErrorOccurred |
+                             kCFStreamEventEndEncountered;
   if (CFWriteStreamSetClient(_writeStream, writeFlags, &MessageQueueWriteEvent, &context))
     // Schedule it in the run loop to receive error information.
     CFWriteStreamScheduleWithRunLoop(_writeStream, [_runLoop getCFRunLoop], kCFRunLoopCommonModes);
-- 
2.43.5