OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // TODO(vtl): I currently potentially overflow in doing index calculations. | 5 // TODO(vtl): I currently potentially overflow in doing index calculations. |
6 // E.g., |start_index_| and |current_num_bytes_| fit into a |uint32_t|, but | 6 // E.g., |start_index_| and |current_num_bytes_| fit into a |uint32_t|, but |
7 // their sum may not. This is bad and poses a security risk. (We're currently | 7 // their sum may not. This is bad and poses a security risk. (We're currently |
8 // saved by the limit on capacity -- the maximum size of the buffer, checked in | 8 // saved by the limit on capacity -- the maximum size of the buffer, checked in |
9 // |DataPipe::ValidateOptions()|, is currently sufficiently small. | 9 // |DataPipe::ValidateOptions()|, is currently sufficiently small. |
10 | 10 |
(...skipping 24 matching lines...) Expand all Loading... |
35 // If the consumer is still open and we still have data, we have to keep the | 35 // If the consumer is still open and we still have data, we have to keep the |
36 // buffer around. Currently, we won't free it even if it empties later. (We | 36 // buffer around. Currently, we won't free it even if it empties later. (We |
37 // could do this -- requiring a check on every read -- but that seems to be | 37 // could do this -- requiring a check on every read -- but that seems to be |
38 // optimizing for the uncommon case.) | 38 // optimizing for the uncommon case.) |
39 if (!consumer_open_no_lock() || !current_num_bytes_) { | 39 if (!consumer_open_no_lock() || !current_num_bytes_) { |
40 // Note: There can only be a two-phase *read* (by the consumer) if we still | 40 // Note: There can only be a two-phase *read* (by the consumer) if we still |
41 // have data. | 41 // have data. |
42 DCHECK(!consumer_in_two_phase_read_no_lock()); | 42 DCHECK(!consumer_in_two_phase_read_no_lock()); |
43 DestroyBufferNoLock(); | 43 DestroyBufferNoLock(); |
44 } | 44 } |
45 AwakeConsumerWaitersForStateChangeNoLock(); | |
46 } | 45 } |
47 | 46 |
48 MojoResult LocalDataPipe::ProducerWriteDataImplNoLock(const void* elements, | 47 MojoResult LocalDataPipe::ProducerWriteDataImplNoLock(const void* elements, |
49 uint32_t* num_bytes, | 48 uint32_t* num_bytes, |
50 bool all_or_none) { | 49 bool all_or_none) { |
51 DCHECK_EQ(*num_bytes % element_num_bytes(), 0u); | 50 DCHECK_EQ(*num_bytes % element_num_bytes(), 0u); |
52 DCHECK_GT(*num_bytes, 0u); | 51 DCHECK_GT(*num_bytes, 0u); |
53 DCHECK(consumer_open_no_lock()); | 52 DCHECK(consumer_open_no_lock()); |
54 | 53 |
55 size_t num_bytes_to_write = 0; | 54 size_t num_bytes_to_write = 0; |
56 if (may_discard()) { | 55 if (may_discard()) { |
57 if (all_or_none && *num_bytes > capacity_num_bytes()) | 56 if (all_or_none && *num_bytes > capacity_num_bytes()) |
58 return MOJO_RESULT_OUT_OF_RANGE; | 57 return MOJO_RESULT_OUT_OF_RANGE; |
59 | 58 |
60 num_bytes_to_write = std::min(static_cast<size_t>(*num_bytes), | 59 num_bytes_to_write = std::min(static_cast<size_t>(*num_bytes), |
61 capacity_num_bytes()); | 60 capacity_num_bytes()); |
62 if (num_bytes_to_write > capacity_num_bytes() - current_num_bytes_) { | 61 if (num_bytes_to_write > capacity_num_bytes() - current_num_bytes_) { |
63 // Discard as much as needed (discard oldest first). | 62 // Discard as much as needed (discard oldest first). |
64 size_t num_bytes_to_discard = | 63 MarkDataAsConsumedNoLock( |
65 num_bytes_to_write - (capacity_num_bytes() - current_num_bytes_); | 64 num_bytes_to_write - (capacity_num_bytes() - current_num_bytes_)); |
66 start_index_ += num_bytes_to_discard; | 65 // No need to wake up write waiters, since we're definitely going to leave |
67 start_index_ %= capacity_num_bytes(); | 66 // the buffer full. |
68 current_num_bytes_ -= num_bytes_to_discard; | |
69 } | 67 } |
70 } else { | 68 } else { |
71 if (all_or_none && *num_bytes > capacity_num_bytes() - current_num_bytes_) { | 69 if (all_or_none && *num_bytes > capacity_num_bytes() - current_num_bytes_) { |
72 // Don't return "should wait" since you can't wait for a specified amount | 70 // Don't return "should wait" since you can't wait for a specified amount |
73 // of data. | 71 // of data. |
74 return MOJO_RESULT_OUT_OF_RANGE; | 72 return MOJO_RESULT_OUT_OF_RANGE; |
75 } | 73 } |
76 | 74 |
77 num_bytes_to_write = std::min(static_cast<size_t>(*num_bytes), | 75 num_bytes_to_write = std::min(static_cast<size_t>(*num_bytes), |
78 capacity_num_bytes() - current_num_bytes_); | 76 capacity_num_bytes() - current_num_bytes_); |
(...skipping 10 matching lines...) Expand all Loading... |
89 EnsureBufferNoLock(); | 87 EnsureBufferNoLock(); |
90 memcpy(buffer_.get() + first_write_index, elements, num_bytes_to_write_first); | 88 memcpy(buffer_.get() + first_write_index, elements, num_bytes_to_write_first); |
91 | 89 |
92 if (num_bytes_to_write_first < num_bytes_to_write) { | 90 if (num_bytes_to_write_first < num_bytes_to_write) { |
93 // The "second write index" is zero. | 91 // The "second write index" is zero. |
94 memcpy(buffer_.get(), | 92 memcpy(buffer_.get(), |
95 static_cast<const char*>(elements) + num_bytes_to_write_first, | 93 static_cast<const char*>(elements) + num_bytes_to_write_first, |
96 num_bytes_to_write - num_bytes_to_write_first); | 94 num_bytes_to_write - num_bytes_to_write_first); |
97 } | 95 } |
98 | 96 |
99 bool was_empty = (current_num_bytes_ == 0); | |
100 | |
101 current_num_bytes_ += num_bytes_to_write; | 97 current_num_bytes_ += num_bytes_to_write; |
102 DCHECK_LE(current_num_bytes_, capacity_num_bytes()); | 98 DCHECK_LE(current_num_bytes_, capacity_num_bytes()); |
103 | |
104 if (was_empty && num_bytes_to_write > 0) | |
105 AwakeConsumerWaitersForStateChangeNoLock(); | |
106 | |
107 *num_bytes = static_cast<uint32_t>(num_bytes_to_write); | 99 *num_bytes = static_cast<uint32_t>(num_bytes_to_write); |
108 return MOJO_RESULT_OK; | 100 return MOJO_RESULT_OK; |
109 } | 101 } |
110 | 102 |
111 MojoResult LocalDataPipe::ProducerBeginWriteDataImplNoLock( | 103 MojoResult LocalDataPipe::ProducerBeginWriteDataImplNoLock( |
112 void** buffer, | 104 void** buffer, |
113 uint32_t* buffer_num_bytes, | 105 uint32_t* buffer_num_bytes, |
114 bool all_or_none) { | 106 bool all_or_none) { |
115 DCHECK(consumer_open_no_lock()); | 107 DCHECK(consumer_open_no_lock()); |
116 | 108 |
| 109 // The index we need to start writing at. |
| 110 size_t write_index = |
| 111 (start_index_ + current_num_bytes_) % capacity_num_bytes(); |
| 112 |
117 size_t max_num_bytes_to_write = GetMaxNumBytesToWriteNoLock(); | 113 size_t max_num_bytes_to_write = GetMaxNumBytesToWriteNoLock(); |
118 if (all_or_none && *buffer_num_bytes > max_num_bytes_to_write) { | 114 if (all_or_none && *buffer_num_bytes > max_num_bytes_to_write) { |
119 // Don't return "should wait" since you can't wait for a specified amount of | 115 // In "may discard" mode, we can always write from the write index to the |
120 // data. | 116 // end of the buffer. |
121 return MOJO_RESULT_OUT_OF_RANGE; | 117 if (may_discard() && |
| 118 *buffer_num_bytes <= capacity_num_bytes() - write_index) { |
| 119 // To do so, we need to discard an appropriate amount of data. |
| 120 // We should only reach here if the start index is after the write index! |
| 121 DCHECK_GE(start_index_, write_index); |
| 122 DCHECK_GT(*buffer_num_bytes - max_num_bytes_to_write, 0u); |
| 123 MarkDataAsConsumedNoLock(*buffer_num_bytes - max_num_bytes_to_write); |
| 124 max_num_bytes_to_write = *buffer_num_bytes; |
| 125 } else { |
| 126 // Don't return "should wait" since you can't wait for a specified amount |
| 127 // of data. |
| 128 return MOJO_RESULT_OUT_OF_RANGE; |
| 129 } |
122 } | 130 } |
123 | 131 |
124 // Don't go into a two-phase write if there's no room. | 132 // Don't go into a two-phase write if there's no room. |
125 if (max_num_bytes_to_write == 0) | 133 if (max_num_bytes_to_write == 0) |
126 return MOJO_RESULT_SHOULD_WAIT; | 134 return MOJO_RESULT_SHOULD_WAIT; |
127 | 135 |
128 size_t write_index = | |
129 (start_index_ + current_num_bytes_) % capacity_num_bytes(); | |
130 EnsureBufferNoLock(); | 136 EnsureBufferNoLock(); |
131 *buffer = buffer_.get() + write_index; | 137 *buffer = buffer_.get() + write_index; |
132 *buffer_num_bytes = static_cast<uint32_t>(max_num_bytes_to_write); | 138 *buffer_num_bytes = static_cast<uint32_t>(max_num_bytes_to_write); |
133 set_producer_two_phase_max_num_bytes_written_no_lock( | 139 set_producer_two_phase_max_num_bytes_written_no_lock( |
134 static_cast<uint32_t>(max_num_bytes_to_write)); | 140 static_cast<uint32_t>(max_num_bytes_to_write)); |
135 return MOJO_RESULT_OK; | 141 return MOJO_RESULT_OK; |
136 } | 142 } |
137 | 143 |
138 MojoResult LocalDataPipe::ProducerEndWriteDataImplNoLock( | 144 MojoResult LocalDataPipe::ProducerEndWriteDataImplNoLock( |
139 uint32_t num_bytes_written) { | 145 uint32_t num_bytes_written) { |
140 if (num_bytes_written > producer_two_phase_max_num_bytes_written_no_lock()) { | 146 if (num_bytes_written > producer_two_phase_max_num_bytes_written_no_lock()) { |
141 // Note: The two-phase write ends here even on failure. | 147 // Note: The two-phase write ends here even on failure. |
142 set_producer_two_phase_max_num_bytes_written_no_lock(0); | 148 set_producer_two_phase_max_num_bytes_written_no_lock(0); |
143 return MOJO_RESULT_INVALID_ARGUMENT; | 149 return MOJO_RESULT_INVALID_ARGUMENT; |
144 } | 150 } |
145 | 151 |
146 bool was_empty = (current_num_bytes_ == 0); | |
147 | |
148 current_num_bytes_ += num_bytes_written; | 152 current_num_bytes_ += num_bytes_written; |
149 DCHECK_LE(current_num_bytes_, capacity_num_bytes()); | 153 DCHECK_LE(current_num_bytes_, capacity_num_bytes()); |
150 set_producer_two_phase_max_num_bytes_written_no_lock(0); | 154 set_producer_two_phase_max_num_bytes_written_no_lock(0); |
151 | |
152 if (was_empty && num_bytes_written > 0) | |
153 AwakeConsumerWaitersForStateChangeNoLock(); | |
154 | |
155 return MOJO_RESULT_OK; | 155 return MOJO_RESULT_OK; |
156 } | 156 } |
157 | 157 |
158 MojoWaitFlags LocalDataPipe::ProducerSatisfiedFlagsNoLock() { | 158 MojoWaitFlags LocalDataPipe::ProducerSatisfiedFlagsNoLock() { |
159 MojoWaitFlags rv = MOJO_WAIT_FLAG_NONE; | 159 MojoWaitFlags rv = MOJO_WAIT_FLAG_NONE; |
160 if (consumer_open_no_lock() && current_num_bytes_ < capacity_num_bytes()) | 160 if (consumer_open_no_lock() && |
| 161 (may_discard() || current_num_bytes_ < capacity_num_bytes()) && |
| 162 !producer_in_two_phase_write_no_lock()) |
161 rv |= MOJO_WAIT_FLAG_WRITABLE; | 163 rv |= MOJO_WAIT_FLAG_WRITABLE; |
162 return rv; | 164 return rv; |
163 } | 165 } |
164 | 166 |
165 MojoWaitFlags LocalDataPipe::ProducerSatisfiableFlagsNoLock() { | 167 MojoWaitFlags LocalDataPipe::ProducerSatisfiableFlagsNoLock() { |
166 MojoWaitFlags rv = MOJO_WAIT_FLAG_NONE; | 168 MojoWaitFlags rv = MOJO_WAIT_FLAG_NONE; |
167 if (consumer_open_no_lock()) | 169 if (consumer_open_no_lock()) |
168 rv |= MOJO_WAIT_FLAG_WRITABLE; | 170 rv |= MOJO_WAIT_FLAG_WRITABLE; |
169 return rv; | 171 return rv; |
170 } | 172 } |
171 | 173 |
172 void LocalDataPipe::ConsumerCloseImplNoLock() { | 174 void LocalDataPipe::ConsumerCloseImplNoLock() { |
173 // If the producer is around and in a two-phase write, we have to keep the | 175 // If the producer is around and in a two-phase write, we have to keep the |
174 // buffer around. (We then don't free it until the producer is closed. This | 176 // buffer around. (We then don't free it until the producer is closed. This |
175 // could be rectified, but again seems like optimizing for the uncommon case.) | 177 // could be rectified, but again seems like optimizing for the uncommon case.) |
176 if (!producer_open_no_lock() || !producer_in_two_phase_write_no_lock()) | 178 if (!producer_open_no_lock() || !producer_in_two_phase_write_no_lock()) |
177 DestroyBufferNoLock(); | 179 DestroyBufferNoLock(); |
178 current_num_bytes_ = 0; | 180 current_num_bytes_ = 0; |
179 AwakeProducerWaitersForStateChangeNoLock(); | |
180 } | 181 } |
181 | 182 |
182 MojoResult LocalDataPipe::ConsumerReadDataImplNoLock(void* elements, | 183 MojoResult LocalDataPipe::ConsumerReadDataImplNoLock(void* elements, |
183 uint32_t* num_bytes, | 184 uint32_t* num_bytes, |
184 bool all_or_none) { | 185 bool all_or_none) { |
185 DCHECK_EQ(*num_bytes % element_num_bytes(), 0u); | 186 DCHECK_EQ(*num_bytes % element_num_bytes(), 0u); |
186 DCHECK_GT(*num_bytes, 0u); | 187 DCHECK_GT(*num_bytes, 0u); |
187 | 188 |
188 if (all_or_none && *num_bytes > current_num_bytes_) { | 189 if (all_or_none && *num_bytes > current_num_bytes_) { |
189 // Don't return "should wait" since you can't wait for a specified amount of | 190 // Don't return "should wait" since you can't wait for a specified amount of |
(...skipping 14 matching lines...) Expand all Loading... |
204 std::min(num_bytes_to_read, GetMaxNumBytesToReadNoLock()); | 205 std::min(num_bytes_to_read, GetMaxNumBytesToReadNoLock()); |
205 memcpy(elements, buffer_.get() + start_index_, num_bytes_to_read_first); | 206 memcpy(elements, buffer_.get() + start_index_, num_bytes_to_read_first); |
206 | 207 |
207 if (num_bytes_to_read_first < num_bytes_to_read) { | 208 if (num_bytes_to_read_first < num_bytes_to_read) { |
208 // The "second read index" is zero. | 209 // The "second read index" is zero. |
209 memcpy(static_cast<char*>(elements) + num_bytes_to_read_first, | 210 memcpy(static_cast<char*>(elements) + num_bytes_to_read_first, |
210 buffer_.get(), | 211 buffer_.get(), |
211 num_bytes_to_read - num_bytes_to_read_first); | 212 num_bytes_to_read - num_bytes_to_read_first); |
212 } | 213 } |
213 | 214 |
214 bool was_full = (current_num_bytes_ == capacity_num_bytes()); | 215 MarkDataAsConsumedNoLock(num_bytes_to_read); |
215 | |
216 start_index_ += num_bytes_to_read; | |
217 start_index_ %= capacity_num_bytes(); | |
218 current_num_bytes_ -= num_bytes_to_read; | |
219 | |
220 if (was_full && num_bytes_to_read > 0) | |
221 AwakeProducerWaitersForStateChangeNoLock(); | |
222 | |
223 *num_bytes = static_cast<uint32_t>(num_bytes_to_read); | 216 *num_bytes = static_cast<uint32_t>(num_bytes_to_read); |
224 return MOJO_RESULT_OK; | 217 return MOJO_RESULT_OK; |
225 } | 218 } |
226 | 219 |
227 MojoResult LocalDataPipe::ConsumerDiscardDataImplNoLock(uint32_t* num_bytes, | 220 MojoResult LocalDataPipe::ConsumerDiscardDataImplNoLock(uint32_t* num_bytes, |
228 bool all_or_none) { | 221 bool all_or_none) { |
229 DCHECK_EQ(*num_bytes % element_num_bytes(), 0u); | 222 DCHECK_EQ(*num_bytes % element_num_bytes(), 0u); |
230 DCHECK_GT(*num_bytes, 0u); | 223 DCHECK_GT(*num_bytes, 0u); |
231 | 224 |
232 if (all_or_none && *num_bytes > current_num_bytes_) { | 225 if (all_or_none && *num_bytes > current_num_bytes_) { |
233 // Don't return "should wait" since you can't wait for a specified amount of | 226 // Don't return "should wait" since you can't wait for a specified amount of |
234 // data. | 227 // data. |
235 return producer_open_no_lock() ? MOJO_RESULT_OUT_OF_RANGE : | 228 return producer_open_no_lock() ? MOJO_RESULT_OUT_OF_RANGE : |
236 MOJO_RESULT_FAILED_PRECONDITION; | 229 MOJO_RESULT_FAILED_PRECONDITION; |
237 } | 230 } |
238 | 231 |
239 // Be consistent with other operations; error if no data available. | 232 // Be consistent with other operations; error if no data available. |
240 if (current_num_bytes_ == 0) { | 233 if (current_num_bytes_ == 0) { |
241 return producer_open_no_lock() ? MOJO_RESULT_SHOULD_WAIT : | 234 return producer_open_no_lock() ? MOJO_RESULT_SHOULD_WAIT : |
242 MOJO_RESULT_FAILED_PRECONDITION; | 235 MOJO_RESULT_FAILED_PRECONDITION; |
243 } | 236 } |
244 | 237 |
245 bool was_full = (current_num_bytes_ == capacity_num_bytes()); | |
246 | |
247 size_t num_bytes_to_discard = | 238 size_t num_bytes_to_discard = |
248 std::min(static_cast<size_t>(*num_bytes), current_num_bytes_); | 239 std::min(static_cast<size_t>(*num_bytes), current_num_bytes_); |
249 start_index_ = (start_index_ + num_bytes_to_discard) % capacity_num_bytes(); | 240 MarkDataAsConsumedNoLock(num_bytes_to_discard); |
250 current_num_bytes_ -= num_bytes_to_discard; | |
251 | |
252 if (was_full && num_bytes_to_discard > 0) | |
253 AwakeProducerWaitersForStateChangeNoLock(); | |
254 | |
255 *num_bytes = static_cast<uint32_t>(num_bytes_to_discard); | 241 *num_bytes = static_cast<uint32_t>(num_bytes_to_discard); |
256 return MOJO_RESULT_OK; | 242 return MOJO_RESULT_OK; |
257 } | 243 } |
258 | 244 |
259 MojoResult LocalDataPipe::ConsumerQueryDataImplNoLock(uint32_t* num_bytes) { | 245 MojoResult LocalDataPipe::ConsumerQueryDataImplNoLock(uint32_t* num_bytes) { |
260 // Note: This cast is safe, since the capacity fits into a |uint32_t|. | 246 // Note: This cast is safe, since the capacity fits into a |uint32_t|. |
261 *num_bytes = static_cast<uint32_t>(current_num_bytes_); | 247 *num_bytes = static_cast<uint32_t>(current_num_bytes_); |
262 return MOJO_RESULT_OK; | 248 return MOJO_RESULT_OK; |
263 } | 249 } |
264 | 250 |
(...skipping 23 matching lines...) Expand all Loading... |
288 } | 274 } |
289 | 275 |
290 MojoResult LocalDataPipe::ConsumerEndReadDataImplNoLock( | 276 MojoResult LocalDataPipe::ConsumerEndReadDataImplNoLock( |
291 uint32_t num_bytes_read) { | 277 uint32_t num_bytes_read) { |
292 if (num_bytes_read > consumer_two_phase_max_num_bytes_read_no_lock()) { | 278 if (num_bytes_read > consumer_two_phase_max_num_bytes_read_no_lock()) { |
293 // Note: The two-phase read ends here even on failure. | 279 // Note: The two-phase read ends here even on failure. |
294 set_consumer_two_phase_max_num_bytes_read_no_lock(0); | 280 set_consumer_two_phase_max_num_bytes_read_no_lock(0); |
295 return MOJO_RESULT_INVALID_ARGUMENT; | 281 return MOJO_RESULT_INVALID_ARGUMENT; |
296 } | 282 } |
297 | 283 |
298 bool was_full = (current_num_bytes_ == capacity_num_bytes()); | 284 DCHECK_LE(start_index_ + num_bytes_read, capacity_num_bytes()); |
299 | 285 MarkDataAsConsumedNoLock(num_bytes_read); |
300 start_index_ += num_bytes_read; | |
301 DCHECK_LE(start_index_, capacity_num_bytes()); | |
302 start_index_ %= capacity_num_bytes(); | |
303 DCHECK_LE(num_bytes_read, current_num_bytes_); | |
304 current_num_bytes_ -= num_bytes_read; | |
305 set_consumer_two_phase_max_num_bytes_read_no_lock(0); | 286 set_consumer_two_phase_max_num_bytes_read_no_lock(0); |
306 | |
307 if (was_full && num_bytes_read > 0) | |
308 AwakeProducerWaitersForStateChangeNoLock(); | |
309 | |
310 return MOJO_RESULT_OK; | 287 return MOJO_RESULT_OK; |
311 } | 288 } |
312 | 289 |
313 MojoWaitFlags LocalDataPipe::ConsumerSatisfiedFlagsNoLock() { | 290 MojoWaitFlags LocalDataPipe::ConsumerSatisfiedFlagsNoLock() { |
314 MojoWaitFlags rv = MOJO_WAIT_FLAG_NONE; | 291 MojoWaitFlags rv = MOJO_WAIT_FLAG_NONE; |
315 if (current_num_bytes_ > 0) | 292 if (current_num_bytes_ > 0 && !consumer_in_two_phase_read_no_lock()) |
316 rv |= MOJO_WAIT_FLAG_READABLE; | 293 rv |= MOJO_WAIT_FLAG_READABLE; |
317 return rv; | 294 return rv; |
318 } | 295 } |
319 | 296 |
320 MojoWaitFlags LocalDataPipe::ConsumerSatisfiableFlagsNoLock() { | 297 MojoWaitFlags LocalDataPipe::ConsumerSatisfiableFlagsNoLock() { |
321 MojoWaitFlags rv = MOJO_WAIT_FLAG_NONE; | 298 MojoWaitFlags rv = MOJO_WAIT_FLAG_NONE; |
322 if (current_num_bytes_ > 0 || producer_open_no_lock()) | 299 if (current_num_bytes_ > 0 || producer_open_no_lock()) |
323 rv |= MOJO_WAIT_FLAG_READABLE; | 300 rv |= MOJO_WAIT_FLAG_READABLE; |
324 return rv; | 301 return rv; |
325 } | 302 } |
(...skipping 27 matching lines...) Expand all Loading... |
353 } | 330 } |
354 return capacity_num_bytes() - next_index; | 331 return capacity_num_bytes() - next_index; |
355 } | 332 } |
356 | 333 |
357 size_t LocalDataPipe::GetMaxNumBytesToReadNoLock() { | 334 size_t LocalDataPipe::GetMaxNumBytesToReadNoLock() { |
358 if (start_index_ + current_num_bytes_ > capacity_num_bytes()) | 335 if (start_index_ + current_num_bytes_ > capacity_num_bytes()) |
359 return capacity_num_bytes() - start_index_; | 336 return capacity_num_bytes() - start_index_; |
360 return current_num_bytes_; | 337 return current_num_bytes_; |
361 } | 338 } |
362 | 339 |
| 340 void LocalDataPipe::MarkDataAsConsumedNoLock(size_t num_bytes) { |
| 341 DCHECK_LE(num_bytes, current_num_bytes_); |
| 342 start_index_ += num_bytes; |
| 343 start_index_ %= capacity_num_bytes(); |
| 344 current_num_bytes_ -= num_bytes; |
| 345 } |
| 346 |
363 } // namespace system | 347 } // namespace system |
364 } // namespace mojo | 348 } // namespace mojo |
OLD | NEW |