Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ipc / ipc_sync_message.cc
blob8a770b17a1f407382938562ffcee4210a3076e66
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.
5 #include "ipc/ipc_sync_message.h"
7 #include <stack>
9 #include "base/atomic_sequence_num.h"
10 #include "base/lazy_instance.h"
11 #include "base/logging.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "build/build_config.h"
15 namespace {
17 struct WaitableEventLazyInstanceTraits
18 : public base::DefaultLazyInstanceTraits<base::WaitableEvent> {
19 static base::WaitableEvent* New(void* instance) {
20 // Use placement new to initialize our instance in our preallocated space.
21 return new (instance) base::WaitableEvent(true, true);
25 base::LazyInstance<base::WaitableEvent, WaitableEventLazyInstanceTraits>
26 dummy_event = LAZY_INSTANCE_INITIALIZER;
28 base::StaticAtomicSequenceNumber g_next_id;
30 } // namespace
32 namespace IPC {
34 #define kSyncMessageHeaderSize 4
36 SyncMessage::SyncMessage(int32_t routing_id,
37 uint32_t type,
38 PriorityValue priority,
39 MessageReplyDeserializer* deserializer)
40 : Message(routing_id, type, priority),
41 deserializer_(deserializer),
42 pump_messages_event_(NULL) {
43 set_sync();
44 set_unblock(true);
46 // Add synchronous message data before the message payload.
47 SyncHeader header;
48 header.message_id = g_next_id.GetNext();
49 WriteSyncHeader(this, header);
52 SyncMessage::~SyncMessage() {
55 MessageReplyDeserializer* SyncMessage::GetReplyDeserializer() {
56 DCHECK(deserializer_.get());
57 return deserializer_.release();
60 void SyncMessage::EnableMessagePumping() {
61 DCHECK(!pump_messages_event_);
62 set_pump_messages_event(dummy_event.Pointer());
65 bool SyncMessage::IsMessageReplyTo(const Message& msg, int request_id) {
66 if (!msg.is_reply())
67 return false;
69 return GetMessageId(msg) == request_id;
72 base::PickleIterator SyncMessage::GetDataIterator(const Message* msg) {
73 base::PickleIterator iter(*msg);
74 if (!iter.SkipBytes(kSyncMessageHeaderSize))
75 return base::PickleIterator();
76 else
77 return iter;
80 int SyncMessage::GetMessageId(const Message& msg) {
81 if (!msg.is_sync() && !msg.is_reply())
82 return 0;
84 SyncHeader header;
85 if (!ReadSyncHeader(msg, &header))
86 return 0;
88 return header.message_id;
91 Message* SyncMessage::GenerateReply(const Message* msg) {
92 DCHECK(msg->is_sync());
94 Message* reply = new Message(msg->routing_id(), IPC_REPLY_ID,
95 msg->priority());
96 reply->set_reply();
98 SyncHeader header;
100 // use the same message id, but this time reply bit is set
101 header.message_id = GetMessageId(*msg);
102 WriteSyncHeader(reply, header);
104 return reply;
107 bool SyncMessage::ReadSyncHeader(const Message& msg, SyncHeader* header) {
108 DCHECK(msg.is_sync() || msg.is_reply());
110 base::PickleIterator iter(msg);
111 bool result = iter.ReadInt(&header->message_id);
112 if (!result) {
113 NOTREACHED();
114 return false;
117 return true;
120 bool SyncMessage::WriteSyncHeader(Message* msg, const SyncHeader& header) {
121 DCHECK(msg->is_sync() || msg->is_reply());
122 DCHECK(msg->payload_size() == 0);
123 bool result = msg->WriteInt(header.message_id);
124 if (!result) {
125 NOTREACHED();
126 return false;
129 // Note: if you add anything here, you need to update kSyncMessageHeaderSize.
130 DCHECK(kSyncMessageHeaderSize == msg->payload_size());
132 return true;
136 bool MessageReplyDeserializer::SerializeOutputParameters(const Message& msg) {
137 return SerializeOutputParameters(msg, SyncMessage::GetDataIterator(&msg));
140 } // namespace IPC