OLD | NEW |
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 // This is really a unit test for |MasterConnectionManager| and | 5 // This is really a unit test for |MasterConnectionManager| and |
6 // |SlaveConnectionManager| (since they need to be tested together). | 6 // |SlaveConnectionManager| (since they need to be tested together). |
7 | 7 |
8 #include "mojo/edk/system/connection_manager.h" | 8 #include "mojo/edk/system/connection_manager.h" |
9 | 9 |
10 #include <stdint.h> | 10 #include <stdint.h> |
11 | 11 |
| 12 #include <memory> |
12 #include <string> | 13 #include <string> |
13 | 14 |
14 #include "base/message_loop/message_loop.h" | |
15 #include "base/run_loop.h" | |
16 #include "base/threading/thread_checker.h" | 15 #include "base/threading/thread_checker.h" |
17 #include "mojo/edk/base_edk/platform_task_runner_impl.h" | 16 #include "mojo/edk/base_edk/platform_task_runner_impl.h" |
18 #include "mojo/edk/embedder/master_process_delegate.h" | 17 #include "mojo/edk/embedder/master_process_delegate.h" |
19 #include "mojo/edk/embedder/platform_channel_pair.h" | 18 #include "mojo/edk/embedder/platform_channel_pair.h" |
20 #include "mojo/edk/embedder/simple_platform_support.h" | 19 #include "mojo/edk/embedder/simple_platform_support.h" |
21 #include "mojo/edk/embedder/slave_process_delegate.h" | 20 #include "mojo/edk/embedder/slave_process_delegate.h" |
| 21 #include "mojo/edk/platform/message_loop.h" |
| 22 #include "mojo/edk/platform/test_message_loop.h" |
22 #include "mojo/edk/system/master_connection_manager.h" | 23 #include "mojo/edk/system/master_connection_manager.h" |
23 #include "mojo/edk/system/slave_connection_manager.h" | 24 #include "mojo/edk/system/slave_connection_manager.h" |
24 #include "mojo/edk/test/test_utils.h" | 25 #include "mojo/edk/test/test_utils.h" |
25 #include "mojo/edk/util/ref_ptr.h" | 26 #include "mojo/edk/util/ref_ptr.h" |
26 #include "mojo/public/cpp/system/macros.h" | 27 #include "mojo/public/cpp/system/macros.h" |
27 #include "testing/gtest/include/gtest/gtest.h" | 28 #include "testing/gtest/include/gtest/gtest.h" |
28 | 29 |
| 30 using mojo::platform::MessageLoop; |
29 using mojo::platform::TaskRunner; | 31 using mojo::platform::TaskRunner; |
| 32 using mojo::platform::test::CreateTestMessageLoop; |
30 using mojo::util::MakeRefCounted; | 33 using mojo::util::MakeRefCounted; |
31 using mojo::util::RefPtr; | 34 using mojo::util::RefPtr; |
32 | 35 |
33 namespace mojo { | 36 namespace mojo { |
34 namespace system { | 37 namespace system { |
35 namespace { | 38 namespace { |
36 | 39 |
37 bool ArePlatformHandlesConnected(const embedder::PlatformHandle& h1, | 40 bool ArePlatformHandlesConnected(const embedder::PlatformHandle& h1, |
38 const embedder::PlatformHandle& h2) { | 41 const embedder::PlatformHandle& h2) { |
39 const uint32_t w1 = 0xdeadbeef; | 42 const uint32_t w1 = 0xdeadbeef; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
80 private: | 83 private: |
81 base::ThreadChecker thread_checker_; | 84 base::ThreadChecker thread_checker_; |
82 std::string name_; | 85 std::string name_; |
83 | 86 |
84 MOJO_DISALLOW_COPY_AND_ASSIGN(TestSlaveInfo); | 87 MOJO_DISALLOW_COPY_AND_ASSIGN(TestSlaveInfo); |
85 }; | 88 }; |
86 | 89 |
87 class MockMasterProcessDelegate : public embedder::MasterProcessDelegate { | 90 class MockMasterProcessDelegate : public embedder::MasterProcessDelegate { |
88 public: | 91 public: |
89 MockMasterProcessDelegate() | 92 MockMasterProcessDelegate() |
90 : current_run_loop_(), on_slave_disconnect_calls_(0) {} | 93 : current_message_loop_(), on_slave_disconnect_calls_(0) {} |
91 ~MockMasterProcessDelegate() override {} | 94 ~MockMasterProcessDelegate() override {} |
92 | 95 |
93 void RunUntilNotified() { | 96 void RunUntilNotified(MessageLoop* message_loop) { |
94 CHECK(!current_run_loop_); | 97 CHECK(!current_message_loop_); |
95 base::RunLoop run_loop; | 98 current_message_loop_ = message_loop; |
96 current_run_loop_ = &run_loop; | 99 message_loop->Run(); |
97 run_loop.Run(); | 100 current_message_loop_ = nullptr; |
98 current_run_loop_ = nullptr; | |
99 } | 101 } |
100 | 102 |
101 unsigned on_slave_disconnect_calls() const { | 103 unsigned on_slave_disconnect_calls() const { |
102 return on_slave_disconnect_calls_; | 104 return on_slave_disconnect_calls_; |
103 } | 105 } |
104 const std::string& last_slave_disconnect_name() const { | 106 const std::string& last_slave_disconnect_name() const { |
105 return last_slave_disconnect_name_; | 107 return last_slave_disconnect_name_; |
106 } | 108 } |
107 | 109 |
108 // |embedder::MasterProcessDelegate| implementation: | 110 // |embedder::MasterProcessDelegate| implementation: |
109 void OnShutdownComplete() override { NOTREACHED(); } | 111 void OnShutdownComplete() override { NOTREACHED(); } |
110 | 112 |
111 void OnSlaveDisconnect(embedder::SlaveInfo slave_info) override { | 113 void OnSlaveDisconnect(embedder::SlaveInfo slave_info) override { |
112 CHECK(thread_checker_.CalledOnValidThread()); | 114 CHECK(thread_checker_.CalledOnValidThread()); |
113 on_slave_disconnect_calls_++; | 115 on_slave_disconnect_calls_++; |
114 last_slave_disconnect_name_ = | 116 last_slave_disconnect_name_ = |
115 static_cast<TestSlaveInfo*>(slave_info)->name(); | 117 static_cast<TestSlaveInfo*>(slave_info)->name(); |
116 DVLOG(1) << "Disconnected from slave process " | 118 DVLOG(1) << "Disconnected from slave process " |
117 << last_slave_disconnect_name_; | 119 << last_slave_disconnect_name_; |
118 delete static_cast<TestSlaveInfo*>(slave_info); | 120 delete static_cast<TestSlaveInfo*>(slave_info); |
119 | 121 |
120 if (current_run_loop_) | 122 if (current_message_loop_) |
121 current_run_loop_->Quit(); | 123 current_message_loop_->QuitNow(); |
122 } | 124 } |
123 | 125 |
124 private: | 126 private: |
125 base::ThreadChecker thread_checker_; | 127 base::ThreadChecker thread_checker_; |
126 base::RunLoop* current_run_loop_; | 128 MessageLoop* current_message_loop_; |
127 | 129 |
128 unsigned on_slave_disconnect_calls_; | 130 unsigned on_slave_disconnect_calls_; |
129 std::string last_slave_disconnect_name_; | 131 std::string last_slave_disconnect_name_; |
130 | 132 |
131 MOJO_DISALLOW_COPY_AND_ASSIGN(MockMasterProcessDelegate); | 133 MOJO_DISALLOW_COPY_AND_ASSIGN(MockMasterProcessDelegate); |
132 }; | 134 }; |
133 | 135 |
134 class MockSlaveProcessDelegate : public embedder::SlaveProcessDelegate { | 136 class MockSlaveProcessDelegate : public embedder::SlaveProcessDelegate { |
135 public: | 137 public: |
136 MockSlaveProcessDelegate() | 138 MockSlaveProcessDelegate() |
137 : current_run_loop_(), on_master_disconnect_calls_(0) {} | 139 : current_message_loop_(), on_master_disconnect_calls_(0) {} |
138 ~MockSlaveProcessDelegate() override {} | 140 ~MockSlaveProcessDelegate() override {} |
139 | 141 |
140 void RunUntilNotified() { | 142 void RunUntilNotified(MessageLoop* message_loop) { |
141 CHECK(!current_run_loop_); | 143 CHECK(!current_message_loop_); |
142 base::RunLoop run_loop; | 144 current_message_loop_ = message_loop; |
143 current_run_loop_ = &run_loop; | 145 message_loop->Run(); |
144 run_loop.Run(); | 146 current_message_loop_ = nullptr; |
145 current_run_loop_ = nullptr; | |
146 } | 147 } |
147 | 148 |
148 unsigned on_master_disconnect_calls() const { | 149 unsigned on_master_disconnect_calls() const { |
149 return on_master_disconnect_calls_; | 150 return on_master_disconnect_calls_; |
150 } | 151 } |
151 | 152 |
152 // |embedder::SlaveProcessDelegate| implementation: | 153 // |embedder::SlaveProcessDelegate| implementation: |
153 void OnShutdownComplete() override { NOTREACHED(); } | 154 void OnShutdownComplete() override { NOTREACHED(); } |
154 | 155 |
155 void OnMasterDisconnect() override { | 156 void OnMasterDisconnect() override { |
156 CHECK(thread_checker_.CalledOnValidThread()); | 157 CHECK(thread_checker_.CalledOnValidThread()); |
157 on_master_disconnect_calls_++; | 158 on_master_disconnect_calls_++; |
158 DVLOG(1) << "Disconnected from master process"; | 159 DVLOG(1) << "Disconnected from master process"; |
159 | 160 |
160 if (current_run_loop_) | 161 if (current_message_loop_) |
161 current_run_loop_->Quit(); | 162 current_message_loop_->QuitNow(); |
162 } | 163 } |
163 | 164 |
164 private: | 165 private: |
165 base::ThreadChecker thread_checker_; | 166 base::ThreadChecker thread_checker_; |
166 base::RunLoop* current_run_loop_; | 167 MessageLoop* current_message_loop_; |
167 | 168 |
168 unsigned on_master_disconnect_calls_; | 169 unsigned on_master_disconnect_calls_; |
169 | 170 |
170 MOJO_DISALLOW_COPY_AND_ASSIGN(MockSlaveProcessDelegate); | 171 MOJO_DISALLOW_COPY_AND_ASSIGN(MockSlaveProcessDelegate); |
171 }; | 172 }; |
172 | 173 |
173 class ConnectionManagerTest : public testing::Test { | 174 class ConnectionManagerTest : public testing::Test { |
174 protected: | 175 protected: |
175 ConnectionManagerTest() | 176 ConnectionManagerTest() : message_loop_(CreateTestMessageLoop()) {} |
176 : task_runner_(MakeRefCounted<base_edk::PlatformTaskRunnerImpl>( | |
177 message_loop_.task_runner())) {} | |
178 ~ConnectionManagerTest() override {} | 177 ~ConnectionManagerTest() override {} |
179 | 178 |
180 embedder::PlatformSupport* platform_support() { return &platform_support_; } | 179 embedder::PlatformSupport* platform_support() { return &platform_support_; } |
181 const RefPtr<TaskRunner>& task_runner() { return task_runner_; } | 180 MessageLoop* message_loop() { return message_loop_.get(); } |
| 181 const RefPtr<TaskRunner>& task_runner() { |
| 182 return message_loop_->GetTaskRunner(); |
| 183 } |
182 MockMasterProcessDelegate& master_process_delegate() { | 184 MockMasterProcessDelegate& master_process_delegate() { |
183 return master_process_delegate_; | 185 return master_process_delegate_; |
184 } | 186 } |
185 | 187 |
186 // Connects the given |slave| (with the given |slave_process_delegate|) to the | 188 // Connects the given |slave| (with the given |slave_process_delegate|) to the |
187 // given master, creating and using a |TestSlaveInfo| with the given | 189 // given master, creating and using a |TestSlaveInfo| with the given |
188 // |slave_name|, and returns the process identifier for the slave. | 190 // |slave_name|, and returns the process identifier for the slave. |
189 ProcessIdentifier ConnectSlave( | 191 ProcessIdentifier ConnectSlave( |
190 MasterConnectionManager* master, | 192 MasterConnectionManager* master, |
191 embedder::SlaveProcessDelegate* slave_process_delegate, | 193 embedder::SlaveProcessDelegate* slave_process_delegate, |
192 SlaveConnectionManager* slave, | 194 SlaveConnectionManager* slave, |
193 const std::string& slave_name) { | 195 const std::string& slave_name) { |
194 embedder::PlatformChannelPair platform_channel_pair; | 196 embedder::PlatformChannelPair platform_channel_pair; |
195 ProcessIdentifier slave_process_identifier = | 197 ProcessIdentifier slave_process_identifier = |
196 master->AddSlave(new TestSlaveInfo(slave_name), | 198 master->AddSlave(new TestSlaveInfo(slave_name), |
197 platform_channel_pair.PassServerHandle()); | 199 platform_channel_pair.PassServerHandle()); |
198 slave->Init(task_runner_.Clone(), slave_process_delegate, | 200 slave->Init(task_runner().Clone(), slave_process_delegate, |
199 platform_channel_pair.PassClientHandle()); | 201 platform_channel_pair.PassClientHandle()); |
200 return slave_process_identifier; | 202 return slave_process_identifier; |
201 } | 203 } |
202 | 204 |
203 private: | 205 private: |
204 embedder::SimplePlatformSupport platform_support_; | 206 embedder::SimplePlatformSupport platform_support_; |
205 base::MessageLoop message_loop_; | 207 std::unique_ptr<MessageLoop> message_loop_; |
206 RefPtr<TaskRunner> task_runner_; | |
207 MockMasterProcessDelegate master_process_delegate_; | 208 MockMasterProcessDelegate master_process_delegate_; |
208 | 209 |
209 MOJO_DISALLOW_COPY_AND_ASSIGN(ConnectionManagerTest); | 210 MOJO_DISALLOW_COPY_AND_ASSIGN(ConnectionManagerTest); |
210 }; | 211 }; |
211 | 212 |
212 TEST_F(ConnectionManagerTest, BasicConnectSlaves) { | 213 TEST_F(ConnectionManagerTest, BasicConnectSlaves) { |
213 MasterConnectionManager master(platform_support()); | 214 MasterConnectionManager master(platform_support()); |
214 master.Init(task_runner().Clone(), &master_process_delegate()); | 215 master.Init(task_runner().Clone(), &master_process_delegate()); |
215 | 216 |
216 MockSlaveProcessDelegate slave1_process_delegate; | 217 MockSlaveProcessDelegate slave1_process_delegate; |
(...skipping 28 matching lines...) Expand all Loading... |
245 EXPECT_EQ(ConnectionManager::Result::SUCCESS_CONNECT_NEW_CONNECTION, | 246 EXPECT_EQ(ConnectionManager::Result::SUCCESS_CONNECT_NEW_CONNECTION, |
246 slave2.Connect(connection_id, &peer2, &is_first, &h2)); | 247 slave2.Connect(connection_id, &peer2, &is_first, &h2)); |
247 EXPECT_EQ(slave1_id, peer2); | 248 EXPECT_EQ(slave1_id, peer2); |
248 EXPECT_FALSE(is_first); | 249 EXPECT_FALSE(is_first); |
249 EXPECT_TRUE(h2.is_valid()); | 250 EXPECT_TRUE(h2.is_valid()); |
250 | 251 |
251 EXPECT_TRUE(ArePlatformHandlesConnected(h1.get(), h2.get())); | 252 EXPECT_TRUE(ArePlatformHandlesConnected(h1.get(), h2.get())); |
252 | 253 |
253 // The process manager shouldn't have gotten any notifications yet. (Spin the | 254 // The process manager shouldn't have gotten any notifications yet. (Spin the |
254 // message loop to make sure none were enqueued.) | 255 // message loop to make sure none were enqueued.) |
255 base::RunLoop().RunUntilIdle(); | 256 message_loop()->RunUntilIdle(); |
256 EXPECT_EQ(0u, master_process_delegate().on_slave_disconnect_calls()); | 257 EXPECT_EQ(0u, master_process_delegate().on_slave_disconnect_calls()); |
257 | 258 |
258 slave1.Shutdown(); | 259 slave1.Shutdown(); |
259 | 260 |
260 // |OnSlaveDisconnect()| should be called once. | 261 // |OnSlaveDisconnect()| should be called once. |
261 master_process_delegate().RunUntilNotified(); | 262 master_process_delegate().RunUntilNotified(message_loop()); |
262 EXPECT_EQ(1u, master_process_delegate().on_slave_disconnect_calls()); | 263 EXPECT_EQ(1u, master_process_delegate().on_slave_disconnect_calls()); |
263 EXPECT_EQ("slave1", master_process_delegate().last_slave_disconnect_name()); | 264 EXPECT_EQ("slave1", master_process_delegate().last_slave_disconnect_name()); |
264 | 265 |
265 slave2.Shutdown(); | 266 slave2.Shutdown(); |
266 | 267 |
267 // |OnSlaveDisconnect()| should be called again. | 268 // |OnSlaveDisconnect()| should be called again. |
268 master_process_delegate().RunUntilNotified(); | 269 master_process_delegate().RunUntilNotified(message_loop()); |
269 EXPECT_EQ(2u, master_process_delegate().on_slave_disconnect_calls()); | 270 EXPECT_EQ(2u, master_process_delegate().on_slave_disconnect_calls()); |
270 EXPECT_EQ("slave2", master_process_delegate().last_slave_disconnect_name()); | 271 EXPECT_EQ("slave2", master_process_delegate().last_slave_disconnect_name()); |
271 | 272 |
272 master.Shutdown(); | 273 master.Shutdown(); |
273 | 274 |
274 // None of the above should result in |OnMasterDisconnect()| being called. | 275 // None of the above should result in |OnMasterDisconnect()| being called. |
275 base::RunLoop().RunUntilIdle(); | 276 message_loop()->RunUntilIdle(); |
276 EXPECT_EQ(0u, slave1_process_delegate.on_master_disconnect_calls()); | 277 EXPECT_EQ(0u, slave1_process_delegate.on_master_disconnect_calls()); |
277 EXPECT_EQ(0u, slave2_process_delegate.on_master_disconnect_calls()); | 278 EXPECT_EQ(0u, slave2_process_delegate.on_master_disconnect_calls()); |
278 } | 279 } |
279 | 280 |
280 TEST_F(ConnectionManagerTest, ShutdownMasterBeforeSlave) { | 281 TEST_F(ConnectionManagerTest, ShutdownMasterBeforeSlave) { |
281 MasterConnectionManager master(platform_support()); | 282 MasterConnectionManager master(platform_support()); |
282 master.Init(task_runner().Clone(), &master_process_delegate()); | 283 master.Init(task_runner().Clone(), &master_process_delegate()); |
283 | 284 |
284 MockSlaveProcessDelegate slave_process_delegate; | 285 MockSlaveProcessDelegate slave_process_delegate; |
285 SlaveConnectionManager slave(platform_support()); | 286 SlaveConnectionManager slave(platform_support()); |
286 ProcessIdentifier slave_id = | 287 ProcessIdentifier slave_id = |
287 ConnectSlave(&master, &slave_process_delegate, &slave, "slave"); | 288 ConnectSlave(&master, &slave_process_delegate, &slave, "slave"); |
288 EXPECT_TRUE(IsValidSlaveProcessIdentifier(slave_id)); | 289 EXPECT_TRUE(IsValidSlaveProcessIdentifier(slave_id)); |
289 | 290 |
290 // The process manager shouldn't have gotten any notifications yet. (Spin the | 291 // The process manager shouldn't have gotten any notifications yet. (Spin the |
291 // message loop to make sure none were enqueued.) | 292 // message loop to make sure none were enqueued.) |
292 base::RunLoop().RunUntilIdle(); | 293 message_loop()->RunUntilIdle(); |
293 EXPECT_EQ(0u, master_process_delegate().on_slave_disconnect_calls()); | 294 EXPECT_EQ(0u, master_process_delegate().on_slave_disconnect_calls()); |
294 | 295 |
295 master.Shutdown(); | 296 master.Shutdown(); |
296 | 297 |
297 // |OnSlaveDisconnect()| should be called. | 298 // |OnSlaveDisconnect()| should be called. |
298 master_process_delegate().RunUntilNotified(); | 299 master_process_delegate().RunUntilNotified(message_loop()); |
299 EXPECT_EQ(1u, master_process_delegate().on_slave_disconnect_calls()); | 300 EXPECT_EQ(1u, master_process_delegate().on_slave_disconnect_calls()); |
300 EXPECT_EQ("slave", master_process_delegate().last_slave_disconnect_name()); | 301 EXPECT_EQ("slave", master_process_delegate().last_slave_disconnect_name()); |
301 | 302 |
302 // |OnMasterDisconnect()| should also be (or have been) called. | 303 // |OnMasterDisconnect()| should also be (or have been) called. |
303 slave_process_delegate.RunUntilNotified(); | 304 slave_process_delegate.RunUntilNotified(message_loop()); |
304 EXPECT_EQ(1u, slave_process_delegate.on_master_disconnect_calls()); | 305 EXPECT_EQ(1u, slave_process_delegate.on_master_disconnect_calls()); |
305 | 306 |
306 slave.Shutdown(); | 307 slave.Shutdown(); |
307 } | 308 } |
308 | 309 |
309 TEST_F(ConnectionManagerTest, SlaveCancelConnect) { | 310 TEST_F(ConnectionManagerTest, SlaveCancelConnect) { |
310 MasterConnectionManager master(platform_support()); | 311 MasterConnectionManager master(platform_support()); |
311 master.Init(task_runner().Clone(), &master_process_delegate()); | 312 master.Init(task_runner().Clone(), &master_process_delegate()); |
312 | 313 |
313 MockSlaveProcessDelegate slave1_process_delegate; | 314 MockSlaveProcessDelegate slave1_process_delegate; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
362 | 363 |
363 ConnectionIdentifier connection_id = master.GenerateConnectionIdentifier(); | 364 ConnectionIdentifier connection_id = master.GenerateConnectionIdentifier(); |
364 EXPECT_TRUE(slave1.AllowConnect(connection_id)); | 365 EXPECT_TRUE(slave1.AllowConnect(connection_id)); |
365 EXPECT_TRUE(slave2.AllowConnect(connection_id)); | 366 EXPECT_TRUE(slave2.AllowConnect(connection_id)); |
366 | 367 |
367 slave1.Shutdown(); | 368 slave1.Shutdown(); |
368 | 369 |
369 // |OnSlaveDisconnect()| should be called. After it's called, this means that | 370 // |OnSlaveDisconnect()| should be called. After it's called, this means that |
370 // the disconnect has been detected and handled, including the removal of the | 371 // the disconnect has been detected and handled, including the removal of the |
371 // pending connection. | 372 // pending connection. |
372 master_process_delegate().RunUntilNotified(); | 373 master_process_delegate().RunUntilNotified(message_loop()); |
373 EXPECT_EQ(1u, master_process_delegate().on_slave_disconnect_calls()); | 374 EXPECT_EQ(1u, master_process_delegate().on_slave_disconnect_calls()); |
374 | 375 |
375 ProcessIdentifier peer2 = kInvalidProcessIdentifier; | 376 ProcessIdentifier peer2 = kInvalidProcessIdentifier; |
376 bool is_first = false; | 377 bool is_first = false; |
377 embedder::ScopedPlatformHandle h2; | 378 embedder::ScopedPlatformHandle h2; |
378 EXPECT_EQ(ConnectionManager::Result::FAILURE, | 379 EXPECT_EQ(ConnectionManager::Result::FAILURE, |
379 slave2.Connect(connection_id, &peer2, &is_first, &h2)); | 380 slave2.Connect(connection_id, &peer2, &is_first, &h2)); |
380 EXPECT_EQ(kInvalidProcessIdentifier, peer2); | 381 EXPECT_EQ(kInvalidProcessIdentifier, peer2); |
381 EXPECT_FALSE(is_first); | 382 EXPECT_FALSE(is_first); |
382 EXPECT_FALSE(h2.is_valid()); | 383 EXPECT_FALSE(h2.is_valid()); |
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
690 | 691 |
691 slave.Shutdown(); | 692 slave.Shutdown(); |
692 master.Shutdown(); | 693 master.Shutdown(); |
693 } | 694 } |
694 | 695 |
695 // TODO(vtl): More shutdown cases for |AddSlaveAndBootstrap()|? | 696 // TODO(vtl): More shutdown cases for |AddSlaveAndBootstrap()|? |
696 | 697 |
697 } // namespace | 698 } // namespace |
698 } // namespace system | 699 } // namespace system |
699 } // namespace mojo | 700 } // namespace mojo |
OLD | NEW |