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_ |