767657d4280f954f57e0b976219a60dcdd9b5ca3
[platform/framework/web/crosswalk.git] / src / mojo / system / data_pipe.cc
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/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/system/constants.h"
15 #include "mojo/system/memory.h"
16 #include "mojo/system/options_validation.h"
17 #include "mojo/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