Home | History | Annotate | Download | only in ipc
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "build/build_config.h"
      6 
      7 #if defined(OS_WIN)
      8 #include <windows.h>
      9 #endif
     10 #include <stack>
     11 
     12 #include "base/atomic_sequence_num.h"
     13 #include "base/lazy_instance.h"
     14 #include "base/logging.h"
     15 #include "base/synchronization/waitable_event.h"
     16 #include "ipc/ipc_sync_message.h"
     17 
     18 namespace {
     19 
     20 struct WaitableEventLazyInstanceTraits
     21     : public base::DefaultLazyInstanceTraits<base::WaitableEvent> {
     22   static base::WaitableEvent* New(void* instance) {
     23     // Use placement new to initialize our instance in our preallocated space.
     24     return new (instance) base::WaitableEvent(true, true);
     25   }
     26 };
     27 
     28 base::LazyInstance<base::WaitableEvent, WaitableEventLazyInstanceTraits>
     29     dummy_event = LAZY_INSTANCE_INITIALIZER;
     30 
     31 base::StaticAtomicSequenceNumber g_next_id;
     32 
     33 }  // namespace
     34 
     35 namespace IPC {
     36 
     37 #define kSyncMessageHeaderSize 4
     38 
     39 SyncMessage::SyncMessage(
     40     int32 routing_id,
     41     uint32 type,
     42     PriorityValue priority,
     43     MessageReplyDeserializer* deserializer)
     44     : Message(routing_id, type, priority),
     45       deserializer_(deserializer),
     46       pump_messages_event_(NULL)
     47       {
     48   set_sync();
     49   set_unblock(true);
     50 
     51   // Add synchronous message data before the message payload.
     52   SyncHeader header;
     53   header.message_id = g_next_id.GetNext();
     54   WriteSyncHeader(this, header);
     55 }
     56 
     57 SyncMessage::~SyncMessage() {
     58 }
     59 
     60 MessageReplyDeserializer* SyncMessage::GetReplyDeserializer() {
     61   DCHECK(deserializer_.get());
     62   return deserializer_.release();
     63 }
     64 
     65 void SyncMessage::EnableMessagePumping() {
     66   DCHECK(!pump_messages_event_);
     67   set_pump_messages_event(dummy_event.Pointer());
     68 }
     69 
     70 bool SyncMessage::IsMessageReplyTo(const Message& msg, int request_id) {
     71   if (!msg.is_reply())
     72     return false;
     73 
     74   return GetMessageId(msg) == request_id;
     75 }
     76 
     77 PickleIterator SyncMessage::GetDataIterator(const Message* msg) {
     78   PickleIterator iter(*msg);
     79   if (!iter.SkipBytes(kSyncMessageHeaderSize))
     80     return PickleIterator();
     81   else
     82     return iter;
     83 }
     84 
     85 int SyncMessage::GetMessageId(const Message& msg) {
     86   if (!msg.is_sync() && !msg.is_reply())
     87     return 0;
     88 
     89   SyncHeader header;
     90   if (!ReadSyncHeader(msg, &header))
     91     return 0;
     92 
     93   return header.message_id;
     94 }
     95 
     96 Message* SyncMessage::GenerateReply(const Message* msg) {
     97   DCHECK(msg->is_sync());
     98 
     99   Message* reply = new Message(msg->routing_id(), IPC_REPLY_ID,
    100                                msg->priority());
    101   reply->set_reply();
    102 
    103   SyncHeader header;
    104 
    105   // use the same message id, but this time reply bit is set
    106   header.message_id = GetMessageId(*msg);
    107   WriteSyncHeader(reply, header);
    108 
    109   return reply;
    110 }
    111 
    112 bool SyncMessage::ReadSyncHeader(const Message& msg, SyncHeader* header) {
    113   DCHECK(msg.is_sync() || msg.is_reply());
    114 
    115   PickleIterator iter(msg);
    116   bool result = msg.ReadInt(&iter, &header->message_id);
    117   if (!result) {
    118     NOTREACHED();
    119     return false;
    120   }
    121 
    122   return true;
    123 }
    124 
    125 bool SyncMessage::WriteSyncHeader(Message* msg, const SyncHeader& header) {
    126   DCHECK(msg->is_sync() || msg->is_reply());
    127   DCHECK(msg->payload_size() == 0);
    128   bool result = msg->WriteInt(header.message_id);
    129   if (!result) {
    130     NOTREACHED();
    131     return false;
    132   }
    133 
    134   // Note: if you add anything here, you need to update kSyncMessageHeaderSize.
    135   DCHECK(kSyncMessageHeaderSize == msg->payload_size());
    136 
    137   return true;
    138 }
    139 
    140 
    141 bool MessageReplyDeserializer::SerializeOutputParameters(const Message& msg) {
    142   return SerializeOutputParameters(msg, SyncMessage::GetDataIterator(&msg));
    143 }
    144 
    145 }  // namespace IPC
    146