| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2015 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 "content/child/shared_memory_data_consumer_handle.h" |
| 6 |
| 7 #include <algorithm> |
| 8 #include <deque> |
| 9 #include <vector> |
| 10 |
| 11 #include "content/public/child/fixed_received_data.h" |
| 12 |
| 13 namespace content { |
| 14 |
| 15 using Result = blink::WebDataConsumerHandle::Result; |
| 16 |
| 17 class SharedMemoryDataConsumerHandle::Context final |
| 18 : public base::RefCountedThreadSafe<Context> { |
| 19 public: |
| 20 Context() |
| 21 : result_(Ok), |
| 22 first_offset_(0), |
| 23 client_(nullptr), |
| 24 is_reader_active_(true) {} |
| 25 |
| 26 bool IsEmpty() const { return queue_.empty(); } |
| 27 void Clear() { |
| 28 for (RequestPeer::ReceivedData* data : queue_) { |
| 29 delete data; |
| 30 } |
| 31 queue_.clear(); |
| 32 first_offset_ = 0; |
| 33 client_ = nullptr; |
| 34 } |
| 35 RequestPeer::ReceivedData* Top() { return queue_.front(); } |
| 36 void Push(scoped_ptr<RequestPeer::ReceivedData> data) { |
| 37 queue_.push_back(data.release()); |
| 38 } |
| 39 size_t first_offset() const { return first_offset_; } |
| 40 Result result() const { return result_; } |
| 41 void set_result(Result r) { result_ = r; } |
| 42 Client* client() { return client_; } |
| 43 void set_client(Client* client) { client_ = client; } |
| 44 bool is_reader_active() const { return is_reader_active_; } |
| 45 void set_is_reader_active(bool b) { is_reader_active_ = b; } |
| 46 void Consume(size_t s) { |
| 47 first_offset_ += s; |
| 48 RequestPeer::ReceivedData* top = Top(); |
| 49 if (static_cast<size_t>(top->length()) <= first_offset_) { |
| 50 delete top; |
| 51 queue_.pop_front(); |
| 52 first_offset_ = 0; |
| 53 } |
| 54 } |
| 55 |
| 56 private: |
| 57 friend class base::RefCountedThreadSafe<Context>; |
| 58 ~Context() { |
| 59 // This is necessary because the queue stores raw pointers. |
| 60 Clear(); |
| 61 } |
| 62 |
| 63 // |result_| stores the ultimate state of this handle if it has. Otherwise, |
| 64 // |Ok| is set. |
| 65 Result result_; |
| 66 // TODO(yhirano): Use std::deque<scoped_ptr<ReceivedData>> once it is allowed. |
| 67 std::deque<RequestPeer::ReceivedData*> queue_; |
| 68 size_t first_offset_; |
| 69 Client* client_; |
| 70 bool is_reader_active_; |
| 71 |
| 72 DISALLOW_COPY_AND_ASSIGN(Context); |
| 73 }; |
| 74 |
| 75 SharedMemoryDataConsumerHandle::Writer::Writer( |
| 76 const scoped_refptr<Context>& context, |
| 77 BackpressureMode mode) |
| 78 : context_(context), mode_(mode) { |
| 79 } |
| 80 |
| 81 SharedMemoryDataConsumerHandle::Writer::~Writer() { |
| 82 Close(); |
| 83 } |
| 84 |
| 85 void SharedMemoryDataConsumerHandle::Writer::AddData( |
| 86 scoped_ptr<RequestPeer::ReceivedData> data) { |
| 87 if (!data->length()) { |
| 88 // We omit empty data. |
| 89 return; |
| 90 } |
| 91 |
| 92 if (!context_->is_reader_active()) { |
| 93 // No one is interested in the data. |
| 94 return; |
| 95 } |
| 96 |
| 97 bool needs_notification = context_->client() && context_->IsEmpty(); |
| 98 scoped_ptr<RequestPeer::ReceivedData> data_to_pass; |
| 99 if (mode_ == kApplyBackpressure) { |
| 100 data_to_pass = data.Pass(); |
| 101 } else { |
| 102 data_to_pass = make_scoped_ptr(new FixedReceivedData(data.get())); |
| 103 } |
| 104 context_->Push(data_to_pass.Pass()); |
| 105 |
| 106 if (needs_notification) |
| 107 context_->client()->didGetReadable(); |
| 108 } |
| 109 |
| 110 void SharedMemoryDataConsumerHandle::Writer::Close() { |
| 111 if (context_->result() == Ok) { |
| 112 context_->set_result(Done); |
| 113 if (context_->client() && context_->IsEmpty()) |
| 114 context_->client()->didGetReadable(); |
| 115 } |
| 116 } |
| 117 |
| 118 SharedMemoryDataConsumerHandle::SharedMemoryDataConsumerHandle( |
| 119 BackpressureMode mode, |
| 120 scoped_ptr<Writer>* writer) |
| 121 : context_(new Context) { |
| 122 writer->reset(new Writer(context_, mode)); |
| 123 } |
| 124 |
| 125 SharedMemoryDataConsumerHandle::~SharedMemoryDataConsumerHandle() { |
| 126 context_->set_is_reader_active(false); |
| 127 context_->Clear(); |
| 128 } |
| 129 |
| 130 Result SharedMemoryDataConsumerHandle::read(void* data, |
| 131 size_t size, |
| 132 Flags flags, |
| 133 size_t* read_size_to_return) { |
| 134 size_t total_read_size = 0; |
| 135 *read_size_to_return = 0; |
| 136 if (context_->result() != Ok && context_->result() != Done) |
| 137 return context_->result(); |
| 138 |
| 139 while (!context_->IsEmpty() && total_read_size < size) { |
| 140 const auto& top = context_->Top(); |
| 141 size_t readable = top->length() - context_->first_offset(); |
| 142 size_t writable = size - total_read_size; |
| 143 size_t read_size = std::min(readable, writable); |
| 144 const char* begin = top->payload() + context_->first_offset(); |
| 145 std::copy(begin, begin + read_size, |
| 146 static_cast<char*>(data) + total_read_size); |
| 147 total_read_size += read_size; |
| 148 context_->Consume(read_size); |
| 149 } |
| 150 *read_size_to_return = total_read_size; |
| 151 return total_read_size ? Ok : context_->result() == Done ? Done : ShouldWait; |
| 152 } |
| 153 |
| 154 Result SharedMemoryDataConsumerHandle::beginRead(const void** buffer, |
| 155 Flags flags, |
| 156 size_t* available) { |
| 157 *buffer = nullptr; |
| 158 *available = 0; |
| 159 |
| 160 if (context_->result() != Ok && context_->result() != Done) |
| 161 return context_->result(); |
| 162 |
| 163 if (context_->IsEmpty()) |
| 164 return context_->result() == Done ? Done : ShouldWait; |
| 165 |
| 166 const auto& top = context_->Top(); |
| 167 *buffer = top->payload() + context_->first_offset(); |
| 168 *available = top->length() - context_->first_offset(); |
| 169 |
| 170 return Ok; |
| 171 } |
| 172 |
| 173 Result SharedMemoryDataConsumerHandle::endRead(size_t read_size) { |
| 174 if (context_->IsEmpty()) |
| 175 return UnexpectedError; |
| 176 |
| 177 context_->Consume(read_size); |
| 178 return Ok; |
| 179 } |
| 180 |
| 181 void SharedMemoryDataConsumerHandle::registerClient(Client* client) { |
| 182 context_->set_client(client); |
| 183 |
| 184 if (!context_->IsEmpty()) |
| 185 client->didGetReadable(); |
| 186 } |
| 187 |
| 188 void SharedMemoryDataConsumerHandle::unregisterClient() { |
| 189 context_->set_client(nullptr); |
| 190 } |
| 191 |
| 192 } // namespace content |
| OLD | NEW |