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

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: Correct some outdated expectations during shutdown 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.h ('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"
14 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h" 15 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
15 #include "third_party/mojo/src/mojo/edk/embedder/process_delegate.h" 16 #include "third_party/mojo/src/mojo/edk/embedder/process_delegate.h"
16 17
17 namespace IPC { 18 namespace IPC {
18 19
19 namespace { 20 namespace {
20 21
21 class IPCSupportInitializer : public mojo::embedder::ProcessDelegate { 22 class IPCSupportInitializer : public mojo::embedder::ProcessDelegate {
22 public: 23 public:
23 IPCSupportInitializer() 24 IPCSupportInitializer()
24 : init_count_(0), 25 : init_count_(0),
25 shutting_down_(false) { 26 shutting_down_(false),
26 } 27 was_shut_down_(false),
28 observer_(nullptr),
29 weak_factory_(this) {}
27 30
28 ~IPCSupportInitializer() override {} 31 ~IPCSupportInitializer() override { DCHECK(!observer_); }
29 32
30 void Init(scoped_refptr<base::TaskRunner> io_thread_task_runner) { 33 void Init(scoped_refptr<base::TaskRunner> io_thread_task_runner);
31 base::AutoLock locker(lock_); 34 void ShutDown();
32 DCHECK((init_count_ == 0 && !io_thread_task_runner_) ||
33 io_thread_task_runner_ == io_thread_task_runner);
34 35
35 if (shutting_down_) { 36 // Forces the initializer to shut down even if scopers are still holding it.
36 // If reinitialized before a pending shutdown task is executed, we 37 void ForceShutdown();
37 // effectively cancel the shutdown task. 38
38 DCHECK(init_count_ == 1); 39 private:
39 shutting_down_ = false; 40 // This watches for destruction of the MessageLoop that IPCSupportInitializer
40 return; 41 // uses for IO, and guarantees that the initializer is shut down if it still
42 // exists when the loop is being destroyed.
43 class MessageLoopObserver : public base::MessageLoop::DestructionObserver {
44 public:
45 MessageLoopObserver(base::WeakPtr<IPCSupportInitializer> weak_initializer)
46 : weak_initializer_(weak_initializer) {}
47
48 ~MessageLoopObserver() override {
49 base::MessageLoop::current()->RemoveDestructionObserver(this);
41 } 50 }
42 51
43 init_count_++; 52 private:
44 if (init_count_ == 1) { 53 // base::MessageLoop::DestructionObserver:
45 io_thread_task_runner_ = io_thread_task_runner; 54 void WillDestroyCurrentMessageLoop() override {
46 mojo::embedder::InitIPCSupport(mojo::embedder::ProcessType::NONE, 55 if (weak_initializer_)
jam 2015/05/11 15:53:25 you can only check a weak pointer on the thread wh
Ken Rockot(use gerrit already) 2015/05/11 16:11:53 Fixed.
47 io_thread_task_runner_, 56 weak_initializer_->ForceShutdown();
48 this, io_thread_task_runner_,
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 } 57 }
62 58
63 shutting_down_ = true; 59 base::WeakPtr<IPCSupportInitializer> weak_initializer_;
64 if (base::MessageLoop::current() &&
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 60
76 private: 61 DISALLOW_COPY_AND_ASSIGN(MessageLoopObserver);
77 void ShutDownOnIOThread() { 62 };
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 63
64 void ShutDownOnIOThread();
65
66 // mojo::embedder::ProcessDelegate:
88 void OnShutdownComplete() override {} 67 void OnShutdownComplete() override {}
89 68
69 static void WatchMessageLoopOnIOThread(MessageLoopObserver* observer);
70
90 base::Lock lock_; 71 base::Lock lock_;
91 size_t init_count_; 72 size_t init_count_;
92 bool shutting_down_; 73 bool shutting_down_;
93 74
75 // This is used to track whether shutdown has occurred yet, since we can be
76 // shut down by either the scoper or IO MessageLoop destruction.
77 bool was_shut_down_;
78
79 // The message loop destruction observer we have watching our IO loop. This
80 // is created on the initializer's own thread but is used and destroyed on the
81 // IO thread.
82 MessageLoopObserver* observer_;
83
94 scoped_refptr<base::TaskRunner> io_thread_task_runner_; 84 scoped_refptr<base::TaskRunner> io_thread_task_runner_;
95 85
86 base::WeakPtrFactory<IPCSupportInitializer> weak_factory_;
87
96 DISALLOW_COPY_AND_ASSIGN(IPCSupportInitializer); 88 DISALLOW_COPY_AND_ASSIGN(IPCSupportInitializer);
97 }; 89 };
98 90
91 void IPCSupportInitializer::Init(
92 scoped_refptr<base::TaskRunner> io_thread_task_runner) {
93 base::AutoLock locker(lock_);
94 DCHECK((init_count_ == 0 && !io_thread_task_runner_) ||
95 io_thread_task_runner_ == io_thread_task_runner);
96
97 if (shutting_down_) {
98 // If reinitialized before a pending shutdown task is executed, we
99 // effectively cancel the shutdown task.
100 DCHECK(init_count_ == 1);
101 shutting_down_ = false;
102 return;
103 }
104
105 init_count_++;
106 if (init_count_ == 1) {
107 was_shut_down_ = false;
108 observer_ = new MessageLoopObserver(weak_factory_.GetWeakPtr());
109 io_thread_task_runner_ = io_thread_task_runner;
110 io_thread_task_runner_->PostTask(
111 FROM_HERE, base::Bind(&WatchMessageLoopOnIOThread, observer_));
112 mojo::embedder::InitIPCSupport(
113 mojo::embedder::ProcessType::NONE, io_thread_task_runner_, this,
114 io_thread_task_runner_, mojo::embedder::ScopedPlatformHandle());
115 }
116 }
117
118 void IPCSupportInitializer::ShutDown() {
119 {
120 base::AutoLock locker(lock_);
121 if (shutting_down_ || was_shut_down_)
122 return;
123 DCHECK(init_count_ > 0);
124 if (init_count_ > 1) {
125 init_count_--;
126 return;
127 }
128 }
129 ForceShutdown();
130 }
131
132 void IPCSupportInitializer::ForceShutdown() {
133 base::AutoLock locker(lock_);
134 if (shutting_down_ || was_shut_down_)
135 return;
136 shutting_down_ = true;
137 if (base::MessageLoop::current() &&
138 base::MessageLoop::current()->task_runner() == io_thread_task_runner_) {
139 base::AutoUnlock unlocker_(lock_);
140 ShutDownOnIOThread();
141 } else {
142 io_thread_task_runner_->PostTask(
143 FROM_HERE, base::Bind(&IPCSupportInitializer::ShutDownOnIOThread,
144 base::Unretained(this)));
145 }
146 }
147
148 void IPCSupportInitializer::ShutDownOnIOThread() {
149 base::AutoLock locker(lock_);
150 if (shutting_down_ && !was_shut_down_) {
151 mojo::embedder::ShutdownIPCSupportOnIOThread();
152 init_count_ = 0;
153 shutting_down_ = false;
154 io_thread_task_runner_ = nullptr;
155 was_shut_down_ = true;
156 if (observer_) {
157 delete observer_;
158 observer_ = nullptr;
159 }
160 }
161 }
162
163 // static
164 void IPCSupportInitializer::WatchMessageLoopOnIOThread(
165 MessageLoopObserver* observer) {
166 base::MessageLoop::current()->AddDestructionObserver(observer);
167 }
168
99 base::LazyInstance<IPCSupportInitializer>::Leaky ipc_support_initializer; 169 base::LazyInstance<IPCSupportInitializer>::Leaky ipc_support_initializer;
100 170
101 } // namespace 171 } // namespace
102 172
103 ScopedIPCSupport::ScopedIPCSupport( 173 ScopedIPCSupport::ScopedIPCSupport(
104 scoped_refptr<base::TaskRunner> io_thread_task_runner) { 174 scoped_refptr<base::TaskRunner> io_thread_task_runner) {
105 ipc_support_initializer.Get().Init(io_thread_task_runner); 175 ipc_support_initializer.Get().Init(io_thread_task_runner);
106 } 176 }
107 177
108 ScopedIPCSupport::~ScopedIPCSupport() { 178 ScopedIPCSupport::~ScopedIPCSupport() {
109 ipc_support_initializer.Get().ShutDown(); 179 ipc_support_initializer.Get().ShutDown();
110 } 180 }
111 181
112 } // namespace IPC 182 } // namespace IPC
OLDNEW
« ipc/mojo/ipc_channel_mojo.h ('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