Hello everyone,
I'm reading source code of IPC module, I have a question about sending synchronous message with timeout, the source code is in the cpp file chromium\home\src_tarball\tarball\chromium\src\ipc\ipc_sync_channel.cc, relevant snip shown as below:
When a sync-message is timeout, the context->GetSendDoneEvent() will be set in the ipc_task_runner, and the listener thread will be unblocked and
get return from the SyncChannel::WaitForReply function, then the context->Pop() get called, this function will pop the outermost PendingSyncMsg from
the deserializers_, the question is: this PendingSyncMsg probably not the corresponding one to the done_event, because after the original send() call,
there could be more PendingSyncMsg be pushed into deserializers_, any ideas?
===========================================================================================================
bool SyncChannel::SendWithTimeout(Message* message, int timeout_ms) {
#ifdef IPC_MESSAGE_LOG_ENABLED
Logging* logger = Logging::GetInstance();
std::string name;
logger->GetMessageText(message->type(), &name, message, NULL);
TRACE_EVENT1("task", "SyncChannel::SendWithTimeout",
"name", name);
#else
TRACE_EVENT2("task", "SyncChannel::SendWithTimeout",
"class", IPC_MESSAGE_ID_CLASS(message->type()),
"line", IPC_MESSAGE_ID_LINE(message->type()));
#endif
if (!message->is_sync()) {
ChannelProxy::Send(message);
return true;
}
// *this* might get deleted in WaitForReply.
scoped_refptr<SyncContext> context(sync_context());
if (context->shutdown_event()->IsSignaled()) {
VLOG(1) << "shutdown event is signaled";
delete message;
return false;
}
DCHECK(sync_messages_with_no_timeout_allowed_ ||
timeout_ms != base::kNoTimeout);
SyncMessage* sync_msg = static_cast<SyncMessage*>(message);
context->Push(sync_msg);
int message_id = SyncMessage::GetMessageId(*sync_msg);
WaitableEvent* pump_messages_event = sync_msg->pump_messages_event();
ChannelProxy::Send(message);
if (timeout_ms != base::kNoTimeout) {
// We use the sync message id so that when a message times out, we don't
// confuse it with another send that is either above/below this Send in
// the call stack.
context->ipc_task_runner()->PostDelayedTask(
FROM_HERE,
base::Bind(&SyncContext::OnSendTimeout, context.get(), message_id),
base::TimeDelta::FromMilliseconds(timeout_ms));
}
// Wait for reply, or for any other incoming synchronous messages.
// *this* might get deleted, so only call static functions at this point.
WaitForReply(context, pump_messages_event);
return context->Pop();
}
===========================================================================================================
void SyncChannel::WaitForReply(
SyncContext* context, WaitableEvent* pump_messages_event) {
context->DispatchMessages();
while (true) {
WaitableEvent* objects[] = {
context->GetDispatchEvent(),
context->GetSendDoneEvent(),
pump_messages_event
};
unsigned count = pump_messages_event ? 3: 2;
size_t result = WaitableEvent::WaitMany(objects, count);
if (result == 0 /* dispatch event */) {
// We're waiting for a reply, but we received a blocking synchronous
// call. We must process it or otherwise a deadlock might occur.
context->GetDispatchEvent()->Reset();
context->DispatchMessages();
continue;
}
if (result == 2 /* pump_messages_event */)
WaitForReplyWithNestedMessageLoop(context); // Run a nested message loop.
break;
}
}
===========================================================================================================