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

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

Issue 14046031: Worker changes to prepare for lock-free shutdown. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 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 | Annotate | Revision Log
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/ui_model_worker.h" 5 #include "chrome/browser/sync/glue/ui_model_worker.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/message_loop.h" 9 #include "base/message_loop.h"
10 #include "base/synchronization/waitable_event.h" 10 #include "base/synchronization/waitable_event.h"
(...skipping 27 matching lines...) Expand all
38 *error_info = work.Run(); 38 *error_info = work.Run();
39 39
40 // Notify the UIModelWorker that scheduled us that we have run 40 // Notify the UIModelWorker that scheduled us that we have run
41 // successfully. 41 // successfully.
42 scheduler->OnTaskCompleted(); 42 scheduler->OnTaskCompleted();
43 work_done->Signal(); // Unblock the syncer thread that scheduled us. 43 work_done->Signal(); // Unblock the syncer thread that scheduled us.
44 } 44 }
45 45
46 } // namespace 46 } // namespace
47 47
48 UIModelWorker::UIModelWorker() 48 UIModelWorker::UIModelWorker(syncer::WorkerLoopDestructionObserver* observer)
49 : state_(WORKING), 49 : syncer::ModelSafeWorker(observer),
50 state_(WORKING),
50 syncapi_has_shutdown_(false), 51 syncapi_has_shutdown_(false),
51 syncapi_event_(&lock_) { 52 syncapi_event_(&lock_) {
52 } 53 }
53 54
54 void UIModelWorker::Stop() { 55 void UIModelWorker::Stop() {
55 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 56 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
56 57
57 base::AutoLock lock(lock_); 58 base::AutoLock lock(lock_);
58 DCHECK_EQ(state_, WORKING); 59 DCHECK_EQ(state_, WORKING);
59 60
60 // We're on our own now, the beloved UI MessageLoop is no longer running. 61 // We're on our own now, the beloved UI MessageLoop is no longer running.
61 // Any tasks scheduled or to be scheduled on the UI MessageLoop will not run. 62 // Any tasks scheduled or to be scheduled on the UI MessageLoop will not run.
62 state_ = RUNNING_MANUAL_SHUTDOWN_PUMP; 63 state_ = RUNNING_MANUAL_SHUTDOWN_PUMP;
63 64
64 // Drain any final tasks manually until the SyncerThread tells us it has 65 // Drain any final tasks manually until the SyncerThread tells us it has
65 // totally finished. There should only ever be 0 or 1 tasks Run() here. 66 // totally finished. There should only ever be 0 or 1 tasks Run() here.
66 while (!syncapi_has_shutdown_) { 67 while (!syncapi_has_shutdown_) {
67 if (!pending_work_.is_null()) 68 if (!pending_work_.is_null())
68 pending_work_.Run(); // OnTaskCompleted will set reset |pending_work_|. 69 pending_work_.Run(); // OnTaskCompleted will set reset |pending_work_|.
69 70
70 // http://crbug.com/19757 71 // http://crbug.com/19757
71 base::ThreadRestrictions::ScopedAllowWait allow_wait; 72 base::ThreadRestrictions::ScopedAllowWait allow_wait;
72 // Wait for either a new task or SyncerThread termination. 73 // Wait for either a new task or SyncerThread termination.
73 syncapi_event_.Wait(); 74 syncapi_event_.Wait();
74 } 75 }
75 76
76 state_ = STOPPED; 77 state_ = STOPPED;
77 } 78 }
78 79
79 syncer::SyncerError UIModelWorker::DoWorkAndWaitUntilDone( 80 void UIModelWorker::RegisterForLoopDestruction() {
81 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
82 MessageLoop::current()->AddDestructionObserver(this);
83 }
84
85 syncer::SyncerError UIModelWorker::DoWorkAndWaitUntilDoneImpl(
80 const syncer::WorkCallback& work) { 86 const syncer::WorkCallback& work) {
81 // In most cases, this method is called in WORKING state. It is possible this 87 // In most cases, this method is called in WORKING state. It is possible this
82 // gets called when we are in the RUNNING_MANUAL_SHUTDOWN_PUMP state, because 88 // gets called when we are in the RUNNING_MANUAL_SHUTDOWN_PUMP state, because
83 // the UI loop has initiated shutdown but the syncer hasn't got the memo yet. 89 // the UI loop has initiated shutdown but the syncer hasn't got the memo yet.
84 // This is fine, the work will get scheduled and run normally or run by our 90 // This is fine, the work will get scheduled and run normally or run by our
85 // code handling this case in Stop(). Note there _no_ way we can be in here 91 // code handling this case in Stop(). Note there _no_ way we can be in here
86 // with state_ = STOPPED, so it is safe to read / compare in this case. 92 // with state_ = STOPPED, so it is safe to read / compare in this case.
87 CHECK_NE(ANNOTATE_UNPROTECTED_READ(state_), STOPPED); 93 CHECK_NE(ANNOTATE_UNPROTECTED_READ(state_), STOPPED);
88 syncer::SyncerError error_info; 94 syncer::SyncerError error_info;
89 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { 95 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
90 DLOG(WARNING) << "DoWorkAndWaitUntilDone called from " 96 DLOG(WARNING) << "DoWorkAndWaitUntilDone called from "
91 << "ui_loop_. Probably a nested invocation?"; 97 << "ui_loop_. Probably a nested invocation?";
92 return work.Run(); 98 return work.Run();
93 } 99 }
94 100
95 // Create an unsignaled event to wait on.
96 base::WaitableEvent work_done(false, false);
97 { 101 {
98 // We lock only to avoid PostTask'ing a NULL pending_work_ (because it 102 // We lock only to avoid PostTask'ing a NULL pending_work_ (because it
99 // could get Run() in Stop() and call OnTaskCompleted before we post). 103 // could get Run() in Stop() and call OnTaskCompleted before we post).
100 // The task is owned by the message loop as per usual. 104 // The task is owned by the message loop as per usual.
101 base::AutoLock lock(lock_); 105 base::AutoLock lock(lock_);
102 DCHECK(pending_work_.is_null()); 106 DCHECK(pending_work_.is_null());
103 pending_work_ = base::Bind(&CallDoWorkAndSignalCallback, work, &work_done, 107 pending_work_ = base::Bind(&CallDoWorkAndSignalCallback, work,
108 work_done_or_stopped(),
104 base::Unretained(this), &error_info); 109 base::Unretained(this), &error_info);
105 if (!BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, pending_work_)) { 110 if (!BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, pending_work_)) {
106 DLOG(WARNING) << "Could not post work to UI loop."; 111 DLOG(WARNING) << "Could not post work to UI loop.";
107 error_info = syncer::CANNOT_DO_WORK; 112 error_info = syncer::CANNOT_DO_WORK;
108 pending_work_.Reset(); 113 pending_work_.Reset();
109 syncapi_event_.Signal(); 114 syncapi_event_.Signal();
110 return error_info; 115 return error_info;
111 } 116 }
112 } 117 }
113 syncapi_event_.Signal(); // Notify that the syncapi produced work for us. 118 syncapi_event_.Signal(); // Notify that the syncapi produced work for us.
114 work_done.Wait(); 119 work_done_or_stopped()->Wait();
115 return error_info; 120 return error_info;
116 } 121 }
117 122
118 syncer::ModelSafeGroup UIModelWorker::GetModelSafeGroup() { 123 syncer::ModelSafeGroup UIModelWorker::GetModelSafeGroup() {
119 return syncer::GROUP_UI; 124 return syncer::GROUP_UI;
120 } 125 }
121 126
122 void UIModelWorker::OnSyncerShutdownComplete() { 127 void UIModelWorker::OnSyncerShutdownComplete() {
123 base::AutoLock lock(lock_); 128 base::AutoLock lock(lock_);
124 // The SyncerThread has terminated and we are no longer needed by syncapi. 129 // The SyncerThread has terminated and we are no longer needed by syncapi.
125 // The UI loop initiated shutdown and is (or will be) waiting in Stop(). 130 // The UI loop initiated shutdown and is (or will be) waiting in Stop().
126 // We could either be WORKING or RUNNING_MANUAL_SHUTDOWN_PUMP, depending 131 // We could either be WORKING or RUNNING_MANUAL_SHUTDOWN_PUMP, depending
127 // on where we timeslice the UI thread in Stop; but we can't be STOPPED, 132 // on where we timeslice the UI thread in Stop; but we can't be STOPPED,
128 // because that would imply OnSyncerShutdownComplete already signaled. 133 // because that would imply OnSyncerShutdownComplete already signaled.
129 DCHECK_NE(state_, STOPPED); 134 DCHECK_NE(state_, STOPPED);
130 135
131 syncapi_has_shutdown_ = true; 136 syncapi_has_shutdown_ = true;
132 syncapi_event_.Signal(); 137 syncapi_event_.Signal();
133 } 138 }
134 139
135 UIModelWorker::~UIModelWorker() { 140 UIModelWorker::~UIModelWorker() {
136 DCHECK_EQ(state_, STOPPED); 141 DCHECK_EQ(state_, STOPPED);
137 } 142 }
138 143
139 } // namespace browser_sync 144 } // namespace browser_sync
OLDNEW
« no previous file with comments | « chrome/browser/sync/glue/ui_model_worker.h ('k') | chrome/browser/sync/glue/ui_model_worker_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698