OLD | NEW |
| (Empty) |
1 // Copyright 2013 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 "mojo/edk/system/local_message_pipe_endpoint.h" | |
6 | |
7 #include <string.h> | |
8 | |
9 #include "base/logging.h" | |
10 #include "mojo/edk/system/dispatcher.h" | |
11 #include "mojo/edk/system/message_in_transit.h" | |
12 | |
13 namespace mojo { | |
14 namespace system { | |
15 | |
16 LocalMessagePipeEndpoint::LocalMessagePipeEndpoint( | |
17 MessageInTransitQueue* message_queue) | |
18 : is_open_(true), is_peer_open_(true) { | |
19 if (message_queue) | |
20 message_queue_.Swap(message_queue); | |
21 } | |
22 | |
23 LocalMessagePipeEndpoint::~LocalMessagePipeEndpoint() { | |
24 DCHECK(!is_open_); | |
25 DCHECK(message_queue_.IsEmpty()); // Should be implied by not being open. | |
26 } | |
27 | |
28 MessagePipeEndpoint::Type LocalMessagePipeEndpoint::GetType() const { | |
29 return kTypeLocal; | |
30 } | |
31 | |
32 bool LocalMessagePipeEndpoint::OnPeerClose() { | |
33 DCHECK(is_open_); | |
34 DCHECK(is_peer_open_); | |
35 | |
36 HandleSignalsState old_state = GetHandleSignalsState(); | |
37 is_peer_open_ = false; | |
38 HandleSignalsState new_state = GetHandleSignalsState(); | |
39 | |
40 if (!new_state.equals(old_state)) | |
41 awakable_list_.AwakeForStateChange(new_state); | |
42 | |
43 return true; | |
44 } | |
45 | |
46 void LocalMessagePipeEndpoint::EnqueueMessage( | |
47 scoped_ptr<MessageInTransit> message) { | |
48 DCHECK(is_open_); | |
49 DCHECK(is_peer_open_); | |
50 | |
51 bool was_empty = message_queue_.IsEmpty(); | |
52 message_queue_.AddMessage(message.Pass()); | |
53 if (was_empty) | |
54 awakable_list_.AwakeForStateChange(GetHandleSignalsState()); | |
55 } | |
56 | |
57 void LocalMessagePipeEndpoint::Close() { | |
58 DCHECK(is_open_); | |
59 is_open_ = false; | |
60 message_queue_.Clear(); | |
61 } | |
62 | |
63 void LocalMessagePipeEndpoint::CancelAllAwakables() { | |
64 DCHECK(is_open_); | |
65 awakable_list_.CancelAll(); | |
66 } | |
67 | |
68 MojoResult LocalMessagePipeEndpoint::ReadMessage( | |
69 UserPointer<void> bytes, | |
70 UserPointer<uint32_t> num_bytes, | |
71 DispatcherVector* dispatchers, | |
72 uint32_t* num_dispatchers, | |
73 MojoReadMessageFlags flags) { | |
74 DCHECK(is_open_); | |
75 DCHECK(!dispatchers || dispatchers->empty()); | |
76 | |
77 const uint32_t max_bytes = num_bytes.IsNull() ? 0 : num_bytes.Get(); | |
78 const uint32_t max_num_dispatchers = num_dispatchers ? *num_dispatchers : 0; | |
79 | |
80 if (message_queue_.IsEmpty()) { | |
81 return is_peer_open_ ? MOJO_RESULT_SHOULD_WAIT | |
82 : MOJO_RESULT_FAILED_PRECONDITION; | |
83 } | |
84 | |
85 // TODO(vtl): If |flags & MOJO_READ_MESSAGE_FLAG_MAY_DISCARD|, we could pop | |
86 // and release the lock immediately. | |
87 bool enough_space = true; | |
88 MessageInTransit* message = message_queue_.PeekMessage(); | |
89 if (!num_bytes.IsNull()) | |
90 num_bytes.Put(message->num_bytes()); | |
91 if (message->num_bytes() <= max_bytes) | |
92 bytes.PutArray(message->bytes(), message->num_bytes()); | |
93 else | |
94 enough_space = false; | |
95 | |
96 if (DispatcherVector* queued_dispatchers = message->dispatchers()) { | |
97 if (num_dispatchers) | |
98 *num_dispatchers = static_cast<uint32_t>(queued_dispatchers->size()); | |
99 if (enough_space) { | |
100 if (queued_dispatchers->empty()) { | |
101 // Nothing to do. | |
102 } else if (queued_dispatchers->size() <= max_num_dispatchers) { | |
103 DCHECK(dispatchers); | |
104 dispatchers->swap(*queued_dispatchers); | |
105 } else { | |
106 enough_space = false; | |
107 } | |
108 } | |
109 } else { | |
110 if (num_dispatchers) | |
111 *num_dispatchers = 0; | |
112 } | |
113 | |
114 message = nullptr; | |
115 | |
116 if (enough_space || (flags & MOJO_READ_MESSAGE_FLAG_MAY_DISCARD)) { | |
117 message_queue_.DiscardMessage(); | |
118 | |
119 // Now it's empty, thus no longer readable. | |
120 if (message_queue_.IsEmpty()) { | |
121 // It's currently not possible to wait for non-readability, but we should | |
122 // do the state change anyway. | |
123 awakable_list_.AwakeForStateChange(GetHandleSignalsState()); | |
124 } | |
125 } | |
126 | |
127 if (!enough_space) | |
128 return MOJO_RESULT_RESOURCE_EXHAUSTED; | |
129 | |
130 return MOJO_RESULT_OK; | |
131 } | |
132 | |
133 HandleSignalsState LocalMessagePipeEndpoint::GetHandleSignalsState() const { | |
134 HandleSignalsState rv; | |
135 if (!message_queue_.IsEmpty()) { | |
136 rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_READABLE; | |
137 rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_READABLE; | |
138 } | |
139 if (is_peer_open_) { | |
140 rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_WRITABLE; | |
141 rv.satisfiable_signals |= | |
142 MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE; | |
143 } else { | |
144 rv.satisfied_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; | |
145 } | |
146 rv.satisfiable_signals |= MOJO_HANDLE_SIGNAL_PEER_CLOSED; | |
147 return rv; | |
148 } | |
149 | |
150 MojoResult LocalMessagePipeEndpoint::AddAwakable( | |
151 Awakable* awakable, | |
152 MojoHandleSignals signals, | |
153 uint32_t context, | |
154 HandleSignalsState* signals_state) { | |
155 DCHECK(is_open_); | |
156 | |
157 HandleSignalsState state = GetHandleSignalsState(); | |
158 if (state.satisfies(signals)) { | |
159 if (signals_state) | |
160 *signals_state = state; | |
161 return MOJO_RESULT_ALREADY_EXISTS; | |
162 } | |
163 if (!state.can_satisfy(signals)) { | |
164 if (signals_state) | |
165 *signals_state = state; | |
166 return MOJO_RESULT_FAILED_PRECONDITION; | |
167 } | |
168 | |
169 awakable_list_.Add(awakable, signals, context); | |
170 return MOJO_RESULT_OK; | |
171 } | |
172 | |
173 void LocalMessagePipeEndpoint::RemoveAwakable( | |
174 Awakable* awakable, | |
175 HandleSignalsState* signals_state) { | |
176 DCHECK(is_open_); | |
177 awakable_list_.Remove(awakable); | |
178 if (signals_state) | |
179 *signals_state = GetHandleSignalsState(); | |
180 } | |
181 | |
182 } // namespace system | |
183 } // namespace mojo | |
OLD | NEW |