|  | // 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. | 
|  |  | 
|  | #ifndef MOJO_EDK_SYSTEM_DATA_PIPE_H_ | 
|  | #define MOJO_EDK_SYSTEM_DATA_PIPE_H_ | 
|  |  | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include <memory> | 
|  |  | 
|  | #include "base/compiler_specific.h" | 
|  | #include "mojo/edk/embedder/platform_handle_vector.h" | 
|  | #include "mojo/edk/system/channel_endpoint_client.h" | 
|  | #include "mojo/edk/system/handle_signals_state.h" | 
|  | #include "mojo/edk/system/memory.h" | 
|  | #include "mojo/edk/system/mutex.h" | 
|  | #include "mojo/edk/system/thread_annotations.h" | 
|  | #include "mojo/public/c/system/data_pipe.h" | 
|  | #include "mojo/public/c/system/types.h" | 
|  | #include "mojo/public/cpp/system/macros.h" | 
|  |  | 
|  | namespace mojo { | 
|  | namespace system { | 
|  |  | 
|  | class Awakable; | 
|  | class AwakableList; | 
|  | class Channel; | 
|  | class ChannelEndpoint; | 
|  | class DataPipeImpl; | 
|  | class MessageInTransitQueue; | 
|  |  | 
|  | // |DataPipe| is a base class for secondary objects implementing data pipes, | 
|  | // similar to |MessagePipe| (see the explanatory comment in core.cc). It is | 
|  | // typically owned by the dispatcher(s) corresponding to the local endpoints. | 
|  | // Its subclasses implement the three cases: local producer and consumer, local | 
|  | // producer and remote consumer, and remote producer and local consumer. This | 
|  | // class is thread-safe. | 
|  | class DataPipe final : public ChannelEndpointClient { | 
|  | public: | 
|  | // The default options for |MojoCreateDataPipe()|. (Real uses should obtain | 
|  | // this via |ValidateCreateOptions()| with a null |in_options|; this is | 
|  | // exposed directly for testing convenience.) | 
|  | static MojoCreateDataPipeOptions GetDefaultCreateOptions(); | 
|  |  | 
|  | // Validates and/or sets default options for |MojoCreateDataPipeOptions|. If | 
|  | // non-null, |in_options| must point to a struct of at least | 
|  | // |in_options->struct_size| bytes. |out_options| must point to a (current) | 
|  | // |MojoCreateDataPipeOptions| and will be entirely overwritten on success (it | 
|  | // may be partly overwritten on failure). | 
|  | static MojoResult ValidateCreateOptions( | 
|  | UserPointer<const MojoCreateDataPipeOptions> in_options, | 
|  | MojoCreateDataPipeOptions* out_options); | 
|  |  | 
|  | // Creates a local (both producer and consumer) data pipe (using | 
|  | // |LocalDataPipeImpl|. |validated_options| should be the output of | 
|  | // |ValidateOptions()|. In particular: |struct_size| is ignored (so | 
|  | // |validated_options| must be the current version of the struct) and | 
|  | // |capacity_num_bytes| must be nonzero. | 
|  | static DataPipe* CreateLocal( | 
|  | const MojoCreateDataPipeOptions& validated_options); | 
|  |  | 
|  | // Creates a data pipe with a remote producer and a local consumer, using an | 
|  | // existing |ChannelEndpoint| (whose |ReplaceClient()| it'll call) and taking | 
|  | // |message_queue|'s contents as already-received incoming messages. If | 
|  | // |channel_endpoint| is null, this will create a "half-open" data pipe (with | 
|  | // only the consumer open). Note that this may fail, in which case it returns | 
|  | // null. | 
|  | static DataPipe* CreateRemoteProducerFromExisting( | 
|  | const MojoCreateDataPipeOptions& validated_options, | 
|  | MessageInTransitQueue* message_queue, | 
|  | ChannelEndpoint* channel_endpoint); | 
|  |  | 
|  | // Creates a data pipe with a local producer and a remote consumer, using an | 
|  | // existing |ChannelEndpoint| (whose |ReplaceClient()| it'll call) and taking | 
|  | // |message_queue|'s contents as already-received incoming messages | 
|  | // (|message_queue| may be null). If |channel_endpoint| is null, this will | 
|  | // create a "half-open" data pipe (with only the producer open). Note that | 
|  | // this may fail, in which case it returns null. | 
|  | static DataPipe* CreateRemoteConsumerFromExisting( | 
|  | const MojoCreateDataPipeOptions& validated_options, | 
|  | size_t consumer_num_bytes, | 
|  | MessageInTransitQueue* message_queue, | 
|  | ChannelEndpoint* channel_endpoint); | 
|  |  | 
|  | // Used by |DataPipeProducerDispatcher::Deserialize()|. Returns true on | 
|  | // success (in which case, |*data_pipe| is set appropriately) and false on | 
|  | // failure (in which case |*data_pipe| may or may not be set to null). | 
|  | static bool ProducerDeserialize(Channel* channel, | 
|  | const void* source, | 
|  | size_t size, | 
|  | scoped_refptr<DataPipe>* data_pipe); | 
|  |  | 
|  | // Used by |DataPipeConsumerDispatcher::Deserialize()|. Returns true on | 
|  | // success (in which case, |*data_pipe| is set appropriately) and false on | 
|  | // failure (in which case |*data_pipe| may or may not be set to null). | 
|  | static bool ConsumerDeserialize(Channel* channel, | 
|  | const void* source, | 
|  | size_t size, | 
|  | scoped_refptr<DataPipe>* data_pipe); | 
|  |  | 
|  | // These are called by the producer dispatcher to implement its methods of | 
|  | // corresponding names. | 
|  | void ProducerCancelAllAwakables(); | 
|  | void ProducerClose(); | 
|  | MojoResult ProducerWriteData(UserPointer<const void> elements, | 
|  | UserPointer<uint32_t> num_bytes, | 
|  | bool all_or_none); | 
|  | MojoResult ProducerBeginWriteData(UserPointer<void*> buffer, | 
|  | UserPointer<uint32_t> buffer_num_bytes); | 
|  | MojoResult ProducerEndWriteData(uint32_t num_bytes_written); | 
|  | HandleSignalsState ProducerGetHandleSignalsState(); | 
|  | MojoResult ProducerAddAwakable(Awakable* awakable, | 
|  | MojoHandleSignals signals, | 
|  | uint32_t context, | 
|  | HandleSignalsState* signals_state); | 
|  | void ProducerRemoveAwakable(Awakable* awakable, | 
|  | HandleSignalsState* signals_state); | 
|  | void ProducerStartSerialize(Channel* channel, | 
|  | size_t* max_size, | 
|  | size_t* max_platform_handles); | 
|  | bool ProducerEndSerialize(Channel* channel, | 
|  | void* destination, | 
|  | size_t* actual_size, | 
|  | embedder::PlatformHandleVector* platform_handles); | 
|  | bool ProducerIsBusy() const; | 
|  |  | 
|  | // These are called by the consumer dispatcher to implement its methods of | 
|  | // corresponding names. | 
|  | void ConsumerCancelAllAwakables(); | 
|  | void ConsumerClose(); | 
|  | // This does not validate its arguments, except to check that |*num_bytes| is | 
|  | // a multiple of |element_num_bytes_|. | 
|  | MojoResult ConsumerReadData(UserPointer<void> elements, | 
|  | UserPointer<uint32_t> num_bytes, | 
|  | bool all_or_none, | 
|  | bool peek); | 
|  | MojoResult ConsumerDiscardData(UserPointer<uint32_t> num_bytes, | 
|  | bool all_or_none); | 
|  | MojoResult ConsumerQueryData(UserPointer<uint32_t> num_bytes); | 
|  | MojoResult ConsumerBeginReadData(UserPointer<const void*> buffer, | 
|  | UserPointer<uint32_t> buffer_num_bytes); | 
|  | MojoResult ConsumerEndReadData(uint32_t num_bytes_read); | 
|  | HandleSignalsState ConsumerGetHandleSignalsState(); | 
|  | MojoResult ConsumerAddAwakable(Awakable* awakable, | 
|  | MojoHandleSignals signals, | 
|  | uint32_t context, | 
|  | HandleSignalsState* signals_state); | 
|  | void ConsumerRemoveAwakable(Awakable* awakable, | 
|  | HandleSignalsState* signals_state); | 
|  | void ConsumerStartSerialize(Channel* channel, | 
|  | size_t* max_size, | 
|  | size_t* max_platform_handles); | 
|  | bool ConsumerEndSerialize(Channel* channel, | 
|  | void* destination, | 
|  | size_t* actual_size, | 
|  | embedder::PlatformHandleVector* platform_handles); | 
|  | bool ConsumerIsBusy() const; | 
|  |  | 
|  | // The following are only to be used by |DataPipeImpl| (and its subclasses): | 
|  |  | 
|  | // Replaces |impl_| with |new_impl| (which must not be null). For use when | 
|  | // serializing data pipe dispatchers (i.e., in |ProducerEndSerialize()| and | 
|  | // |ConsumerEndSerialize()|). Returns the old value of |impl_| (in case the | 
|  | // caller needs to manage its lifetime). | 
|  | std::unique_ptr<DataPipeImpl> ReplaceImplNoLock( | 
|  | std::unique_ptr<DataPipeImpl> new_impl) | 
|  | MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_); | 
|  | void SetProducerClosedNoLock() MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_); | 
|  | void SetConsumerClosedNoLock() MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_); | 
|  |  | 
|  | void ProducerCloseNoLock() MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_); | 
|  | void ConsumerCloseNoLock() MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_); | 
|  |  | 
|  | // Thread-safe and fast (they don't take |mutex_|): | 
|  | const MojoCreateDataPipeOptions& validated_options() const { | 
|  | return validated_options_; | 
|  | } | 
|  | size_t element_num_bytes() const { | 
|  | return validated_options_.element_num_bytes; | 
|  | } | 
|  | size_t capacity_num_bytes() const { | 
|  | return validated_options_.capacity_num_bytes; | 
|  | } | 
|  |  | 
|  | // Must be called under |mutex_|. | 
|  | bool producer_open_no_lock() const MOJO_SHARED_LOCKS_REQUIRED(mutex_) { | 
|  | mutex_.AssertHeld(); | 
|  | return producer_open_; | 
|  | } | 
|  | bool consumer_open_no_lock() const MOJO_SHARED_LOCKS_REQUIRED(mutex_) { | 
|  | mutex_.AssertHeld(); | 
|  | return consumer_open_; | 
|  | } | 
|  | uint32_t producer_two_phase_max_num_bytes_written_no_lock() const | 
|  | MOJO_SHARED_LOCKS_REQUIRED(mutex_) { | 
|  | mutex_.AssertHeld(); | 
|  | return producer_two_phase_max_num_bytes_written_; | 
|  | } | 
|  | uint32_t consumer_two_phase_max_num_bytes_read_no_lock() const | 
|  | MOJO_SHARED_LOCKS_REQUIRED(mutex_) { | 
|  | mutex_.AssertHeld(); | 
|  | return consumer_two_phase_max_num_bytes_read_; | 
|  | } | 
|  | void set_producer_two_phase_max_num_bytes_written_no_lock(uint32_t num_bytes) | 
|  | MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_) { | 
|  | mutex_.AssertHeld(); | 
|  | producer_two_phase_max_num_bytes_written_ = num_bytes; | 
|  | } | 
|  | void set_consumer_two_phase_max_num_bytes_read_no_lock(uint32_t num_bytes) | 
|  | MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_) { | 
|  | mutex_.AssertHeld(); | 
|  | consumer_two_phase_max_num_bytes_read_ = num_bytes; | 
|  | } | 
|  | bool producer_in_two_phase_write_no_lock() const | 
|  | MOJO_SHARED_LOCKS_REQUIRED(mutex_) { | 
|  | mutex_.AssertHeld(); | 
|  | return producer_two_phase_max_num_bytes_written_ > 0; | 
|  | } | 
|  | bool consumer_in_two_phase_read_no_lock() const | 
|  | MOJO_SHARED_LOCKS_REQUIRED(mutex_) { | 
|  | mutex_.AssertHeld(); | 
|  | return consumer_two_phase_max_num_bytes_read_ > 0; | 
|  | } | 
|  |  | 
|  | private: | 
|  | // |validated_options| should be the output of |ValidateOptions()|. In | 
|  | // particular: |struct_size| is ignored (so |validated_options| must be the | 
|  | // current version of the struct) and |capacity_num_bytes| must be nonzero. | 
|  | // TODO(vtl): |has_local_producer|/|has_local_consumer| shouldn't really be | 
|  | // arguments here. Instead, they should be determined from the |impl| ... but | 
|  | // the |impl|'s typically figures these out by examining the owner, i.e., the | 
|  | // |DataPipe| object. Probably, this indicates that more stuff should be moved | 
|  | // to |DataPipeImpl|, but for now we'll live with this. | 
|  | DataPipe(bool has_local_producer, | 
|  | bool has_local_consumer, | 
|  | const MojoCreateDataPipeOptions& validated_options, | 
|  | std::unique_ptr<DataPipeImpl> impl); | 
|  | ~DataPipe() override; | 
|  |  | 
|  | // |ChannelEndpointClient| implementation: | 
|  | bool OnReadMessage(unsigned port, MessageInTransit* message) override; | 
|  | void OnDetachFromChannel(unsigned port) override; | 
|  |  | 
|  | void AwakeProducerAwakablesForStateChangeNoLock( | 
|  | const HandleSignalsState& new_producer_state) | 
|  | MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_); | 
|  | void AwakeConsumerAwakablesForStateChangeNoLock( | 
|  | const HandleSignalsState& new_consumer_state) | 
|  | MOJO_EXCLUSIVE_LOCKS_REQUIRED(mutex_); | 
|  |  | 
|  | void SetProducerClosed(); | 
|  | void SetConsumerClosed(); | 
|  |  | 
|  | bool has_local_producer_no_lock() const MOJO_SHARED_LOCKS_REQUIRED(mutex_) { | 
|  | mutex_.AssertHeld(); | 
|  | return !!producer_awakable_list_; | 
|  | } | 
|  | bool has_local_consumer_no_lock() const MOJO_SHARED_LOCKS_REQUIRED(mutex_) { | 
|  | mutex_.AssertHeld(); | 
|  | return !!consumer_awakable_list_; | 
|  | } | 
|  |  | 
|  | MSVC_SUPPRESS_WARNING(4324) | 
|  | const MojoCreateDataPipeOptions validated_options_; | 
|  |  | 
|  | mutable Mutex mutex_; | 
|  | // *Known* state of producer or consumer. | 
|  | bool producer_open_ MOJO_GUARDED_BY(mutex_); | 
|  | bool consumer_open_ MOJO_GUARDED_BY(mutex_); | 
|  | // Non-null only if the producer or consumer, respectively, is local. | 
|  | std::unique_ptr<AwakableList> producer_awakable_list_ MOJO_GUARDED_BY(mutex_); | 
|  | std::unique_ptr<AwakableList> consumer_awakable_list_ MOJO_GUARDED_BY(mutex_); | 
|  | // These are nonzero if and only if a two-phase write/read is in progress. | 
|  | uint32_t producer_two_phase_max_num_bytes_written_ MOJO_GUARDED_BY(mutex_); | 
|  | uint32_t consumer_two_phase_max_num_bytes_read_ MOJO_GUARDED_BY(mutex_); | 
|  | std::unique_ptr<DataPipeImpl> impl_ MOJO_GUARDED_BY(mutex_); | 
|  |  | 
|  | MOJO_DISALLOW_COPY_AND_ASSIGN(DataPipe); | 
|  | }; | 
|  |  | 
|  | }  // namespace system | 
|  | }  // namespace mojo | 
|  |  | 
|  | #endif  // MOJO_EDK_SYSTEM_DATA_PIPE_H_ |