PassOwnPtr<ArgumentDecoder> Connection::sendSyncMessage(MessageID messageID, uint64_t syncRequestID, PassOwnPtr<ArgumentEncoder> encoder, double timeout) { // We only allow sending sync messages from the client run loop. ASSERT(RunLoop::current() == m_clientRunLoop); if (!isValid()) return 0; // Push the pending sync reply information on our stack. { MutexLocker locker(m_pendingSyncRepliesMutex); m_pendingSyncReplies.append(PendingSyncReply(syncRequestID)); } // First send the message. sendMessage(messageID, encoder); // Then wait for a reply. OwnPtr<ArgumentDecoder> reply = waitForSyncReply(syncRequestID, timeout); // Finally, pop the pending sync reply information. { MutexLocker locker(m_pendingSyncRepliesMutex); ASSERT(m_pendingSyncReplies.last().syncRequestID == syncRequestID); m_pendingSyncReplies.removeLast(); } return reply.release(); }
PassOwnPtr<ArgumentDecoder> Connection::sendSyncMessage(MessageID messageID, uint64_t syncRequestID, PassOwnPtr<ArgumentEncoder> encoder, double timeout) { // We only allow sending sync messages from the client run loop. ASSERT(RunLoop::current() == m_clientRunLoop); if (!isValid()) return 0; // Push the pending sync reply information on our stack. { MutexLocker locker(m_syncReplyStateMutex); if (!m_shouldWaitForSyncReplies) return 0; m_pendingSyncReplies.append(PendingSyncReply(syncRequestID)); } // First send the message. sendMessage(messageID, encoder); // Then wait for a reply. Waiting for a reply could involve dispatching incoming sync messages, so // keep an extra reference to the connection here in case it's invalidated. RefPtr<Connection> protect(this); OwnPtr<ArgumentDecoder> reply = waitForSyncReply(syncRequestID, timeout); // Finally, pop the pending sync reply information. { MutexLocker locker(m_syncReplyStateMutex); ASSERT(m_pendingSyncReplies.last().syncRequestID == syncRequestID); m_pendingSyncReplies.removeLast(); if (m_pendingSyncReplies.isEmpty()) { // This was the bottom-most sendSyncMessage call in the stack. If we have any pending incoming // sync messages, they need to be dispatched. if (!m_syncMessagesReceivedWhileWaitingForSyncReply.isEmpty()) { // Add the messages. MutexLocker locker(m_incomingMessagesLock); m_incomingMessages.append(m_syncMessagesReceivedWhileWaitingForSyncReply); m_syncMessagesReceivedWhileWaitingForSyncReply.clear(); // Schedule for the messages to be sent. m_clientRunLoop->scheduleWork(WorkItem::create(this, &Connection::dispatchMessages)); } } } return reply.release(); }
std::unique_ptr<MessageDecoder> Connection::sendSyncMessage(uint64_t syncRequestID, std::unique_ptr<MessageEncoder> encoder, std::chrono::milliseconds timeout, unsigned syncSendFlags) { if (RunLoop::current() != m_clientRunLoop) { // No flags are supported for synchronous messages sent from secondary threads. ASSERT(!syncSendFlags); return sendSyncMessageFromSecondaryThread(syncRequestID, std::move(encoder), timeout); } if (!isValid()) { didFailToSendSyncMessage(); return nullptr; } // Push the pending sync reply information on our stack. { MutexLocker locker(m_syncReplyStateMutex); if (!m_shouldWaitForSyncReplies) { didFailToSendSyncMessage(); return nullptr; } m_pendingSyncReplies.append(PendingSyncReply(syncRequestID)); } ++m_inSendSyncCount; // First send the message. sendMessage(std::move(encoder), DispatchMessageEvenWhenWaitingForSyncReply); // Then wait for a reply. Waiting for a reply could involve dispatching incoming sync messages, so // keep an extra reference to the connection here in case it's invalidated. Ref<Connection> protect(*this); std::unique_ptr<MessageDecoder> reply = waitForSyncReply(syncRequestID, timeout, syncSendFlags); --m_inSendSyncCount; // Finally, pop the pending sync reply information. { MutexLocker locker(m_syncReplyStateMutex); ASSERT(m_pendingSyncReplies.last().syncRequestID == syncRequestID); m_pendingSyncReplies.removeLast(); } if (!reply) didFailToSendSyncMessage(); return reply; }