1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ipc/mojo/scoped_ipc_support.h"
8 #include "base/lazy_instance.h"
9 #include "base/logging.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/synchronization/condition_variable.h"
12 #include "base/synchronization/lock.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "base/thread_task_runner_handle.h"
15 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
16 #include "third_party/mojo/src/mojo/edk/embedder/process_delegate.h"
22 class IPCSupportInitializer
: public mojo::embedder::ProcessDelegate
{
24 IPCSupportInitializer()
26 shutting_down_(false),
27 was_shut_down_(false),
30 ~IPCSupportInitializer() override
{ DCHECK(!observer_
); }
32 void Init(scoped_refptr
<base::TaskRunner
> io_thread_task_runner
);
35 // Forces the initializer to shut down even if scopers are still holding it.
39 // This watches for destruction of the MessageLoop that IPCSupportInitializer
40 // uses for IO, and guarantees that the initializer is shut down if it still
41 // exists when the loop is being destroyed.
42 class MessageLoopObserver
: public base::MessageLoop::DestructionObserver
{
44 MessageLoopObserver(IPCSupportInitializer
* initializer
)
45 : initializer_(initializer
) {}
47 ~MessageLoopObserver() override
{
48 base::MessageLoop::current()->RemoveDestructionObserver(this);
52 // base::MessageLoop::DestructionObserver:
53 void WillDestroyCurrentMessageLoop() override
{
54 initializer_
->ForceShutdown();
57 IPCSupportInitializer
* initializer_
;
59 DISALLOW_COPY_AND_ASSIGN(MessageLoopObserver
);
62 void ShutDownOnIOThread();
64 // mojo::embedder::ProcessDelegate:
65 void OnShutdownComplete() override
{}
67 static void WatchMessageLoopOnIOThread(MessageLoopObserver
* observer
);
73 // This is used to track whether shutdown has occurred yet, since we can be
74 // shut down by either the scoper or IO MessageLoop destruction.
77 // The message loop destruction observer we have watching our IO loop. This
78 // is created on the initializer's own thread but is used and destroyed on the
80 MessageLoopObserver
* observer_
;
82 scoped_refptr
<base::TaskRunner
> io_thread_task_runner_
;
84 DISALLOW_COPY_AND_ASSIGN(IPCSupportInitializer
);
87 void IPCSupportInitializer::Init(
88 scoped_refptr
<base::TaskRunner
> io_thread_task_runner
) {
89 base::AutoLock
locker(lock_
);
90 DCHECK((init_count_
== 0 && !io_thread_task_runner_
) ||
91 io_thread_task_runner_
== io_thread_task_runner
);
94 // If reinitialized before a pending shutdown task is executed, we
95 // effectively cancel the shutdown task.
96 DCHECK(init_count_
== 1);
97 shutting_down_
= false;
102 if (init_count_
== 1) {
103 was_shut_down_
= false;
104 observer_
= new MessageLoopObserver(this);
105 io_thread_task_runner_
= io_thread_task_runner
;
106 io_thread_task_runner_
->PostTask(
107 FROM_HERE
, base::Bind(&WatchMessageLoopOnIOThread
, observer_
));
108 mojo::embedder::InitIPCSupport(
109 mojo::embedder::ProcessType::NONE
, io_thread_task_runner_
, this,
110 io_thread_task_runner_
, mojo::embedder::ScopedPlatformHandle());
114 void IPCSupportInitializer::ShutDown() {
116 base::AutoLock
locker(lock_
);
117 if (shutting_down_
|| was_shut_down_
)
119 DCHECK(init_count_
> 0);
120 if (init_count_
> 1) {
128 void IPCSupportInitializer::ForceShutdown() {
129 base::AutoLock
locker(lock_
);
130 if (shutting_down_
|| was_shut_down_
)
132 shutting_down_
= true;
133 if (base::MessageLoop::current() &&
134 base::MessageLoop::current()->task_runner() == io_thread_task_runner_
) {
135 base::AutoUnlock
unlocker_(lock_
);
136 ShutDownOnIOThread();
138 io_thread_task_runner_
->PostTask(
139 FROM_HERE
, base::Bind(&IPCSupportInitializer::ShutDownOnIOThread
,
140 base::Unretained(this)));
144 void IPCSupportInitializer::ShutDownOnIOThread() {
145 base::AutoLock
locker(lock_
);
146 if (shutting_down_
&& !was_shut_down_
) {
147 mojo::embedder::ShutdownIPCSupportOnIOThread();
149 shutting_down_
= false;
150 io_thread_task_runner_
= nullptr;
151 was_shut_down_
= true;
160 void IPCSupportInitializer::WatchMessageLoopOnIOThread(
161 MessageLoopObserver
* observer
) {
162 base::MessageLoop::current()->AddDestructionObserver(observer
);
165 base::LazyInstance
<IPCSupportInitializer
>::Leaky ipc_support_initializer
;
169 ScopedIPCSupport::ScopedIPCSupport(
170 scoped_refptr
<base::TaskRunner
> io_thread_task_runner
) {
171 ipc_support_initializer
.Get().Init(io_thread_task_runner
);
174 ScopedIPCSupport::~ScopedIPCSupport() {
175 ipc_support_initializer
.Get().ShutDown();