| Index: third_party/mojo/src/mojo/edk/system/slave_connection_manager.h
|
| diff --git a/third_party/mojo/src/mojo/edk/system/slave_connection_manager.h b/third_party/mojo/src/mojo/edk/system/slave_connection_manager.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..e773448e1d0938e18cdf7cb80160719b770e005a
|
| --- /dev/null
|
| +++ b/third_party/mojo/src/mojo/edk/system/slave_connection_manager.h
|
| @@ -0,0 +1,160 @@
|
| +// Copyright 2015 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_SLAVE_CONNECTION_MANAGER_H_
|
| +#define MOJO_EDK_SYSTEM_SLAVE_CONNECTION_MANAGER_H_
|
| +
|
| +#include "base/macros.h"
|
| +#include "base/memory/ref_counted.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/synchronization/lock.h"
|
| +#include "base/synchronization/waitable_event.h"
|
| +#include "base/threading/thread.h"
|
| +#include "mojo/edk/embedder/scoped_platform_handle.h"
|
| +#include "mojo/edk/embedder/slave_process_delegate.h"
|
| +#include "mojo/edk/system/connection_manager.h"
|
| +#include "mojo/edk/system/raw_channel.h"
|
| +#include "mojo/edk/system/system_impl_export.h"
|
| +
|
| +namespace base {
|
| +class TaskRunner;
|
| +}
|
| +
|
| +namespace mojo {
|
| +
|
| +namespace embedder {
|
| +class SlaveProcessDelegate;
|
| +}
|
| +
|
| +namespace system {
|
| +
|
| +// The |ConnectionManager| implementation for slave processes.
|
| +//
|
| +// Objects of this class must created, initialized (via |Init()|), shut down
|
| +// (via |Shutdown()|), and destroyed on the same thread (the "creation thread").
|
| +// Otherwise, its public methods are thread-safe (except that they may not be
|
| +// called from its internal, private thread).
|
| +class MOJO_SYSTEM_IMPL_EXPORT SlaveConnectionManager
|
| + : public ConnectionManager,
|
| + public RawChannel::Delegate {
|
| + public:
|
| + // Note: None of the public methods may be called from |private_thread_|.
|
| +
|
| + SlaveConnectionManager();
|
| + ~SlaveConnectionManager() override;
|
| +
|
| + // No other methods may be called until after this has been called.
|
| + // |slave_process_delegate| must stay alive at least until after |Shutdown()|
|
| + // has been called; its methods will be called on this object's creation
|
| + // thread.
|
| + void Init(embedder::SlaveProcessDelegate* slave_process_delegate,
|
| + embedder::ScopedPlatformHandle platform_handle);
|
| +
|
| + // No other methods may be called after this is (or while it is being) called.
|
| + void Shutdown();
|
| +
|
| + // |ConnectionManager| methods:
|
| + bool AllowConnect(const ConnectionIdentifier& connection_id) override;
|
| + bool CancelConnect(const ConnectionIdentifier& connection_id) override;
|
| + bool Connect(const ConnectionIdentifier& connection_id,
|
| + ProcessIdentifier* peer_process_identifier,
|
| + embedder::ScopedPlatformHandle* platform_handle) override;
|
| +
|
| + private:
|
| + // These should only be called on |private_thread_|:
|
| + void InitOnPrivateThread(embedder::ScopedPlatformHandle platform_handle);
|
| + void ShutdownOnPrivateThread();
|
| + void AllowConnectOnPrivateThread(const ConnectionIdentifier& connection_id,
|
| + bool* result);
|
| + void CancelConnectOnPrivateThread(const ConnectionIdentifier& connection_id,
|
| + bool* result);
|
| + void ConnectOnPrivateThread(const ConnectionIdentifier& connection_id,
|
| + bool* result,
|
| + ProcessIdentifier* peer_process_identifier,
|
| + embedder::ScopedPlatformHandle* platform_handle);
|
| +
|
| + // |RawChannel::Delegate| methods (only called on |private_thread_|):
|
| + void OnReadMessage(
|
| + const MessageInTransit::View& message_view,
|
| + embedder::ScopedPlatformHandleVectorPtr platform_handles) override;
|
| + void OnError(Error error) override;
|
| +
|
| + // Asserts that the current thread is the creation thread. (This actually
|
| + // checks the current message loop, which is what we depend on, not the thread
|
| + // per se.)
|
| + void AssertOnCreationThread() const;
|
| +
|
| + // Asserts that the current thread is *not* |private_thread_| (no-op if
|
| + // DCHECKs are not enabled). This should only be called while
|
| + // |private_thread_| is alive (i.e., after |Init()| but before |Shutdown()|).
|
| + void AssertNotOnPrivateThread() const;
|
| +
|
| + // Asserts that the current thread is |private_thread_| (no-op if DCHECKs are
|
| + // not enabled). This should only be called while |private_thread_| is alive
|
| + // (i.e., after |Init()| but before |Shutdown()|).
|
| + void AssertOnPrivateThread() const;
|
| +
|
| + const scoped_refptr<base::TaskRunner> creation_thread_task_runner_;
|
| +
|
| + // These is set in |Init()| before |private_thread_| exists and only cleared
|
| + // in |Shutdown()| after |private_thread_| is dead. Thus it's safe to "use" on
|
| + // |private_thread_|. (Note that |slave_process_delegate_| may only be called
|
| + // from the creation thread.)
|
| + embedder::SlaveProcessDelegate* slave_process_delegate_;
|
| +
|
| + // This is a private I/O thread on which this class does the bulk of its work.
|
| + // It is started in |Init()| and terminated in |Shutdown()|.
|
| + // TODO(vtl): This isn't really necessary.
|
| + base::Thread private_thread_;
|
| +
|
| + // Only accessed on |private_thread_|:
|
| + scoped_ptr<RawChannel> raw_channel_;
|
| + enum AwaitingAckType {
|
| + NOT_AWAITING_ACK,
|
| + AWAITING_ACCEPT_CONNECT_ACK,
|
| + AWAITING_CANCEL_CONNECT_ACK,
|
| + AWAITING_CONNECT_ACK
|
| + };
|
| + AwaitingAckType awaiting_ack_type_;
|
| + bool* ack_result_;
|
| + // Used only when waiting for the ack to "connect":
|
| + ProcessIdentifier* ack_peer_process_identifier_;
|
| + embedder::ScopedPlatformHandle* ack_platform_handle_;
|
| +
|
| + // The (synchronous) |ConnectionManager| methods are implemented in the
|
| + // following way (T is any thread other than |private_thread_|):
|
| + //
|
| + // On thread T:
|
| + // 1. |F()| is called, where F is one of the |ConnectionManager| methods.
|
| + // 2. |lock_| is acquired.
|
| + // 3. |FImpl()| is posted to |private_thread_|.
|
| + // 4. |event_| is waited on (while holding |lock_|!).
|
| + //
|
| + // On |private_thread_| (all with |lock_| held!):
|
| + // 4.1. |FImpl()| is executed, writes an "F" message to |raw_channel_|, and
|
| + // sets |awaiting_ack_type_| appropriately (it must not be "set"
|
| + // before).
|
| + // 4.2. [Control returns to |private_thread_|'s message loop.]
|
| + // 4.3. Eventually, |raw_channel_| calls |OnReadMessage()| with a message,
|
| + // which must be response (|awaiting_ack_type_| must still be set).
|
| + // 4.4. |*ack_result_| and possibly |*ack_platform_handle_| are written to.
|
| + // |awaiting_ack_type_| is "unset".
|
| + // 4.5. |event_| is triggered.
|
| + //
|
| + // Back on thread T:
|
| + // 6. |lock_| is released.
|
| + // 7. [Return from |F()|.]
|
| + //
|
| + // TODO(vtl): This is all a hack. It'd really suffice to have a version of
|
| + // |RawChannel| with fully synchronous reading and writing.
|
| + base::Lock lock_;
|
| + base::WaitableEvent event_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(SlaveConnectionManager);
|
| +};
|
| +
|
| +} // namespace system
|
| +} // namespace mojo
|
| +
|
| +#endif // MOJO_EDK_SYSTEM_SLAVE_CONNECTION_MANAGER_H_
|
|
|