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

Side by Side Diff: chrome/browser/sync/glue/sync_backend_registrar_unittest.cc

Issue 640853008: Sync: Avoid deadlock in SyncBackendRegistrar / ModelSafeWorker on sync backend shutdown. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed CR feedback and verified under valgrind Created 6 years, 2 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "chrome/browser/sync/glue/sync_backend_registrar.h" 5 #include "chrome/browser/sync/glue/sync_backend_registrar.h"
6 6
7 #include "base/run_loop.h"
7 #include "chrome/browser/sync/glue/ui_model_worker.h" 8 #include "chrome/browser/sync/glue/ui_model_worker.h"
8 #include "chrome/test/base/testing_profile.h" 9 #include "chrome/test/base/testing_profile.h"
9 #include "components/sync_driver/change_processor_mock.h" 10 #include "components/sync_driver/change_processor_mock.h"
10 #include "content/public/browser/browser_thread.h" 11 #include "content/public/browser/browser_thread.h"
11 #include "content/public/test/test_browser_thread_bundle.h" 12 #include "content/public/test/test_browser_thread_bundle.h"
12 #include "sync/internal_api/public/base/model_type.h" 13 #include "sync/internal_api/public/base/model_type.h"
13 #include "sync/internal_api/public/test/test_user_share.h" 14 #include "sync/internal_api/public/test/test_user_share.h"
14 #include "testing/gmock/include/gmock/gmock.h" 15 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h" 16 #include "testing/gtest/include/gtest/gtest.h"
16 17
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after
249 done.Wait(); 250 done.Wait();
250 251
251 registrar_->DeactivateDataType(AUTOFILL); 252 registrar_->DeactivateDataType(AUTOFILL);
252 ExpectRoutingInfo(registrar_.get(), syncer::ModelSafeRoutingInfo()); 253 ExpectRoutingInfo(registrar_.get(), syncer::ModelSafeRoutingInfo());
253 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet()); 254 ExpectHasProcessorsForTypes(*registrar_, ModelTypeSet());
254 255
255 // Should do nothing. 256 // Should do nothing.
256 TriggerChanges(registrar_.get(), AUTOFILL); 257 TriggerChanges(registrar_.get(), AUTOFILL);
257 } 258 }
258 259
260 class SyncBackendRegistrarShutdownTest : public testing::Test {
261 public:
262 void BlockDBThread() {
263 EXPECT_FALSE(lock_.Try());
264
265 db_thread_blocked_.Signal();
266 base::AutoLock l(lock_);
267 }
268
269 protected:
270 friend class TestRegistrar;
271
272 SyncBackendRegistrarShutdownTest()
273 : thread_bundle_(content::TestBrowserThreadBundle::REAL_DB_THREAD |
274 content::TestBrowserThreadBundle::REAL_FILE_THREAD |
275 content::TestBrowserThreadBundle::REAL_IO_THREAD),
276 db_thread_blocked_(false, false) {}
277
278 virtual ~SyncBackendRegistrarShutdownTest() {}
279
280 void PostQuitOnUIMessageLoop() {
281 base::AutoLock l(lock_);
Nicolas Zea 2014/10/23 18:07:16 given that you control the lifetime of the registr
stanisc 2014/10/23 19:21:57 I've done this based on the thread sanitizer outpu
282 EXPECT_FALSE(quit_closure_.is_null());
283 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_closure_);
284 }
285
286 content::TestBrowserThreadBundle thread_bundle_;
287 TestingProfile profile_;
288 base::WaitableEvent db_thread_blocked_;
289 // The lock is used to block the DB thread and also to access quit_closure_
290 base::Lock lock_;
Nicolas Zea 2014/10/23 18:07:16 nit: perhaps name this db_thread_lock_?
stanisc 2014/10/23 19:21:57 I renamed it because its purpose got extended to p
291 base::RunLoop run_loop_;
292 base::Closure quit_closure_;
293 };
294
295 // Wrap SyncBackendRegistrar so that we can monitor its lifetime.
296 class TestRegistrar : public SyncBackendRegistrar {
297 public:
298 explicit TestRegistrar(
299 Profile* profile, SyncBackendRegistrarShutdownTest* test)
300 : SyncBackendRegistrar("test", profile, scoped_ptr<base::Thread>()),
301 test_(test) {}
302
303 ~TestRegistrar() override {
304 test_->PostQuitOnUIMessageLoop();
305 }
306
307 private:
308 SyncBackendRegistrarShutdownTest* test_;
309 };
310
311 TEST_F(SyncBackendRegistrarShutdownTest, BlockingShutdown) {
312 // Take ownership of |lock_| so that the DB thread can't acquire it.
313 lock_.Acquire();
314
315 quit_closure_ = run_loop_.QuitClosure();
Nicolas Zea 2014/10/23 18:07:16 nit: may as well just put this in the constructor
stanisc 2014/10/23 19:21:57 Done.
316
317 // This will block the DB thread by waiting on |lock_|.
318 BrowserThread::PostTask(
319 BrowserThread::DB,
320 FROM_HERE,
321 base::Bind(&SyncBackendRegistrarShutdownTest::BlockDBThread,
322 base::Unretained(this)));
323
324 scoped_ptr<TestRegistrar> registrar(new TestRegistrar(&profile_, this));
325 base::Thread* sync_thread = registrar->sync_thread();
326
327 // Stop here until the DB thread gets a chance to run and block on the lock.
328 // Please note that since the task above didn't finish, the task to
329 // initialize the worker on the DB thread hasn't had a chance to run yet too.
330 // Which means ModelSafeWorker::SetWorkingLoopToCurrent hasn't been called
331 // for the DB worker.
332 db_thread_blocked_.Wait();
333
334 registrar->SetInitialTypes(ModelTypeSet());
335
336 // Start the shutdown.
337 registrar->RequestWorkerStopOnUIThread();
338
339 sync_thread->message_loop()->PostTask(
340 FROM_HERE,
341 base::Bind(&SyncBackendRegistrar::Shutdown,
342 base::Unretained(registrar.release())));
343
344 // The test verifies that the sync thread doesn't block because
345 // of the blocked DB thread and can finish the shutdown.
346 sync_thread->message_loop()->RunUntilIdle();
Nicolas Zea 2014/10/23 18:07:16 Could you sanity check that this is necessary? Syn
stanisc 2014/10/23 19:21:57 I think this is needed to ensure that the task pos
347
348 lock_.Release();
349
350 // Run the main thread loop until all workers have been removed and the
351 // registrar destroyed.
352 run_loop_.Run();
353 }
354
259 } // namespace 355 } // namespace
260 356
261 } // namespace browser_sync 357 } // namespace browser_sync
OLDNEW
« no previous file with comments | « chrome/browser/sync/glue/password_model_worker.cc ('k') | chrome/browser/sync/glue/ui_model_worker.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698