             }
         }
     }
-    
+
     /// If there is data waiting to be written, set a flag and the socket will
     /// be closed when all the buffered data has been written.
     /// Otherwise, immediately close the socket.
     public func prepareToClose() {
-        if !preparingToClose {
-            preparingToClose = true
-            
-            if writeBuffer.length == writeBufferPosition && !writeInProgress && !readInProgress {
-                close()
-            }
-        }
-    }
-
-    /// Close the socket and mark this handler as no longer in progress.
+        preparingToClose = true
+        close()
+    }
+
+    /// Close the socket and mark this handler as no longer in progress, if it is safe.
+    /// (there is no data waiting to be written and a socket read/write is not in progress).
     ///
     /// - Note: On Linux closing the socket causes it to be dropped by epoll.
     /// - Note: On OSX the cancel handler will actually close the socket.
     private func close() {
-        #if os(OSX) || os(iOS) || os(tvOS) || os(watchOS) || GCD_ASYNCH
-            readerSource.cancel()
-        #else
-            handleCancel()
-        #endif
-    }
-    
+        if isOpen {
+            isOpen = false
+            // Set isOpen to false before the guard below to avoid another thread invoking
+            // a read/write function in between us clearing the guard and setting the flag.
+            // Make sure to set it back to open if the guard fails and we don't actually close.
+            // This guard needs to be here, not in handleCancel() as readerSource.cancel()
+            // only invokes handleCancel() the first time it is called.
+            guard !writeInProgress && !handleWriteInProgress && !handleReadInProgress
+                && writeBuffer.length == writeBufferPosition else {
+                    isOpen = true
+                    return
+            }
+
+            #if os(OSX) || os(iOS) || os(tvOS) || os(watchOS) || GCD_ASYNCH
+                readerSource.cancel()
+            #else
+                handleCancel()
+            #endif
+        }
+    }
+
     /// DispatchSource cancel handler
     private func handleCancel() {
+        isOpen = false // just in case something besides close() calls handleCancel()
         if socket.socketfd > -1 {
-            if isOpen {
-                isOpen = false
-                socket.close()
-            }
-        }
+            socket.close()
+        }
+
         processor?.inProgress = false
         processor?.keepAliveUntil = 0.0
+        processor?.handler = nil
         processor?.close()
+        processor = nil
     }
 }

    private let readBuffer = NSMutableData()
    private let writeBuffer = NSMutableData()
    private var writeBufferPosition = 0
    private var preparingToClose = false
    private var isOpen = true
    private var writeInProgress = false
    private var readInProgress = false

    /// The file descriptor of the incoming socket
    var fileDescriptor: Int32 { return socket.socketfd }

                if socket.remoteConnectionClosed  {
                    Log.debug("socket remoteConnectionClosed in handleRead()")
                    processor?.socketClosed()
                    preparingToClose = true
                }
            }
        }
        catch let error as Socket.Error {
            if error.errorCode == Int32(Socket.SOCKET_ERR_CONNECTION_RESET) {
                Log.debug("Read from socket (file descriptor \(socket.socketfd)) reset. Error = \(error).")
            } else {
                Log.error("Read from socket (file descriptor \(socket.socketfd)) failed. Error = \(error).")
            }
            preparingToClose = true
        } catch {
            Log.error("Unexpected error...")
            preparingToClose = true
        }

        return result
    }
    
