A question about synchronous message with timeout

27 views
Skip to first unread message

Peng

unread,
May 21, 2013, 9:09:14 PM5/21/13
to chromium...@chromium.org
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;
  }
}

===========================================================================================================
Reply all
Reply to author
Forward
0 new messages