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/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 | |
OLD | NEW |