Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(87)

Side by Side Diff: mojo/edk/system/data_pipe.cc

Issue 814543006: Move //mojo/{public, edk} underneath //third_party (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « mojo/edk/system/data_pipe.h ('k') | mojo/edk/system/data_pipe_consumer_dispatcher.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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/data_pipe.h"
6
7 #include <string.h>
8
9 #include <algorithm>
10 #include <limits>
11
12 #include "base/logging.h"
13 #include "mojo/edk/system/awakable_list.h"
14 #include "mojo/edk/system/configuration.h"
15 #include "mojo/edk/system/memory.h"
16 #include "mojo/edk/system/options_validation.h"
17
18 namespace mojo {
19 namespace system {
20
21 // static
22 MojoCreateDataPipeOptions DataPipe::GetDefaultCreateOptions() {
23 MojoCreateDataPipeOptions result = {
24 static_cast<uint32_t>(sizeof(MojoCreateDataPipeOptions)),
25 MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE,
26 1u,
27 static_cast<uint32_t>(
28 GetConfiguration().default_data_pipe_capacity_bytes)};
29 return result;
30 }
31
32 // static
33 MojoResult DataPipe::ValidateCreateOptions(
34 UserPointer<const MojoCreateDataPipeOptions> in_options,
35 MojoCreateDataPipeOptions* out_options) {
36 const MojoCreateDataPipeOptionsFlags kKnownFlags =
37 MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD;
38
39 *out_options = GetDefaultCreateOptions();
40 if (in_options.IsNull())
41 return MOJO_RESULT_OK;
42
43 UserOptionsReader<MojoCreateDataPipeOptions> reader(in_options);
44 if (!reader.is_valid())
45 return MOJO_RESULT_INVALID_ARGUMENT;
46
47 if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateDataPipeOptions, flags, reader))
48 return MOJO_RESULT_OK;
49 if ((reader.options().flags & ~kKnownFlags))
50 return MOJO_RESULT_UNIMPLEMENTED;
51 out_options->flags = reader.options().flags;
52
53 // Checks for fields beyond |flags|:
54
55 if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateDataPipeOptions, element_num_bytes,
56 reader))
57 return MOJO_RESULT_OK;
58 if (reader.options().element_num_bytes == 0)
59 return MOJO_RESULT_INVALID_ARGUMENT;
60 out_options->element_num_bytes = reader.options().element_num_bytes;
61
62 if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateDataPipeOptions, capacity_num_bytes,
63 reader) ||
64 reader.options().capacity_num_bytes == 0) {
65 // Round the default capacity down to a multiple of the element size (but at
66 // least one element).
67 size_t default_data_pipe_capacity_bytes =
68 GetConfiguration().default_data_pipe_capacity_bytes;
69 out_options->capacity_num_bytes =
70 std::max(static_cast<uint32_t>(default_data_pipe_capacity_bytes -
71 (default_data_pipe_capacity_bytes %
72 out_options->element_num_bytes)),
73 out_options->element_num_bytes);
74 return MOJO_RESULT_OK;
75 }
76 if (reader.options().capacity_num_bytes % out_options->element_num_bytes != 0)
77 return MOJO_RESULT_INVALID_ARGUMENT;
78 if (reader.options().capacity_num_bytes >
79 GetConfiguration().max_data_pipe_capacity_bytes)
80 return MOJO_RESULT_RESOURCE_EXHAUSTED;
81 out_options->capacity_num_bytes = reader.options().capacity_num_bytes;
82
83 return MOJO_RESULT_OK;
84 }
85
86 void DataPipe::ProducerCancelAllAwakables() {
87 base::AutoLock locker(lock_);
88 DCHECK(has_local_producer_no_lock());
89 producer_awakable_list_->CancelAll();
90 }
91
92 void DataPipe::ProducerClose() {
93 base::AutoLock locker(lock_);
94 DCHECK(producer_open_);
95 producer_open_ = false;
96 DCHECK(has_local_producer_no_lock());
97 producer_awakable_list_.reset();
98 // Not a bug, except possibly in "user" code.
99 DVLOG_IF(2, producer_in_two_phase_write_no_lock())
100 << "Producer closed with active two-phase write";
101 producer_two_phase_max_num_bytes_written_ = 0;
102 ProducerCloseImplNoLock();
103 AwakeConsumerAwakablesForStateChangeNoLock(
104 ConsumerGetHandleSignalsStateImplNoLock());
105 }
106
107 MojoResult DataPipe::ProducerWriteData(UserPointer<const void> elements,
108 UserPointer<uint32_t> num_bytes,
109 bool all_or_none) {
110 base::AutoLock locker(lock_);
111 DCHECK(has_local_producer_no_lock());
112
113 if (producer_in_two_phase_write_no_lock())
114 return MOJO_RESULT_BUSY;
115 if (!consumer_open_no_lock())
116 return MOJO_RESULT_FAILED_PRECONDITION;
117
118 // Returning "busy" takes priority over "invalid argument".
119 uint32_t max_num_bytes_to_write = num_bytes.Get();
120 if (max_num_bytes_to_write % element_num_bytes_ != 0)
121 return MOJO_RESULT_INVALID_ARGUMENT;
122
123 if (max_num_bytes_to_write == 0)
124 return MOJO_RESULT_OK; // Nothing to do.
125
126 uint32_t min_num_bytes_to_write = all_or_none ? max_num_bytes_to_write : 0;
127
128 HandleSignalsState old_consumer_state =
129 ConsumerGetHandleSignalsStateImplNoLock();
130 MojoResult rv = ProducerWriteDataImplNoLock(
131 elements, num_bytes, max_num_bytes_to_write, min_num_bytes_to_write);
132 HandleSignalsState new_consumer_state =
133 ConsumerGetHandleSignalsStateImplNoLock();
134 if (!new_consumer_state.equals(old_consumer_state))
135 AwakeConsumerAwakablesForStateChangeNoLock(new_consumer_state);
136 return rv;
137 }
138
139 MojoResult DataPipe::ProducerBeginWriteData(
140 UserPointer<void*> buffer,
141 UserPointer<uint32_t> buffer_num_bytes,
142 bool all_or_none) {
143 base::AutoLock locker(lock_);
144 DCHECK(has_local_producer_no_lock());
145
146 if (producer_in_two_phase_write_no_lock())
147 return MOJO_RESULT_BUSY;
148 if (!consumer_open_no_lock())
149 return MOJO_RESULT_FAILED_PRECONDITION;
150
151 uint32_t min_num_bytes_to_write = 0;
152 if (all_or_none) {
153 min_num_bytes_to_write = buffer_num_bytes.Get();
154 if (min_num_bytes_to_write % element_num_bytes_ != 0)
155 return MOJO_RESULT_INVALID_ARGUMENT;
156 }
157
158 MojoResult rv = ProducerBeginWriteDataImplNoLock(buffer, buffer_num_bytes,
159 min_num_bytes_to_write);
160 if (rv != MOJO_RESULT_OK)
161 return rv;
162 // Note: No need to awake producer awakables, even though we're going from
163 // writable to non-writable (since you can't wait on non-writability).
164 // Similarly, though this may have discarded data (in "may discard" mode),
165 // making it non-readable, there's still no need to awake consumer awakables.
166 DCHECK(producer_in_two_phase_write_no_lock());
167 return MOJO_RESULT_OK;
168 }
169
170 MojoResult DataPipe::ProducerEndWriteData(uint32_t num_bytes_written) {
171 base::AutoLock locker(lock_);
172 DCHECK(has_local_producer_no_lock());
173
174 if (!producer_in_two_phase_write_no_lock())
175 return MOJO_RESULT_FAILED_PRECONDITION;
176 // Note: Allow successful completion of the two-phase write even if the
177 // consumer has been closed.
178
179 HandleSignalsState old_consumer_state =
180 ConsumerGetHandleSignalsStateImplNoLock();
181 MojoResult rv;
182 if (num_bytes_written > producer_two_phase_max_num_bytes_written_ ||
183 num_bytes_written % element_num_bytes_ != 0) {
184 rv = MOJO_RESULT_INVALID_ARGUMENT;
185 producer_two_phase_max_num_bytes_written_ = 0;
186 } else {
187 rv = ProducerEndWriteDataImplNoLock(num_bytes_written);
188 }
189 // Two-phase write ended even on failure.
190 DCHECK(!producer_in_two_phase_write_no_lock());
191 // If we're now writable, we *became* writable (since we weren't writable
192 // during the two-phase write), so awake producer awakables.
193 HandleSignalsState new_producer_state =
194 ProducerGetHandleSignalsStateImplNoLock();
195 if (new_producer_state.satisfies(MOJO_HANDLE_SIGNAL_WRITABLE))
196 AwakeProducerAwakablesForStateChangeNoLock(new_producer_state);
197 HandleSignalsState new_consumer_state =
198 ConsumerGetHandleSignalsStateImplNoLock();
199 if (!new_consumer_state.equals(old_consumer_state))
200 AwakeConsumerAwakablesForStateChangeNoLock(new_consumer_state);
201 return rv;
202 }
203
204 HandleSignalsState DataPipe::ProducerGetHandleSignalsState() {
205 base::AutoLock locker(lock_);
206 DCHECK(has_local_producer_no_lock());
207 return ProducerGetHandleSignalsStateImplNoLock();
208 }
209
210 MojoResult DataPipe::ProducerAddAwakable(Awakable* awakable,
211 MojoHandleSignals signals,
212 uint32_t context,
213 HandleSignalsState* signals_state) {
214 base::AutoLock locker(lock_);
215 DCHECK(has_local_producer_no_lock());
216
217 HandleSignalsState producer_state = ProducerGetHandleSignalsStateImplNoLock();
218 if (producer_state.satisfies(signals)) {
219 if (signals_state)
220 *signals_state = producer_state;
221 return MOJO_RESULT_ALREADY_EXISTS;
222 }
223 if (!producer_state.can_satisfy(signals)) {
224 if (signals_state)
225 *signals_state = producer_state;
226 return MOJO_RESULT_FAILED_PRECONDITION;
227 }
228
229 producer_awakable_list_->Add(awakable, signals, context);
230 return MOJO_RESULT_OK;
231 }
232
233 void DataPipe::ProducerRemoveAwakable(Awakable* awakable,
234 HandleSignalsState* signals_state) {
235 base::AutoLock locker(lock_);
236 DCHECK(has_local_producer_no_lock());
237 producer_awakable_list_->Remove(awakable);
238 if (signals_state)
239 *signals_state = ProducerGetHandleSignalsStateImplNoLock();
240 }
241
242 bool DataPipe::ProducerIsBusy() const {
243 base::AutoLock locker(lock_);
244 return producer_in_two_phase_write_no_lock();
245 }
246
247 void DataPipe::ConsumerCancelAllAwakables() {
248 base::AutoLock locker(lock_);
249 DCHECK(has_local_consumer_no_lock());
250 consumer_awakable_list_->CancelAll();
251 }
252
253 void DataPipe::ConsumerClose() {
254 base::AutoLock locker(lock_);
255 DCHECK(consumer_open_);
256 consumer_open_ = false;
257 DCHECK(has_local_consumer_no_lock());
258 consumer_awakable_list_.reset();
259 // Not a bug, except possibly in "user" code.
260 DVLOG_IF(2, consumer_in_two_phase_read_no_lock())
261 << "Consumer closed with active two-phase read";
262 consumer_two_phase_max_num_bytes_read_ = 0;
263 ConsumerCloseImplNoLock();
264 AwakeProducerAwakablesForStateChangeNoLock(
265 ProducerGetHandleSignalsStateImplNoLock());
266 }
267
268 MojoResult DataPipe::ConsumerReadData(UserPointer<void> elements,
269 UserPointer<uint32_t> num_bytes,
270 bool all_or_none,
271 bool peek) {
272 base::AutoLock locker(lock_);
273 DCHECK(has_local_consumer_no_lock());
274
275 if (consumer_in_two_phase_read_no_lock())
276 return MOJO_RESULT_BUSY;
277
278 uint32_t max_num_bytes_to_read = num_bytes.Get();
279 if (max_num_bytes_to_read % element_num_bytes_ != 0)
280 return MOJO_RESULT_INVALID_ARGUMENT;
281
282 if (max_num_bytes_to_read == 0)
283 return MOJO_RESULT_OK; // Nothing to do.
284
285 uint32_t min_num_bytes_to_read = all_or_none ? max_num_bytes_to_read : 0;
286
287 HandleSignalsState old_producer_state =
288 ProducerGetHandleSignalsStateImplNoLock();
289 MojoResult rv = ConsumerReadDataImplNoLock(
290 elements, num_bytes, max_num_bytes_to_read, min_num_bytes_to_read, peek);
291 HandleSignalsState new_producer_state =
292 ProducerGetHandleSignalsStateImplNoLock();
293 if (!new_producer_state.equals(old_producer_state))
294 AwakeProducerAwakablesForStateChangeNoLock(new_producer_state);
295 return rv;
296 }
297
298 MojoResult DataPipe::ConsumerDiscardData(UserPointer<uint32_t> num_bytes,
299 bool all_or_none) {
300 base::AutoLock locker(lock_);
301 DCHECK(has_local_consumer_no_lock());
302
303 if (consumer_in_two_phase_read_no_lock())
304 return MOJO_RESULT_BUSY;
305
306 uint32_t max_num_bytes_to_discard = num_bytes.Get();
307 if (max_num_bytes_to_discard % element_num_bytes_ != 0)
308 return MOJO_RESULT_INVALID_ARGUMENT;
309
310 if (max_num_bytes_to_discard == 0)
311 return MOJO_RESULT_OK; // Nothing to do.
312
313 uint32_t min_num_bytes_to_discard =
314 all_or_none ? max_num_bytes_to_discard : 0;
315
316 HandleSignalsState old_producer_state =
317 ProducerGetHandleSignalsStateImplNoLock();
318 MojoResult rv = ConsumerDiscardDataImplNoLock(
319 num_bytes, max_num_bytes_to_discard, min_num_bytes_to_discard);
320 HandleSignalsState new_producer_state =
321 ProducerGetHandleSignalsStateImplNoLock();
322 if (!new_producer_state.equals(old_producer_state))
323 AwakeProducerAwakablesForStateChangeNoLock(new_producer_state);
324 return rv;
325 }
326
327 MojoResult DataPipe::ConsumerQueryData(UserPointer<uint32_t> num_bytes) {
328 base::AutoLock locker(lock_);
329 DCHECK(has_local_consumer_no_lock());
330
331 if (consumer_in_two_phase_read_no_lock())
332 return MOJO_RESULT_BUSY;
333
334 // Note: Don't need to validate |*num_bytes| for query.
335 return ConsumerQueryDataImplNoLock(num_bytes);
336 }
337
338 MojoResult DataPipe::ConsumerBeginReadData(
339 UserPointer<const void*> buffer,
340 UserPointer<uint32_t> buffer_num_bytes,
341 bool all_or_none) {
342 base::AutoLock locker(lock_);
343 DCHECK(has_local_consumer_no_lock());
344
345 if (consumer_in_two_phase_read_no_lock())
346 return MOJO_RESULT_BUSY;
347
348 uint32_t min_num_bytes_to_read = 0;
349 if (all_or_none) {
350 min_num_bytes_to_read = buffer_num_bytes.Get();
351 if (min_num_bytes_to_read % element_num_bytes_ != 0)
352 return MOJO_RESULT_INVALID_ARGUMENT;
353 }
354
355 MojoResult rv = ConsumerBeginReadDataImplNoLock(buffer, buffer_num_bytes,
356 min_num_bytes_to_read);
357 if (rv != MOJO_RESULT_OK)
358 return rv;
359 DCHECK(consumer_in_two_phase_read_no_lock());
360 return MOJO_RESULT_OK;
361 }
362
363 MojoResult DataPipe::ConsumerEndReadData(uint32_t num_bytes_read) {
364 base::AutoLock locker(lock_);
365 DCHECK(has_local_consumer_no_lock());
366
367 if (!consumer_in_two_phase_read_no_lock())
368 return MOJO_RESULT_FAILED_PRECONDITION;
369
370 HandleSignalsState old_producer_state =
371 ProducerGetHandleSignalsStateImplNoLock();
372 MojoResult rv;
373 if (num_bytes_read > consumer_two_phase_max_num_bytes_read_ ||
374 num_bytes_read % element_num_bytes_ != 0) {
375 rv = MOJO_RESULT_INVALID_ARGUMENT;
376 consumer_two_phase_max_num_bytes_read_ = 0;
377 } else {
378 rv = ConsumerEndReadDataImplNoLock(num_bytes_read);
379 }
380 // Two-phase read ended even on failure.
381 DCHECK(!consumer_in_two_phase_read_no_lock());
382 // If we're now readable, we *became* readable (since we weren't readable
383 // during the two-phase read), so awake consumer awakables.
384 HandleSignalsState new_consumer_state =
385 ConsumerGetHandleSignalsStateImplNoLock();
386 if (new_consumer_state.satisfies(MOJO_HANDLE_SIGNAL_READABLE))
387 AwakeConsumerAwakablesForStateChangeNoLock(new_consumer_state);
388 HandleSignalsState new_producer_state =
389 ProducerGetHandleSignalsStateImplNoLock();
390 if (!new_producer_state.equals(old_producer_state))
391 AwakeProducerAwakablesForStateChangeNoLock(new_producer_state);
392 return rv;
393 }
394
395 HandleSignalsState DataPipe::ConsumerGetHandleSignalsState() {
396 base::AutoLock locker(lock_);
397 DCHECK(has_local_consumer_no_lock());
398 return ConsumerGetHandleSignalsStateImplNoLock();
399 }
400
401 MojoResult DataPipe::ConsumerAddAwakable(Awakable* awakable,
402 MojoHandleSignals signals,
403 uint32_t context,
404 HandleSignalsState* signals_state) {
405 base::AutoLock locker(lock_);
406 DCHECK(has_local_consumer_no_lock());
407
408 HandleSignalsState consumer_state = ConsumerGetHandleSignalsStateImplNoLock();
409 if (consumer_state.satisfies(signals)) {
410 if (signals_state)
411 *signals_state = consumer_state;
412 return MOJO_RESULT_ALREADY_EXISTS;
413 }
414 if (!consumer_state.can_satisfy(signals)) {
415 if (signals_state)
416 *signals_state = consumer_state;
417 return MOJO_RESULT_FAILED_PRECONDITION;
418 }
419
420 consumer_awakable_list_->Add(awakable, signals, context);
421 return MOJO_RESULT_OK;
422 }
423
424 void DataPipe::ConsumerRemoveAwakable(Awakable* awakable,
425 HandleSignalsState* signals_state) {
426 base::AutoLock locker(lock_);
427 DCHECK(has_local_consumer_no_lock());
428 consumer_awakable_list_->Remove(awakable);
429 if (signals_state)
430 *signals_state = ConsumerGetHandleSignalsStateImplNoLock();
431 }
432
433 bool DataPipe::ConsumerIsBusy() const {
434 base::AutoLock locker(lock_);
435 return consumer_in_two_phase_read_no_lock();
436 }
437
438 DataPipe::DataPipe(bool has_local_producer,
439 bool has_local_consumer,
440 const MojoCreateDataPipeOptions& validated_options)
441 : may_discard_((validated_options.flags &
442 MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD)),
443 element_num_bytes_(validated_options.element_num_bytes),
444 capacity_num_bytes_(validated_options.capacity_num_bytes),
445 producer_open_(true),
446 consumer_open_(true),
447 producer_awakable_list_(has_local_producer ? new AwakableList()
448 : nullptr),
449 consumer_awakable_list_(has_local_consumer ? new AwakableList()
450 : nullptr),
451 producer_two_phase_max_num_bytes_written_(0),
452 consumer_two_phase_max_num_bytes_read_(0) {
453 // Check that the passed in options actually are validated.
454 MojoCreateDataPipeOptions unused = {0};
455 DCHECK_EQ(ValidateCreateOptions(MakeUserPointer(&validated_options), &unused),
456 MOJO_RESULT_OK);
457 }
458
459 DataPipe::~DataPipe() {
460 DCHECK(!producer_open_);
461 DCHECK(!consumer_open_);
462 DCHECK(!producer_awakable_list_);
463 DCHECK(!consumer_awakable_list_);
464 }
465
466 void DataPipe::AwakeProducerAwakablesForStateChangeNoLock(
467 const HandleSignalsState& new_producer_state) {
468 lock_.AssertAcquired();
469 if (!has_local_producer_no_lock())
470 return;
471 producer_awakable_list_->AwakeForStateChange(new_producer_state);
472 }
473
474 void DataPipe::AwakeConsumerAwakablesForStateChangeNoLock(
475 const HandleSignalsState& new_consumer_state) {
476 lock_.AssertAcquired();
477 if (!has_local_consumer_no_lock())
478 return;
479 consumer_awakable_list_->AwakeForStateChange(new_consumer_state);
480 }
481
482 } // namespace system
483 } // namespace mojo
OLDNEW
« no previous file with comments | « mojo/edk/system/data_pipe.h ('k') | mojo/edk/system/data_pipe_consumer_dispatcher.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698