Index: components/sync/driver/glue/ui_model_worker.cc |
diff --git a/components/sync/driver/glue/ui_model_worker.cc b/components/sync/driver/glue/ui_model_worker.cc |
index c812f9a9b54ed6b95cf0c974a3d07f778f2eac48..bd0ae696ca4b2c02655c1f6a24552cdb27533df7 100644 |
--- a/components/sync/driver/glue/ui_model_worker.cc |
+++ b/components/sync/driver/glue/ui_model_worker.cc |
@@ -9,16 +9,24 @@ |
#include "base/bind.h" |
#include "base/bind_helpers.h" |
#include "base/callback.h" |
-#include "base/synchronization/waitable_event.h" |
#include "components/sync/base/scoped_event_signal.h" |
namespace syncer { |
namespace { |
-void CallDoWorkAndSignalEvent(const WorkCallback& work, |
- syncer::ScopedEventSignal scoped_event_signal, |
- SyncerError* error_info) { |
+// |worker| owns the event backing |scoped_event_signal|, so it's important that |
+// it comes after in the parameter list so it gets destroyed after. |
+void DoWorkAndSignalEvent(const WorkCallback& work, |
+ syncer::ScopedEventSignal scoped_event_signal, |
+ scoped_refptr<ModelSafeWorker> worker, |
+ SyncerError* error_info) { |
+ DCHECK(worker->IsOnModelThread()); |
+ if (worker->IsStopped()) { |
+ // Don't set the error here; the pointer may no longer be valid. |
+ return; |
+ } |
+ |
*error_info = work.Run(); |
// The event in |scoped_event_signal| is signaled at the end of this scope. |
} |
@@ -27,7 +35,10 @@ void CallDoWorkAndSignalEvent(const WorkCallback& work, |
UIModelWorker::UIModelWorker( |
scoped_refptr<base::SingleThreadTaskRunner> ui_thread) |
- : ui_thread_(std::move(ui_thread)) {} |
+ : ui_thread_(std::move(ui_thread)), |
+ work_done_or_abandoned_(base::WaitableEvent::ResetPolicy::AUTOMATIC, |
+ base::WaitableEvent::InitialState::NOT_SIGNALED) { |
+} |
SyncerError UIModelWorker::DoWorkAndWaitUntilDoneImpl( |
const WorkCallback& work) { |
@@ -38,26 +49,26 @@ SyncerError UIModelWorker::DoWorkAndWaitUntilDoneImpl( |
return work.Run(); |
} |
- // Signaled when the task is deleted, i.e. after it runs or when it is |
- // abandoned. |
- base::WaitableEvent work_done_or_abandoned( |
- base::WaitableEvent::ResetPolicy::AUTOMATIC, |
- base::WaitableEvent::InitialState::NOT_SIGNALED); |
- |
- if (!ui_thread_->PostTask(FROM_HERE, |
- base::Bind(&CallDoWorkAndSignalEvent, work, |
- base::Passed(syncer::ScopedEventSignal( |
- &work_done_or_abandoned)), |
- &error_info))) { |
+ if (!ui_thread_->PostTask( |
+ FROM_HERE, base::Bind(&DoWorkAndSignalEvent, work, |
+ base::Passed(syncer::ScopedEventSignal( |
+ &work_done_or_abandoned_)), |
+ make_scoped_refptr(this), &error_info))) { |
DLOG(WARNING) << "Could not post work to UI loop."; |
error_info = CANNOT_DO_WORK; |
return error_info; |
} |
- work_done_or_abandoned.Wait(); |
+ work_done_or_abandoned_.Wait(); |
return error_info; |
} |
+void UIModelWorker::RequestStop() { |
+ DCHECK(ui_thread_->BelongsToCurrentThread()); |
+ ModelSafeWorker::RequestStop(); |
+ work_done_or_abandoned_.Signal(); |
+} |
+ |
ModelSafeGroup UIModelWorker::GetModelSafeGroup() { |
return GROUP_UI; |
} |