diff options
Diffstat (limited to 'mojo/edk/system/data_pipe.cc')
-rw-r--r-- | mojo/edk/system/data_pipe.cc | 483 |
1 files changed, 0 insertions, 483 deletions
diff --git a/mojo/edk/system/data_pipe.cc b/mojo/edk/system/data_pipe.cc deleted file mode 100644 index 2f433bd..0000000 --- a/mojo/edk/system/data_pipe.cc +++ /dev/null @@ -1,483 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "mojo/edk/system/data_pipe.h" - -#include <string.h> - -#include <algorithm> -#include <limits> - -#include "base/logging.h" -#include "mojo/edk/system/awakable_list.h" -#include "mojo/edk/system/configuration.h" -#include "mojo/edk/system/memory.h" -#include "mojo/edk/system/options_validation.h" - -namespace mojo { -namespace system { - -// static -MojoCreateDataPipeOptions DataPipe::GetDefaultCreateOptions() { - MojoCreateDataPipeOptions result = { - static_cast<uint32_t>(sizeof(MojoCreateDataPipeOptions)), - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_NONE, - 1u, - static_cast<uint32_t>( - GetConfiguration().default_data_pipe_capacity_bytes)}; - return result; -} - -// static -MojoResult DataPipe::ValidateCreateOptions( - UserPointer<const MojoCreateDataPipeOptions> in_options, - MojoCreateDataPipeOptions* out_options) { - const MojoCreateDataPipeOptionsFlags kKnownFlags = - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD; - - *out_options = GetDefaultCreateOptions(); - if (in_options.IsNull()) - return MOJO_RESULT_OK; - - UserOptionsReader<MojoCreateDataPipeOptions> reader(in_options); - if (!reader.is_valid()) - return MOJO_RESULT_INVALID_ARGUMENT; - - if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateDataPipeOptions, flags, reader)) - return MOJO_RESULT_OK; - if ((reader.options().flags & ~kKnownFlags)) - return MOJO_RESULT_UNIMPLEMENTED; - out_options->flags = reader.options().flags; - - // Checks for fields beyond |flags|: - - if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateDataPipeOptions, element_num_bytes, - reader)) - return MOJO_RESULT_OK; - if (reader.options().element_num_bytes == 0) - return MOJO_RESULT_INVALID_ARGUMENT; - out_options->element_num_bytes = reader.options().element_num_bytes; - - if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateDataPipeOptions, capacity_num_bytes, - reader) || - reader.options().capacity_num_bytes == 0) { - // Round the default capacity down to a multiple of the element size (but at - // least one element). - size_t default_data_pipe_capacity_bytes = - GetConfiguration().default_data_pipe_capacity_bytes; - out_options->capacity_num_bytes = - std::max(static_cast<uint32_t>(default_data_pipe_capacity_bytes - - (default_data_pipe_capacity_bytes % - out_options->element_num_bytes)), - out_options->element_num_bytes); - return MOJO_RESULT_OK; - } - if (reader.options().capacity_num_bytes % out_options->element_num_bytes != 0) - return MOJO_RESULT_INVALID_ARGUMENT; - if (reader.options().capacity_num_bytes > - GetConfiguration().max_data_pipe_capacity_bytes) - return MOJO_RESULT_RESOURCE_EXHAUSTED; - out_options->capacity_num_bytes = reader.options().capacity_num_bytes; - - return MOJO_RESULT_OK; -} - -void DataPipe::ProducerCancelAllAwakables() { - base::AutoLock locker(lock_); - DCHECK(has_local_producer_no_lock()); - producer_awakable_list_->CancelAll(); -} - -void DataPipe::ProducerClose() { - base::AutoLock locker(lock_); - DCHECK(producer_open_); - producer_open_ = false; - DCHECK(has_local_producer_no_lock()); - producer_awakable_list_.reset(); - // Not a bug, except possibly in "user" code. - DVLOG_IF(2, producer_in_two_phase_write_no_lock()) - << "Producer closed with active two-phase write"; - producer_two_phase_max_num_bytes_written_ = 0; - ProducerCloseImplNoLock(); - AwakeConsumerAwakablesForStateChangeNoLock( - ConsumerGetHandleSignalsStateImplNoLock()); -} - -MojoResult DataPipe::ProducerWriteData(UserPointer<const void> elements, - UserPointer<uint32_t> num_bytes, - bool all_or_none) { - base::AutoLock locker(lock_); - DCHECK(has_local_producer_no_lock()); - - if (producer_in_two_phase_write_no_lock()) - return MOJO_RESULT_BUSY; - if (!consumer_open_no_lock()) - return MOJO_RESULT_FAILED_PRECONDITION; - - // Returning "busy" takes priority over "invalid argument". - uint32_t max_num_bytes_to_write = num_bytes.Get(); - if (max_num_bytes_to_write % element_num_bytes_ != 0) - return MOJO_RESULT_INVALID_ARGUMENT; - - if (max_num_bytes_to_write == 0) - return MOJO_RESULT_OK; // Nothing to do. - - uint32_t min_num_bytes_to_write = all_or_none ? max_num_bytes_to_write : 0; - - HandleSignalsState old_consumer_state = - ConsumerGetHandleSignalsStateImplNoLock(); - MojoResult rv = ProducerWriteDataImplNoLock( - elements, num_bytes, max_num_bytes_to_write, min_num_bytes_to_write); - HandleSignalsState new_consumer_state = - ConsumerGetHandleSignalsStateImplNoLock(); - if (!new_consumer_state.equals(old_consumer_state)) - AwakeConsumerAwakablesForStateChangeNoLock(new_consumer_state); - return rv; -} - -MojoResult DataPipe::ProducerBeginWriteData( - UserPointer<void*> buffer, - UserPointer<uint32_t> buffer_num_bytes, - bool all_or_none) { - base::AutoLock locker(lock_); - DCHECK(has_local_producer_no_lock()); - - if (producer_in_two_phase_write_no_lock()) - return MOJO_RESULT_BUSY; - if (!consumer_open_no_lock()) - return MOJO_RESULT_FAILED_PRECONDITION; - - uint32_t min_num_bytes_to_write = 0; - if (all_or_none) { - min_num_bytes_to_write = buffer_num_bytes.Get(); - if (min_num_bytes_to_write % element_num_bytes_ != 0) - return MOJO_RESULT_INVALID_ARGUMENT; - } - - MojoResult rv = ProducerBeginWriteDataImplNoLock(buffer, buffer_num_bytes, - min_num_bytes_to_write); - if (rv != MOJO_RESULT_OK) - return rv; - // Note: No need to awake producer awakables, even though we're going from - // writable to non-writable (since you can't wait on non-writability). - // Similarly, though this may have discarded data (in "may discard" mode), - // making it non-readable, there's still no need to awake consumer awakables. - DCHECK(producer_in_two_phase_write_no_lock()); - return MOJO_RESULT_OK; -} - -MojoResult DataPipe::ProducerEndWriteData(uint32_t num_bytes_written) { - base::AutoLock locker(lock_); - DCHECK(has_local_producer_no_lock()); - - if (!producer_in_two_phase_write_no_lock()) - return MOJO_RESULT_FAILED_PRECONDITION; - // Note: Allow successful completion of the two-phase write even if the - // consumer has been closed. - - HandleSignalsState old_consumer_state = - ConsumerGetHandleSignalsStateImplNoLock(); - MojoResult rv; - if (num_bytes_written > producer_two_phase_max_num_bytes_written_ || - num_bytes_written % element_num_bytes_ != 0) { - rv = MOJO_RESULT_INVALID_ARGUMENT; - producer_two_phase_max_num_bytes_written_ = 0; - } else { - rv = ProducerEndWriteDataImplNoLock(num_bytes_written); - } - // Two-phase write ended even on failure. - DCHECK(!producer_in_two_phase_write_no_lock()); - // If we're now writable, we *became* writable (since we weren't writable - // during the two-phase write), so awake producer awakables. - HandleSignalsState new_producer_state = - ProducerGetHandleSignalsStateImplNoLock(); - if (new_producer_state.satisfies(MOJO_HANDLE_SIGNAL_WRITABLE)) - AwakeProducerAwakablesForStateChangeNoLock(new_producer_state); - HandleSignalsState new_consumer_state = - ConsumerGetHandleSignalsStateImplNoLock(); - if (!new_consumer_state.equals(old_consumer_state)) - AwakeConsumerAwakablesForStateChangeNoLock(new_consumer_state); - return rv; -} - -HandleSignalsState DataPipe::ProducerGetHandleSignalsState() { - base::AutoLock locker(lock_); - DCHECK(has_local_producer_no_lock()); - return ProducerGetHandleSignalsStateImplNoLock(); -} - -MojoResult DataPipe::ProducerAddAwakable(Awakable* awakable, - MojoHandleSignals signals, - uint32_t context, - HandleSignalsState* signals_state) { - base::AutoLock locker(lock_); - DCHECK(has_local_producer_no_lock()); - - HandleSignalsState producer_state = ProducerGetHandleSignalsStateImplNoLock(); - if (producer_state.satisfies(signals)) { - if (signals_state) - *signals_state = producer_state; - return MOJO_RESULT_ALREADY_EXISTS; - } - if (!producer_state.can_satisfy(signals)) { - if (signals_state) - *signals_state = producer_state; - return MOJO_RESULT_FAILED_PRECONDITION; - } - - producer_awakable_list_->Add(awakable, signals, context); - return MOJO_RESULT_OK; -} - -void DataPipe::ProducerRemoveAwakable(Awakable* awakable, - HandleSignalsState* signals_state) { - base::AutoLock locker(lock_); - DCHECK(has_local_producer_no_lock()); - producer_awakable_list_->Remove(awakable); - if (signals_state) - *signals_state = ProducerGetHandleSignalsStateImplNoLock(); -} - -bool DataPipe::ProducerIsBusy() const { - base::AutoLock locker(lock_); - return producer_in_two_phase_write_no_lock(); -} - -void DataPipe::ConsumerCancelAllAwakables() { - base::AutoLock locker(lock_); - DCHECK(has_local_consumer_no_lock()); - consumer_awakable_list_->CancelAll(); -} - -void DataPipe::ConsumerClose() { - base::AutoLock locker(lock_); - DCHECK(consumer_open_); - consumer_open_ = false; - DCHECK(has_local_consumer_no_lock()); - consumer_awakable_list_.reset(); - // Not a bug, except possibly in "user" code. - DVLOG_IF(2, consumer_in_two_phase_read_no_lock()) - << "Consumer closed with active two-phase read"; - consumer_two_phase_max_num_bytes_read_ = 0; - ConsumerCloseImplNoLock(); - AwakeProducerAwakablesForStateChangeNoLock( - ProducerGetHandleSignalsStateImplNoLock()); -} - -MojoResult DataPipe::ConsumerReadData(UserPointer<void> elements, - UserPointer<uint32_t> num_bytes, - bool all_or_none, - bool peek) { - base::AutoLock locker(lock_); - DCHECK(has_local_consumer_no_lock()); - - if (consumer_in_two_phase_read_no_lock()) - return MOJO_RESULT_BUSY; - - uint32_t max_num_bytes_to_read = num_bytes.Get(); - if (max_num_bytes_to_read % element_num_bytes_ != 0) - return MOJO_RESULT_INVALID_ARGUMENT; - - if (max_num_bytes_to_read == 0) - return MOJO_RESULT_OK; // Nothing to do. - - uint32_t min_num_bytes_to_read = all_or_none ? max_num_bytes_to_read : 0; - - HandleSignalsState old_producer_state = - ProducerGetHandleSignalsStateImplNoLock(); - MojoResult rv = ConsumerReadDataImplNoLock( - elements, num_bytes, max_num_bytes_to_read, min_num_bytes_to_read, peek); - HandleSignalsState new_producer_state = - ProducerGetHandleSignalsStateImplNoLock(); - if (!new_producer_state.equals(old_producer_state)) - AwakeProducerAwakablesForStateChangeNoLock(new_producer_state); - return rv; -} - -MojoResult DataPipe::ConsumerDiscardData(UserPointer<uint32_t> num_bytes, - bool all_or_none) { - base::AutoLock locker(lock_); - DCHECK(has_local_consumer_no_lock()); - - if (consumer_in_two_phase_read_no_lock()) - return MOJO_RESULT_BUSY; - - uint32_t max_num_bytes_to_discard = num_bytes.Get(); - if (max_num_bytes_to_discard % element_num_bytes_ != 0) - return MOJO_RESULT_INVALID_ARGUMENT; - - if (max_num_bytes_to_discard == 0) - return MOJO_RESULT_OK; // Nothing to do. - - uint32_t min_num_bytes_to_discard = - all_or_none ? max_num_bytes_to_discard : 0; - - HandleSignalsState old_producer_state = - ProducerGetHandleSignalsStateImplNoLock(); - MojoResult rv = ConsumerDiscardDataImplNoLock( - num_bytes, max_num_bytes_to_discard, min_num_bytes_to_discard); - HandleSignalsState new_producer_state = - ProducerGetHandleSignalsStateImplNoLock(); - if (!new_producer_state.equals(old_producer_state)) - AwakeProducerAwakablesForStateChangeNoLock(new_producer_state); - return rv; -} - -MojoResult DataPipe::ConsumerQueryData(UserPointer<uint32_t> num_bytes) { - base::AutoLock locker(lock_); - DCHECK(has_local_consumer_no_lock()); - - if (consumer_in_two_phase_read_no_lock()) - return MOJO_RESULT_BUSY; - - // Note: Don't need to validate |*num_bytes| for query. - return ConsumerQueryDataImplNoLock(num_bytes); -} - -MojoResult DataPipe::ConsumerBeginReadData( - UserPointer<const void*> buffer, - UserPointer<uint32_t> buffer_num_bytes, - bool all_or_none) { - base::AutoLock locker(lock_); - DCHECK(has_local_consumer_no_lock()); - - if (consumer_in_two_phase_read_no_lock()) - return MOJO_RESULT_BUSY; - - uint32_t min_num_bytes_to_read = 0; - if (all_or_none) { - min_num_bytes_to_read = buffer_num_bytes.Get(); - if (min_num_bytes_to_read % element_num_bytes_ != 0) - return MOJO_RESULT_INVALID_ARGUMENT; - } - - MojoResult rv = ConsumerBeginReadDataImplNoLock(buffer, buffer_num_bytes, - min_num_bytes_to_read); - if (rv != MOJO_RESULT_OK) - return rv; - DCHECK(consumer_in_two_phase_read_no_lock()); - return MOJO_RESULT_OK; -} - -MojoResult DataPipe::ConsumerEndReadData(uint32_t num_bytes_read) { - base::AutoLock locker(lock_); - DCHECK(has_local_consumer_no_lock()); - - if (!consumer_in_two_phase_read_no_lock()) - return MOJO_RESULT_FAILED_PRECONDITION; - - HandleSignalsState old_producer_state = - ProducerGetHandleSignalsStateImplNoLock(); - MojoResult rv; - if (num_bytes_read > consumer_two_phase_max_num_bytes_read_ || - num_bytes_read % element_num_bytes_ != 0) { - rv = MOJO_RESULT_INVALID_ARGUMENT; - consumer_two_phase_max_num_bytes_read_ = 0; - } else { - rv = ConsumerEndReadDataImplNoLock(num_bytes_read); - } - // Two-phase read ended even on failure. - DCHECK(!consumer_in_two_phase_read_no_lock()); - // If we're now readable, we *became* readable (since we weren't readable - // during the two-phase read), so awake consumer awakables. - HandleSignalsState new_consumer_state = - ConsumerGetHandleSignalsStateImplNoLock(); - if (new_consumer_state.satisfies(MOJO_HANDLE_SIGNAL_READABLE)) - AwakeConsumerAwakablesForStateChangeNoLock(new_consumer_state); - HandleSignalsState new_producer_state = - ProducerGetHandleSignalsStateImplNoLock(); - if (!new_producer_state.equals(old_producer_state)) - AwakeProducerAwakablesForStateChangeNoLock(new_producer_state); - return rv; -} - -HandleSignalsState DataPipe::ConsumerGetHandleSignalsState() { - base::AutoLock locker(lock_); - DCHECK(has_local_consumer_no_lock()); - return ConsumerGetHandleSignalsStateImplNoLock(); -} - -MojoResult DataPipe::ConsumerAddAwakable(Awakable* awakable, - MojoHandleSignals signals, - uint32_t context, - HandleSignalsState* signals_state) { - base::AutoLock locker(lock_); - DCHECK(has_local_consumer_no_lock()); - - HandleSignalsState consumer_state = ConsumerGetHandleSignalsStateImplNoLock(); - if (consumer_state.satisfies(signals)) { - if (signals_state) - *signals_state = consumer_state; - return MOJO_RESULT_ALREADY_EXISTS; - } - if (!consumer_state.can_satisfy(signals)) { - if (signals_state) - *signals_state = consumer_state; - return MOJO_RESULT_FAILED_PRECONDITION; - } - - consumer_awakable_list_->Add(awakable, signals, context); - return MOJO_RESULT_OK; -} - -void DataPipe::ConsumerRemoveAwakable(Awakable* awakable, - HandleSignalsState* signals_state) { - base::AutoLock locker(lock_); - DCHECK(has_local_consumer_no_lock()); - consumer_awakable_list_->Remove(awakable); - if (signals_state) - *signals_state = ConsumerGetHandleSignalsStateImplNoLock(); -} - -bool DataPipe::ConsumerIsBusy() const { - base::AutoLock locker(lock_); - return consumer_in_two_phase_read_no_lock(); -} - -DataPipe::DataPipe(bool has_local_producer, - bool has_local_consumer, - const MojoCreateDataPipeOptions& validated_options) - : may_discard_((validated_options.flags & - MOJO_CREATE_DATA_PIPE_OPTIONS_FLAG_MAY_DISCARD)), - element_num_bytes_(validated_options.element_num_bytes), - capacity_num_bytes_(validated_options.capacity_num_bytes), - producer_open_(true), - consumer_open_(true), - producer_awakable_list_(has_local_producer ? new AwakableList() - : nullptr), - consumer_awakable_list_(has_local_consumer ? new AwakableList() - : nullptr), - producer_two_phase_max_num_bytes_written_(0), - consumer_two_phase_max_num_bytes_read_(0) { - // Check that the passed in options actually are validated. - MojoCreateDataPipeOptions unused = {0}; - DCHECK_EQ(ValidateCreateOptions(MakeUserPointer(&validated_options), &unused), - MOJO_RESULT_OK); -} - -DataPipe::~DataPipe() { - DCHECK(!producer_open_); - DCHECK(!consumer_open_); - DCHECK(!producer_awakable_list_); - DCHECK(!consumer_awakable_list_); -} - -void DataPipe::AwakeProducerAwakablesForStateChangeNoLock( - const HandleSignalsState& new_producer_state) { - lock_.AssertAcquired(); - if (!has_local_producer_no_lock()) - return; - producer_awakable_list_->AwakeForStateChange(new_producer_state); -} - -void DataPipe::AwakeConsumerAwakablesForStateChangeNoLock( - const HandleSignalsState& new_consumer_state) { - lock_.AssertAcquired(); - if (!has_local_consumer_no_lock()) - return; - consumer_awakable_list_->AwakeForStateChange(new_consumer_state); -} - -} // namespace system -} // namespace mojo |