#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
+#include "mojo/embedder/platform_handle.h"
#include "mojo/public/c/system/core.h"
-// TODO(vtl): We need this since we can't forward declare
-// |RawSharedBuffer::Mapping|. Maybe fix this.
-#include "mojo/system/raw_shared_buffer.h"
#include "mojo/system/system_impl_export.h"
namespace mojo {
namespace system {
class Channel;
-class CoreImpl;
+class Core;
class Dispatcher;
class DispatcherTransport;
+class HandleTable;
class LocalMessagePipeEndpoint;
-class MessageInTransit;
class ProxyMessagePipeEndpoint;
+class RawSharedBufferMapping;
+class TransportData;
class Waiter;
+typedef std::vector<scoped_refptr<Dispatcher> > DispatcherVector;
+
namespace test {
// Test helper. We need to declare it here so we can friend it.
// |dispatchers| must be non-null but empty, if |num_dispatchers| is non-null
// and nonzero. On success, it will be set to the dispatchers to be received
// (and assigned handles) as part of the message.
- MojoResult ReadMessage(
- void* bytes,
- uint32_t* num_bytes,
- std::vector<scoped_refptr<Dispatcher> >* dispatchers,
- uint32_t* num_dispatchers,
- MojoReadMessageFlags flags);
+ MojoResult ReadMessage(void* bytes,
+ uint32_t* num_bytes,
+ DispatcherVector* dispatchers,
+ uint32_t* num_dispatchers,
+ MojoReadMessageFlags flags);
MojoResult WriteData(const void* elements,
uint32_t* elements_num_bytes,
MojoWriteDataFlags flags);
MojoResult MapBuffer(uint64_t offset,
uint64_t num_bytes,
MojoMapBufferFlags flags,
- scoped_ptr<RawSharedBuffer::Mapping>* mapping);
+ scoped_ptr<RawSharedBufferMapping>* mapping);
// Adds a waiter to this dispatcher. The waiter will be woken up when this
// object changes state to satisfy |flags| with result |wake_result| (which
void RemoveWaiter(Waiter* waiter);
// A dispatcher must be put into a special state in order to be sent across a
- // message pipe. Outside of tests, only |CoreImplAccess| is allowed to do
+ // message pipe. Outside of tests, only |HandleTableAccess| is allowed to do
// this, since there are requirements on the handle table (see below).
//
// In this special state, only a restricted set of operations is allowed.
// These are the ones available as |DispatcherTransport| methods. Other
// |Dispatcher| methods must not be called until |DispatcherTransport::End()|
// has been called.
- class CoreImplAccess {
+ class HandleTableAccess {
private:
- friend class CoreImpl;
- // Tests also need this, to avoid needing |CoreImpl|.
+ friend class Core;
+ friend class HandleTable;
+ // Tests also need this, to avoid needing |Core|.
friend DispatcherTransport test::DispatcherTryStartTransport(Dispatcher*);
// This must be called under the handle table lock and only if the handle
static DispatcherTransport TryStartTransport(Dispatcher* dispatcher);
};
- // A |MessageInTransit| may serialize dispatchers that are attached to it to a
- // given |Channel| and then (probably in a different process) deserialize.
+ // A |TransportData| may serialize dispatchers that are given to it (and which
+ // were previously attached to the |MessageInTransit| that is creating it) to
+ // a given |Channel| and then (probably in a different process) deserialize.
+ // Note that the |MessageInTransit| "owns" (i.e., has the only ref to) these
+ // dispatchers, so there are no locking issues. (There's no lock ordering
+ // issue, and in fact no need to take dispatcher locks at all.)
// TODO(vtl): Consider making another wrapper similar to |DispatcherTransport|
// (but with an owning, unique reference), and having
// |CreateEquivalentDispatcherAndCloseImplNoLock()| return that wrapper (and
- // |MessageInTransit| only holding on to such wrappers).
- class MessageInTransitAccess {
+ // |MessageInTransit|, etc. only holding on to such wrappers).
+ class TransportDataAccess {
private:
- friend class MessageInTransit;
+ friend class TransportData;
// Serialization API. These functions may only be called on such
// dispatchers. (|channel| is the |Channel| to which the dispatcher is to be
// serialized.) See the |Dispatcher| methods of the same names for more
// details.
- // TODO(vtl): Consider replacing this API below with a proper two-phase one
- // ("StartSerialize()" and "EndSerializeAndClose()", with the lock possibly
- // being held across their invocations).
- static size_t GetMaximumSerializedSize(const Dispatcher* dispatcher,
- const Channel* channel);
- static bool SerializeAndClose(Dispatcher* dispatcher,
- Channel* channel,
- void* destination,
- size_t* actual_size);
+ static void StartSerialize(Dispatcher* dispatcher,
+ Channel* channel,
+ size_t* max_size,
+ size_t* max_platform_handles);
+ static bool EndSerializeAndClose(
+ Dispatcher* dispatcher,
+ Channel* channel,
+ void* destination,
+ size_t* actual_size,
+ std::vector<embedder::PlatformHandle>* platform_handles);
// Deserialization API.
- // TODO(vtl): Implement this.
static scoped_refptr<Dispatcher> Deserialize(Channel* channel,
int32_t type,
const void* source,
uint32_t num_bytes,
std::vector<DispatcherTransport>* transports,
MojoWriteMessageFlags flags);
- virtual MojoResult ReadMessageImplNoLock(
- void* bytes,
- uint32_t* num_bytes,
- std::vector<scoped_refptr<Dispatcher> >* dispatchers,
- uint32_t* num_dispatchers,
- MojoReadMessageFlags flags);
+ virtual MojoResult ReadMessageImplNoLock(void* bytes,
+ uint32_t* num_bytes,
+ DispatcherVector* dispatchers,
+ uint32_t* num_dispatchers,
+ MojoReadMessageFlags flags);
virtual MojoResult WriteDataImplNoLock(const void* elements,
uint32_t* num_bytes,
MojoWriteDataFlags flags);
uint64_t offset,
uint64_t num_bytes,
MojoMapBufferFlags flags,
- scoped_ptr<RawSharedBuffer::Mapping>* mapping);
+ scoped_ptr<RawSharedBufferMapping>* mapping);
virtual MojoResult AddWaiterImplNoLock(Waiter* waiter,
MojoWaitFlags flags,
MojoResult wake_result);
// (described below). They will only be called on a dispatcher that's attached
// to and "owned" by a |MessageInTransit|. See the non-"impl" versions for
// more information.
+ //
+ // Note: |StartSerializeImplNoLock()| is actually called with |lock_| NOT
+ // held, since the dispatcher should only be accessible to the calling thread.
+ // On Debug builds, |EndSerializeAndCloseImplNoLock()| is called with |lock_|
+ // held, to satisfy any |lock_.AssertAcquired()| (e.g., in |CloseImplNoLock()|
+ // -- and anything it calls); disentangling those assertions is
+ // difficult/fragile, and would weaken our general checking of invariants.
+ //
// TODO(vtl): Consider making these pure virtual once most things support
// being passed over a message pipe.
- virtual size_t GetMaximumSerializedSizeImplNoLock(
- const Channel* channel) const;
- virtual bool SerializeAndCloseImplNoLock(Channel* channel,
- void* destination,
- size_t* actual_size);
+ virtual void StartSerializeImplNoLock(Channel* channel,
+ size_t* max_size,
+ size_t* max_platform_handles);
+ virtual bool EndSerializeAndCloseImplNoLock(
+ Channel* channel,
+ void* destination,
+ size_t* actual_size,
+ std::vector<embedder::PlatformHandle>* platform_handles);
// Available to subclasses. (Note: Returns a non-const reference, just like
// |base::AutoLock|'s constructor takes a non-const reference.)
scoped_refptr<Dispatcher> CreateEquivalentDispatcherAndCloseNoLock();
// API to serialize dispatchers to a |Channel|, exposed to only
- // |MessageInTransit| (via |MessageInTransitAccess|). They may only be called
- // on a dispatcher attached to a |MessageInTransit| (and in particular not in
+ // |TransportData| (via |TransportData|). They may only be called on a
+ // dispatcher attached to a |MessageInTransit| (and in particular not in
// |CoreImpl|'s handle table).
- // Gets the maximum amount of space that'll be needed to serialize this
- // dispatcher to the given |Channel|. This amount must be no greater than
- // |MessageInTransit::kMaxSerializedDispatcherSize| (message_in_transit.h).
- // Returns zero to indicate that this dispatcher cannot be serialized (to the
- // given |Channel|).
- size_t GetMaximumSerializedSize(const Channel* channel) const;
- // Serializes this dispatcher to the given |Channel| by writing to
- // |destination| and then closes this dispatcher. It may write no more than
- // was indicated by |GetMaximumSerializedSize()|. (WARNING: Beware of races,
- // e.g., if something can be mutated between the two calls!) Returns true on
- // success, in which case |*actual_size| is set to the amount it actually
- // wrote to |destination|. On failure, |*actual_size| should not be modified;
- // however, the dispatcher will still be closed.
- bool SerializeAndClose(Channel* channel,
- void* destination,
- size_t* actual_size);
+ //
+ // Starts the serialization. Returns (via the two "out" parameters) the
+ // maximum amount of space that may be needed to serialize this dispatcher to
+ // the given |Channel| (no more than
+ // |TransportData::kMaxSerializedDispatcherSize|) and the maximum number of
+ // |PlatformHandle|s that may need to be attached (no more than
+ // |TransportData::kMaxSerializedDispatcherPlatformHandles|). If this
+ // dispatcher cannot be serialized to the given |Channel|, |*max_size| and
+ // |*max_platform_handles| should be set to zero. A call to this method will
+ // ALWAYS be followed by a call to |EndSerializeAndClose()| (even if this
+ // dispatcher cannot be serialized to the given |Channel|).
+ void StartSerialize(Channel* channel,
+ size_t* max_size,
+ size_t* max_platform_handles);
+ // Completes the serialization of this dispatcher to the given |Channel| and
+ // closes it. (This call will always follow an earlier call to
+ // |StartSerialize()|, with the same |Channel|.) This does so by writing to
+ // |destination| and appending any |PlatformHandle|s needed to
+ // |platform_handles| (which may be null if no platform handles were indicated
+ // to be required to |StartSerialize()|). This may write no more than the
+ // amount indicated by |StartSerialize()|. (WARNING: Beware of races, e.g., if
+ // something can be mutated between the two calls!) Returns true on success,
+ // in which case |*actual_size| is set to the amount it actually wrote to
+ // |destination|. On failure, |*actual_size| should not be modified; however,
+ // the dispatcher will still be closed.
+ bool EndSerializeAndClose(
+ Channel* channel,
+ void* destination,
+ size_t* actual_size,
+ std::vector<embedder::PlatformHandle>* platform_handles);
// This protects the following members as well as any state added by
// subclasses.
};
// Wrapper around a |Dispatcher| pointer, while it's being processed to be
-// passed in a message pipe. See the comment about |Dispatcher::CoreImplAccess|
-// for more details.
+// passed in a message pipe. See the comment about
+// |Dispatcher::HandleTableAccess| for more details.
//
// Note: This class is deliberately "thin" -- no more expensive than a
// |Dispatcher*|.
Dispatcher* dispatcher() { return dispatcher_; }
private:
- friend class Dispatcher::CoreImplAccess;
+ friend class Dispatcher::HandleTableAccess;
explicit DispatcherTransport(Dispatcher* dispatcher)
: dispatcher_(dispatcher) {}