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