Add a quit source to the DebuggerConnection's run loop to properly handle closing.
authorRobert Sesek <rsesek@bluestatic.org>
Sun, 31 Oct 2010 17:04:48 +0000 (13:04 -0400)
committerRobert Sesek <rsesek@bluestatic.org>
Sun, 31 Oct 2010 17:04:48 +0000 (13:04 -0400)
Source/DebuggerConnection.h
Source/DebuggerConnection.m
Source/DebuggerProcessor.m

index daf7db3c13f98af0aba8b4a752c1dcfef334e230..01c2bb1a03621fe3d399ec0b000a873532133055 100644 (file)
   
   // The write stream. Weak.
   CFWriteStreamRef writeStream_;
-  
+
+  // Run loop source used to quit the thread.
+  CFRunLoopSourceRef quitSource_;
+
   // An ever-increasing integer that gives each transaction a unique ID for the
   // debugging engine.
   NSUInteger transactionID;
index 3f837178c29629cda90fc6b07bfa4c0f89373d3e..598c3c17e7ba55ba0e0705d6f7bb9018f84a3de8 100644 (file)
@@ -43,6 +43,8 @@
 - (void)performSend:(NSString*)command;
 - (void)sendQueuedWrites;
 
+- (void)performQuitSignal;
+
 - (void)handleResponse:(NSXMLDocument*)response;
 - (void)handlePacket:(NSString*)packet;
 
@@ -184,6 +186,14 @@ void SocketAcceptCallback(CFSocketRef socket,
   [connection socketDidAccept];
 }
 
+// Other Run Loop Callbacks ////////////////////////////////////////////////////
+
+void PerformQuitSignal(void* info)
+{
+  DebuggerConnection* obj = (DebuggerConnection*)info;
+  [obj performQuitSignal];
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 @implementation DebuggerConnection
@@ -276,11 +286,23 @@ void SocketAcceptCallback(CFSocketRef socket,
   CFRunLoopAddSource([runLoop_ getCFRunLoop], source, kCFRunLoopCommonModes);
   CFRelease(source);
 
+  // Create a source that is used to quit.
+  CFRunLoopSourceContext quitContext = { 0 };
+  quitContext.version = 0;
+  quitContext.info = self;
+  quitContext.perform = PerformQuitSignal;
+  quitSource_ = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &quitContext);
+  CFRunLoopAddSource([runLoop_ getCFRunLoop], quitSource_, kCFRunLoopCommonModes);
+
   [runLoop_ run];
 
   thread_ = nil;
   runLoop_ = nil;
 
+  CFRunLoopSourceInvalidate(quitSource_);
+  CFRelease(quitSource_);
+  quitSource_ = NULL;
+
   [pool release];
 }
 
@@ -301,16 +323,29 @@ void SocketAcceptCallback(CFSocketRef socket,
  * Closes a socket and releases the ref.
  */
 - (void)close
+{
+  if (runLoop_ && quitSource_) {
+    CFRunLoopSourceSignal(quitSource_);
+    CFRunLoopWakeUp([runLoop_ getCFRunLoop]);
+  }
+}
+
+/**
+ * Quits the run loop and stops the thread.
+ */
+- (void)performQuitSignal
 {
   if (runLoop_) {
     CFRunLoopStop([runLoop_ getCFRunLoop]);
   }
-
+  
   // The socket goes down, so do the streams, which clean themselves up.
   if (socket_) {
     CFSocketInvalidate(socket_);
     CFRelease(socket_);
+    socket_ = NULL;
   }
+
   self.queuedWrites = nil;
   connected_ = NO;
   [writeQueueLock_ release];
@@ -321,8 +356,15 @@ void SocketAcceptCallback(CFSocketRef socket,
  */
 - (void)socketDisconnected
 {
-  [self close];
-  [delegate_ connectionDidClose:self];
+  if (connected_) {
+    // The state still is connected, which means that we did not get here
+    // through normal disconnected procedure (a call to |-close|, followed by
+    // the downing of the socket and the stream, which also produces this
+    // messsage). Instead, the stream callbacks encountered EOF unexpectedly.
+    [self close];
+  }
+  if ([delegate_ respondsToSelector:@selector(connectionDidClose:)])
+    [delegate_ connectionDidClose:self];
 }
 
 /**
@@ -419,6 +461,8 @@ void SocketAcceptCallback(CFSocketRef socket,
  */
 - (void)errorEncountered:(NSString*)error
 {
+  if (![delegate_ respondsToSelector:@selector(errorEncountered:)])
+    return;
   [delegate_ performSelectorOnMainThread:@selector(errorEncountered:)
                               withObject:error
                            waitUntilDone:NO];
index cad456a501e910668e65e9d4682c071410122f7b..c392d32fbff58f992b602da4f0d9acfb1893167b 100644 (file)
  */
 - (void)reconnect
 {
-  [connection_ close];
+  if (connection_.connected)
+    [connection_ close];
   self.status = @"Connecting";
   [connection_ connect];
 }
 // Specific Response Handlers //////////////////////////////////////////////////
 #pragma mark Response Handlers
 
+- (void)errorEncountered:(NSString*)error
+{
+  [delegate errorEncountered:error];
+}
+
 /**
  * Initial packet received. We've started a brand-new connection to the engine.
  */