// Close all connections void ConnectionManager::Shutdown() { // sml::PrintDebug("Shutting down connection manager") ; // Stop the thread (and wait until it has stopped) if (m_ListenerThread) { m_ListenerThread->Stop(true) ; // Remove the listener delete m_ListenerThread ; m_ListenerThread = NULL ; } // sml::PrintDebug("Listener stopped") ; // Stop the receiver thread (and wait until is has stopped) if (m_ReceiverThread) { m_ReceiverThread->Stop(true) ; // sml::PrintDebug("Receiver stopped") ; // Remove the thread delete m_ReceiverThread ; m_ReceiverThread = NULL ; } // Serialize thread access to the connections list soar_thread::Lock lock(&m_ConnectionsMutex) ; for (ConnectionsIter iter = m_Connections.begin() ; iter != m_Connections.end() ; iter++) { Connection* pConnection = *iter ; pConnection->CloseConnection() ; // Remove any events that this connection is listening to KernelSML* pKernelSML = static_cast<KernelSML*>(pConnection->GetUserData()); pKernelSML->RemoveAllListeners(pConnection) ; // Not clear that we can just delete connections as we might be inside a connection callback // when the shutdown comes. So for safety, move connections to a closed list instead of deleting. // For now this will leak the connection object. Later if we are confident we can delete this list. //delete pConnection ; m_ClosedConnections.push_back(pConnection) ; } m_Connections.clear() ; // Now clean up all closed connections. for (ConnectionsIter iter = m_ClosedConnections.begin() ; iter != m_ClosedConnections.end() ; iter++) { Connection* pConnection = *iter ; delete pConnection ; } m_ClosedConnections.clear() ; // sml::PrintDebug("Completed shutdown") ; }
// Go through all connections and read any incoming commands from the sockets. // The messages are sent to the callback registered with the connection when it was created (ReceivedCall currently). // Those calls could take a long time to execute (e.g. a call to Run Soar). // Returns true if we received at least one message. bool ConnectionManager::ReceiveAllMessages() { int index = 0 ; bool receivedOneMessage = false ; // We need to search this list of connections and call each in turn. // But we also want to allow the listener thread to add new connections while we're doing this. // (E.g. we might want to attach a debugger to a process that's already executing a "run" command inside "receiveMessages"). // So we use this slightly cumbersome approach of looking up the connection based on an integer index. // The lookup is thread safe and if the connection list changes between lookups that's fine as this function // will return NULL once we go out of bounds. (You could argue that we might miss calling a connection on a particular pass using this method // but that should be ok). Connection* pConnection = GetConnectionByIndex(index++) ; while (pConnection) { // Check to see if this connection has already been closed // (which includes if the other side has dropped its half of the socket) if (!pConnection->IsClosed()) { receivedOneMessage = pConnection->ReceiveMessages(true) || receivedOneMessage ; } else { // If the connection has closed, delete it from the list of active connections RemoveConnection(pConnection) ; // Remove any events that this connection is listening to KernelSML* pKernelSML = static_cast<KernelSML*>(pConnection->GetUserData()); pKernelSML->RemoveAllListeners(pConnection) ; // Not clear that we can just delete connections as we might be inside a connection callback // when the shutdown comes. So for safety, move connections to a closed list instead of deleting. // For now this will leak the connection object. Later if we are confident we can delete this list. //delete pConnection ; m_ClosedConnections.push_back(pConnection) ; // Since we just removed this connection we should look up the same index value again // so we don't skip any. This isn't really that important. index-- ; } // Get the next connection (will return NULL once we reach the end of the list) pConnection = GetConnectionByIndex(index++) ; } // So far we don't have some sort of shutdown message the remote connections // can send, but if we decide to implement it this allows us to return it. return receivedOneMessage ; }