| 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 |