Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(289)

Side by Side Diff: ipc/mojo/scoped_ipc_support.cc

Issue 1130413002: Mojo IPC threading fixes (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Force shutdown on the correct thread Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« ipc/mojo/ipc_channel_mojo.cc ('K') | « ipc/mojo/ipc_channel_mojo.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ipc/mojo/scoped_ipc_support.h" 5 #include "ipc/mojo/scoped_ipc_support.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/lazy_instance.h" 8 #include "base/lazy_instance.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/memory/weak_ptr.h"
10 #include "base/message_loop/message_loop.h" 11 #include "base/message_loop/message_loop.h"
11 #include "base/synchronization/condition_variable.h" 12 #include "base/synchronization/condition_variable.h"
12 #include "base/synchronization/lock.h" 13 #include "base/synchronization/lock.h"
13 #include "base/synchronization/waitable_event.h" 14 #include "base/synchronization/waitable_event.h"
15 #include "base/thread_task_runner_handle.h"
14 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h" 16 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
15 #include "third_party/mojo/src/mojo/edk/embedder/process_delegate.h" 17 #include "third_party/mojo/src/mojo/edk/embedder/process_delegate.h"
16 18
17 namespace IPC { 19 namespace IPC {
18 20
19 namespace { 21 namespace {
20 22
21 class IPCSupportInitializer : public mojo::embedder::ProcessDelegate { 23 class IPCSupportInitializer : public mojo::embedder::ProcessDelegate {
22 public: 24 public:
23 IPCSupportInitializer() 25 IPCSupportInitializer()
24 : init_count_(0), 26 : init_count_(0),
25 shutting_down_(false) { 27 shutting_down_(false),
26 } 28 was_shut_down_(false),
29 observer_(nullptr),
30 weak_factory_(this) {}
27 31
28 ~IPCSupportInitializer() override {} 32 ~IPCSupportInitializer() override { DCHECK(!observer_); }
29 33
30 void Init(scoped_refptr<base::TaskRunner> io_thread_task_runner) { 34 void Init(scoped_refptr<base::TaskRunner> io_thread_task_runner);
31 base::AutoLock locker(lock_); 35 void ShutDown();
32 DCHECK((init_count_ == 0 && !io_thread_task_runner_) ||
33 io_thread_task_runner_ == io_thread_task_runner);
34 36
35 if (shutting_down_) { 37 // Forces the initializer to shut down even if scopers are still holding it.
36 // If reinitialized before a pending shutdown task is executed, we 38 void ForceShutdown();
37 // effectively cancel the shutdown task. 39
38 DCHECK(init_count_ == 1); 40 private:
39 shutting_down_ = false; 41 // This watches for destruction of the MessageLoop that IPCSupportInitializer
40 return; 42 // uses for IO, and guarantees that the initializer is shut down if it still
43 // exists when the loop is being destroyed.
44 class MessageLoopObserver : public base::MessageLoop::DestructionObserver {
45 public:
46 MessageLoopObserver(
47 scoped_refptr<base::TaskRunner> initializer_task_runner,
48 base::WeakPtr<IPCSupportInitializer> weak_initializer)
49 : initializer_task_runner_(initializer_task_runner),
50 weak_initializer_(weak_initializer) {}
51
52 ~MessageLoopObserver() override {
53 base::MessageLoop::current()->RemoveDestructionObserver(this);
41 } 54 }
42 55
43 init_count_++; 56 private:
44 if (init_count_ == 1) { 57 // base::MessageLoop::DestructionObserver:
45 io_thread_task_runner_ = io_thread_task_runner; 58 void WillDestroyCurrentMessageLoop() override {
46 mojo::embedder::InitIPCSupport(mojo::embedder::ProcessType::NONE, 59 initializer_task_runner_->PostTask(
47 io_thread_task_runner_, 60 FROM_HERE,
48 this, io_thread_task_runner_, 61 base::Bind(&IPCSupportInitializer::ForceShutdown, weak_initializer_));
49 mojo::embedder::ScopedPlatformHandle());
50 }
51 }
52
53 void ShutDown() {
54 base::AutoLock locker(lock_);
55 DCHECK(init_count_ > 0);
56 DCHECK(!shutting_down_);
57
58 if (init_count_ > 1) {
59 init_count_--;
60 return;
61 } 62 }
62 63
63 shutting_down_ = true; 64 scoped_refptr<base::TaskRunner> initializer_task_runner_;
64 if (base::MessageLoop::current() && 65 base::WeakPtr<IPCSupportInitializer> weak_initializer_;
65 base::MessageLoop::current()->task_runner() == io_thread_task_runner_) {
66 base::AutoUnlock unlocker_(lock_);
67 ShutDownOnIOThread();
68 } else {
69 io_thread_task_runner_->PostTask(
70 FROM_HERE,
71 base::Bind(&IPCSupportInitializer::ShutDownOnIOThread,
72 base::Unretained(this)));
73 }
74 }
75 66
76 private: 67 DISALLOW_COPY_AND_ASSIGN(MessageLoopObserver);
77 void ShutDownOnIOThread() { 68 };
78 base::AutoLock locker(lock_);
79 if (shutting_down_) {
80 DCHECK(init_count_ == 1);
81 mojo::embedder::ShutdownIPCSupportOnIOThread();
82 init_count_ = 0;
83 shutting_down_ = false;
84 io_thread_task_runner_ = nullptr;
85 }
86 }
87 69
70 void ShutDownOnIOThread();
71
72 // mojo::embedder::ProcessDelegate:
88 void OnShutdownComplete() override {} 73 void OnShutdownComplete() override {}
89 74
75 static void WatchMessageLoopOnIOThread(MessageLoopObserver* observer);
76
90 base::Lock lock_; 77 base::Lock lock_;
91 size_t init_count_; 78 size_t init_count_;
92 bool shutting_down_; 79 bool shutting_down_;
93 80
81 // This is used to track whether shutdown has occurred yet, since we can be
82 // shut down by either the scoper or IO MessageLoop destruction.
83 bool was_shut_down_;
84
85 // The message loop destruction observer we have watching our IO loop. This
86 // is created on the initializer's own thread but is used and destroyed on the
87 // IO thread.
88 MessageLoopObserver* observer_;
89
94 scoped_refptr<base::TaskRunner> io_thread_task_runner_; 90 scoped_refptr<base::TaskRunner> io_thread_task_runner_;
95 91
92 base::WeakPtrFactory<IPCSupportInitializer> weak_factory_;
93
96 DISALLOW_COPY_AND_ASSIGN(IPCSupportInitializer); 94 DISALLOW_COPY_AND_ASSIGN(IPCSupportInitializer);
97 }; 95 };
98 96
97 void IPCSupportInitializer::Init(
98 scoped_refptr<base::TaskRunner> io_thread_task_runner) {
99 base::AutoLock locker(lock_);
100 DCHECK((init_count_ == 0 && !io_thread_task_runner_) ||
101 io_thread_task_runner_ == io_thread_task_runner);
102
103 if (shutting_down_) {
104 // If reinitialized before a pending shutdown task is executed, we
105 // effectively cancel the shutdown task.
106 DCHECK(init_count_ == 1);
107 shutting_down_ = false;
108 return;
109 }
110
111 init_count_++;
112 if (init_count_ == 1) {
113 was_shut_down_ = false;
114 observer_ = new MessageLoopObserver(base::ThreadTaskRunnerHandle::Get(),
115 weak_factory_.GetWeakPtr());
116 io_thread_task_runner_ = io_thread_task_runner;
117 io_thread_task_runner_->PostTask(
118 FROM_HERE, base::Bind(&WatchMessageLoopOnIOThread, observer_));
119 mojo::embedder::InitIPCSupport(
120 mojo::embedder::ProcessType::NONE, io_thread_task_runner_, this,
121 io_thread_task_runner_, mojo::embedder::ScopedPlatformHandle());
122 }
123 }
124
125 void IPCSupportInitializer::ShutDown() {
126 {
127 base::AutoLock locker(lock_);
128 if (shutting_down_ || was_shut_down_)
129 return;
130 DCHECK(init_count_ > 0);
131 if (init_count_ > 1) {
132 init_count_--;
133 return;
134 }
135 }
136 ForceShutdown();
137 }
138
139 void IPCSupportInitializer::ForceShutdown() {
140 base::AutoLock locker(lock_);
141 if (shutting_down_ || was_shut_down_)
142 return;
143 shutting_down_ = true;
144 if (base::MessageLoop::current() &&
145 base::MessageLoop::current()->task_runner() == io_thread_task_runner_) {
146 base::AutoUnlock unlocker_(lock_);
147 ShutDownOnIOThread();
148 } else {
149 io_thread_task_runner_->PostTask(
150 FROM_HERE, base::Bind(&IPCSupportInitializer::ShutDownOnIOThread,
151 base::Unretained(this)));
152 }
153 }
154
155 void IPCSupportInitializer::ShutDownOnIOThread() {
156 base::AutoLock locker(lock_);
157 if (shutting_down_ && !was_shut_down_) {
158 mojo::embedder::ShutdownIPCSupportOnIOThread();
159 init_count_ = 0;
160 shutting_down_ = false;
161 io_thread_task_runner_ = nullptr;
162 was_shut_down_ = true;
163 if (observer_) {
164 delete observer_;
165 observer_ = nullptr;
166 }
167 }
168 }
169
170 // static
171 void IPCSupportInitializer::WatchMessageLoopOnIOThread(
172 MessageLoopObserver* observer) {
173 base::MessageLoop::current()->AddDestructionObserver(observer);
174 }
175
99 base::LazyInstance<IPCSupportInitializer>::Leaky ipc_support_initializer; 176 base::LazyInstance<IPCSupportInitializer>::Leaky ipc_support_initializer;
100 177
101 } // namespace 178 } // namespace
102 179
103 ScopedIPCSupport::ScopedIPCSupport( 180 ScopedIPCSupport::ScopedIPCSupport(
104 scoped_refptr<base::TaskRunner> io_thread_task_runner) { 181 scoped_refptr<base::TaskRunner> io_thread_task_runner) {
105 ipc_support_initializer.Get().Init(io_thread_task_runner); 182 ipc_support_initializer.Get().Init(io_thread_task_runner);
106 } 183 }
107 184
108 ScopedIPCSupport::~ScopedIPCSupport() { 185 ScopedIPCSupport::~ScopedIPCSupport() {
109 ipc_support_initializer.Get().ShutDown(); 186 ipc_support_initializer.Get().ShutDown();
110 } 187 }
111 188
112 } // namespace IPC 189 } // namespace IPC
OLDNEW
« ipc/mojo/ipc_channel_mojo.cc ('K') | « ipc/mojo/ipc_channel_mojo.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698