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