std::auto_ptr<ArgumentDecoder> Connection::waitForMessage(MessageID messageID, uint64_t destinationID, double timeout) { // First, check if this message is already in the incoming messages queue. { MutexLocker locker(m_incomingMessagesLock); for (size_t i = 0; i < m_incomingMessages.size(); ++i) { const IncomingMessage& message = m_incomingMessages[i]; if (equalIgnoringFlags(message.messageID(), messageID) && message.arguments()->destinationID() == destinationID) { std::auto_ptr<ArgumentDecoder> arguments(message.arguments()); // Erase the incoming message. m_incomingMessages.remove(i); return arguments; } } } double absoluteTime = currentTime() + timeout; std::pair<unsigned, uint64_t> messageAndDestination(std::make_pair(messageID.toInt(), destinationID)); { MutexLocker locker(m_waitForMessageMutex); // We don't support having multiple clients wait for the same message. ASSERT(!m_waitForMessageMap.contains(messageAndDestination)); // Insert our pending wait. m_waitForMessageMap.set(messageAndDestination, 0); } bool timedOut = false; // Now wait for it to be set. while (!timedOut) { MutexLocker locker(m_waitForMessageMutex); HashMap<std::pair<unsigned, uint64_t>, ArgumentDecoder*>::iterator it = m_waitForMessageMap.find(messageAndDestination); if (it->second) { std::auto_ptr<ArgumentDecoder> arguments(it->second); m_waitForMessageMap.remove(it); return arguments; } // We didn't find it, keep waiting. timedOut = !m_waitForMessageCondition.timedWait(m_waitForMessageMutex, absoluteTime); } // We timed out, now remove the pending wait. { MutexLocker locker(m_waitForMessageMutex); m_waitForMessageMap.remove(messageAndDestination); } return std::auto_ptr<ArgumentDecoder>(); }
std::unique_ptr<MessageDecoder> Connection::waitForMessage(StringReference messageReceiverName, StringReference messageName, uint64_t destinationID, std::chrono::milliseconds timeout) { // First, check if this message is already in the incoming messages queue. { MutexLocker locker(m_incomingMessagesLock); for (auto it = m_incomingMessages.begin(), end = m_incomingMessages.end(); it != end; ++it) { std::unique_ptr<MessageDecoder>& message = *it; if (message->messageReceiverName() == messageReceiverName && message->messageName() == messageName && message->destinationID() == destinationID) { std::unique_ptr<MessageDecoder> returnedMessage = std::move(message); m_incomingMessages.remove(it); return returnedMessage; } } } std::pair<std::pair<StringReference, StringReference>, uint64_t> messageAndDestination(std::make_pair(std::make_pair(messageReceiverName, messageName), destinationID)); { std::lock_guard<std::mutex> lock(m_waitForMessageMutex); // We don't support having multiple clients wait for the same message. ASSERT(!m_waitForMessageMap.contains(messageAndDestination)); // Insert our pending wait. m_waitForMessageMap.set(messageAndDestination, nullptr); } // Now wait for it to be set. while (true) { std::unique_lock<std::mutex> lock(m_waitForMessageMutex); auto it = m_waitForMessageMap.find(messageAndDestination); if (it->value) { std::unique_ptr<MessageDecoder> decoder = std::move(it->value); m_waitForMessageMap.remove(it); return decoder; } // Now we wait. if (m_waitForMessageCondition.wait_for(lock, timeout) == std::cv_status::timeout) { // We timed out, now remove the pending wait. m_waitForMessageMap.remove(messageAndDestination); break; } } return nullptr; }