// 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_SYSTEM_DATA_PIPE_H_ #define MOJO_SYSTEM_DATA_PIPE_H_ #include #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/synchronization/lock.h" #include "mojo/public/c/system/data_pipe.h" #include "mojo/public/c/system/types.h" #include "mojo/system/handle_signals_state.h" #include "mojo/system/memory.h" #include "mojo/system/system_impl_export.h" namespace mojo { namespace system { class Waiter; class WaiterList; // |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 MOJO_SYSTEM_IMPL_EXPORT DataPipe : public base::RefCountedThreadSafe { 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 const MojoCreateDataPipeOptions kDefaultCreateOptions; // 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 in_options, MojoCreateDataPipeOptions* out_options); // These are called by the producer dispatcher to implement its methods of // corresponding names. void ProducerCancelAllWaiters(); void ProducerClose(); MojoResult ProducerWriteData(UserPointer elements, UserPointer num_bytes, bool all_or_none); MojoResult ProducerBeginWriteData(UserPointer buffer, UserPointer buffer_num_bytes, bool all_or_none); MojoResult ProducerEndWriteData(uint32_t num_bytes_written); MojoResult ProducerAddWaiter(Waiter* waiter, MojoHandleSignals signals, uint32_t context); void ProducerRemoveWaiter(Waiter* waiter); bool ProducerIsBusy() const; // These are called by the consumer dispatcher to implement its methods of // corresponding names. void ConsumerCancelAllWaiters(); void ConsumerClose(); // This does not validate its arguments, except to check that |*num_bytes| is // a multiple of |element_num_bytes_|. MojoResult ConsumerReadData(UserPointer elements, UserPointer num_bytes, bool all_or_none); MojoResult ConsumerDiscardData(UserPointer num_bytes, bool all_or_none); MojoResult ConsumerQueryData(UserPointer num_bytes); MojoResult ConsumerBeginReadData(UserPointer buffer, UserPointer buffer_num_bytes, bool all_or_none); MojoResult ConsumerEndReadData(uint32_t num_bytes_read); MojoResult ConsumerAddWaiter(Waiter* waiter, MojoHandleSignals signals, uint32_t context); void ConsumerRemoveWaiter(Waiter* waiter); bool ConsumerIsBusy() const; protected: DataPipe(bool has_local_producer, bool has_local_consumer, const MojoCreateDataPipeOptions& validated_options); friend class base::RefCountedThreadSafe; virtual ~DataPipe(); virtual void ProducerCloseImplNoLock() = 0; // |num_bytes.Get()| will be a nonzero multiple of |element_num_bytes_|. virtual MojoResult ProducerWriteDataImplNoLock( UserPointer elements, UserPointer num_bytes, uint32_t max_num_bytes_to_write, uint32_t min_num_bytes_to_write) = 0; virtual MojoResult ProducerBeginWriteDataImplNoLock( UserPointer buffer, UserPointer buffer_num_bytes, uint32_t min_num_bytes_to_write) = 0; virtual MojoResult ProducerEndWriteDataImplNoLock( uint32_t num_bytes_written) = 0; // Note: A producer should not be writable during a two-phase write. virtual HandleSignalsState ProducerGetHandleSignalsStateNoLock() const = 0; virtual void ConsumerCloseImplNoLock() = 0; // |*num_bytes| will be a nonzero multiple of |element_num_bytes_|. virtual MojoResult ConsumerReadDataImplNoLock( UserPointer elements, UserPointer num_bytes, uint32_t max_num_bytes_to_read, uint32_t min_num_bytes_to_read) = 0; virtual MojoResult ConsumerDiscardDataImplNoLock( UserPointer num_bytes, uint32_t max_num_bytes_to_discard, uint32_t min_num_bytes_to_discard) = 0; // |*num_bytes| will be a nonzero multiple of |element_num_bytes_|. virtual MojoResult ConsumerQueryDataImplNoLock( UserPointer num_bytes) = 0; virtual MojoResult ConsumerBeginReadDataImplNoLock( UserPointer buffer, UserPointer buffer_num_bytes, uint32_t min_num_bytes_to_read) = 0; virtual MojoResult ConsumerEndReadDataImplNoLock(uint32_t num_bytes_read) = 0; // Note: A consumer should not be writable during a two-phase read. virtual HandleSignalsState ConsumerGetHandleSignalsStateNoLock() const = 0; // Thread-safe and fast (they don't take the lock): bool may_discard() const { return may_discard_; } size_t element_num_bytes() const { return element_num_bytes_; } size_t capacity_num_bytes() const { return capacity_num_bytes_; } // Must be called under lock. bool producer_open_no_lock() const { lock_.AssertAcquired(); return producer_open_; } bool consumer_open_no_lock() const { lock_.AssertAcquired(); return consumer_open_; } uint32_t producer_two_phase_max_num_bytes_written_no_lock() const { lock_.AssertAcquired(); return producer_two_phase_max_num_bytes_written_; } uint32_t consumer_two_phase_max_num_bytes_read_no_lock() const { lock_.AssertAcquired(); return consumer_two_phase_max_num_bytes_read_; } void set_producer_two_phase_max_num_bytes_written_no_lock( uint32_t num_bytes) { lock_.AssertAcquired(); producer_two_phase_max_num_bytes_written_ = num_bytes; } void set_consumer_two_phase_max_num_bytes_read_no_lock(uint32_t num_bytes) { lock_.AssertAcquired(); consumer_two_phase_max_num_bytes_read_ = num_bytes; } bool producer_in_two_phase_write_no_lock() const { lock_.AssertAcquired(); return producer_two_phase_max_num_bytes_written_ > 0; } bool consumer_in_two_phase_read_no_lock() const { lock_.AssertAcquired(); return consumer_two_phase_max_num_bytes_read_ > 0; } private: void AwakeProducerWaitersForStateChangeNoLock( const HandleSignalsState& new_producer_state); void AwakeConsumerWaitersForStateChangeNoLock( const HandleSignalsState& new_consumer_state); bool has_local_producer_no_lock() const { lock_.AssertAcquired(); return !!producer_waiter_list_; } bool has_local_consumer_no_lock() const { lock_.AssertAcquired(); return !!consumer_waiter_list_; } const bool may_discard_; const size_t element_num_bytes_; const size_t capacity_num_bytes_; mutable base::Lock lock_; // Protects the following members. // *Known* state of producer or consumer. bool producer_open_; bool consumer_open_; // Non-null only if the producer or consumer, respectively, is local. scoped_ptr producer_waiter_list_; scoped_ptr consumer_waiter_list_; // These are nonzero if and only if a two-phase write/read is in progress. uint32_t producer_two_phase_max_num_bytes_written_; uint32_t consumer_two_phase_max_num_bytes_read_; DISALLOW_COPY_AND_ASSIGN(DataPipe); }; } // namespace system } // namespace mojo #endif // MOJO_SYSTEM_DATA_PIPE_H_