Use UintToString() for unsigned values.
[chromium-blink-merge.git] / ipc / mojo / scoped_ipc_support.cc
blobb1d530e0463aedfe7c4e18f13a9aa94e31142395
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"
7 #include "base/bind.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"
18 namespace IPC {
20 namespace {
22 class IPCSupportInitializer : public mojo::embedder::ProcessDelegate {
23 public:
24 IPCSupportInitializer()
25 : init_count_(0),
26 shutting_down_(false),
27 was_shut_down_(false),
28 observer_(nullptr) {}
30 ~IPCSupportInitializer() override { DCHECK(!observer_); }
32 void Init(scoped_refptr<base::TaskRunner> io_thread_task_runner);
33 void ShutDown();
35 // Forces the initializer to shut down even if scopers are still holding it.
36 void ForceShutdown();
38 private:
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 {
43 public:
44 MessageLoopObserver(IPCSupportInitializer* initializer)
45 : initializer_(initializer) {}
47 ~MessageLoopObserver() override {
48 base::MessageLoop::current()->RemoveDestructionObserver(this);
51 private:
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);
69 base::Lock lock_;
70 size_t init_count_;
71 bool shutting_down_;
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.
75 bool was_shut_down_;
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
79 // IO thread.
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);
93 if (shutting_down_) {
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;
98 return;
101 init_count_++;
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_)
118 return;
119 DCHECK(init_count_ > 0);
120 if (init_count_ > 1) {
121 init_count_--;
122 return;
125 ForceShutdown();
128 void IPCSupportInitializer::ForceShutdown() {
129 base::AutoLock locker(lock_);
130 if (shutting_down_ || was_shut_down_)
131 return;
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();
137 } else {
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();
148 init_count_ = 0;
149 shutting_down_ = false;
150 io_thread_task_runner_ = nullptr;
151 was_shut_down_ = true;
152 if (observer_) {
153 delete observer_;
154 observer_ = nullptr;
159 // static
160 void IPCSupportInitializer::WatchMessageLoopOnIOThread(
161 MessageLoopObserver* observer) {
162 base::MessageLoop::current()->AddDestructionObserver(observer);
165 base::LazyInstance<IPCSupportInitializer>::Leaky ipc_support_initializer;
167 } // namespace
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();
178 } // namespace IPC