Index: sync/internal_api/public/engine/model_safe_worker.cc |
diff --git a/sync/internal_api/public/engine/model_safe_worker.cc b/sync/internal_api/public/engine/model_safe_worker.cc |
index eb3fc1f1c3ec286c961e743b23b05e77a7eae358..2aea5cf8378b0b9dbc1350410bdea6b19f8fe2a1 100644 |
--- a/sync/internal_api/public/engine/model_safe_worker.cc |
+++ b/sync/internal_api/public/engine/model_safe_worker.cc |
@@ -75,8 +75,8 @@ ModelSafeWorker::ModelSafeWorker(WorkerLoopDestructionObserver* observer) |
: stopped_(false), |
work_done_or_stopped_(false, false), |
observer_(observer), |
- working_loop_(NULL), |
- working_loop_set_wait_(true, false) {} |
+ working_loop_(NULL) { |
+} |
ModelSafeWorker::~ModelSafeWorker() {} |
@@ -135,26 +135,42 @@ void ModelSafeWorker::WillDestroyCurrentMessageLoop() { |
void ModelSafeWorker::SetWorkingLoopToCurrent() { |
base::AutoLock l(working_loop_lock_); |
DCHECK(!working_loop_); |
- working_loop_ = base::MessageLoop::current(); |
- working_loop_set_wait_.Signal(); |
+ |
+ if (unregister_done_callback_.is_null()) { |
+ // Expected case - UnregisterForLoopDestruction hasn't been called yet. |
+ base::MessageLoop::current()->AddDestructionObserver(this); |
+ working_loop_ = base::MessageLoop::current(); |
+ } else { |
+ // Rare case which is possible when the model type thread remains |
+ // blocked for the entire session and UnregisterForLoopDestruction ends |
+ // up being called before this method. This method is posted unlike |
+ // UnregisterForLoopDestruction - that's why they can end up being called |
+ // out of order. |
+ // In this case we skip the destruction observer registration |
+ // and just invoke the callback stored at UnregisterForLoopDestruction. |
+ DCHECK(stopped_); |
+ unregister_done_callback_.Run(GetModelSafeGroup()); |
+ } |
} |
void ModelSafeWorker::UnregisterForLoopDestruction( |
base::Callback<void(ModelSafeGroup)> unregister_done_callback) { |
- // Ok to wait until |working_loop_| is set because this is called on sync |
- // loop. |
- working_loop_set_wait_.Wait(); |
- |
- { |
- base::AutoLock l(working_loop_lock_); |
- if (working_loop_ != NULL) { |
- // Should be called on sync loop. |
- DCHECK_NE(base::MessageLoop::current(), working_loop_); |
- working_loop_->PostTask( |
- FROM_HERE, |
- base::Bind(&ModelSafeWorker::UnregisterForLoopDestructionAsync, |
- this, unregister_done_callback)); |
- } |
+ base::AutoLock l(working_loop_lock_); |
+ if (working_loop_ != NULL) { |
+ // Normal case - observer registration has been already done. |
+ // Delegate to the sync thread to do the actual unregistration in |
+ // UnregisterForLoopDestructionAsync. |
+ DCHECK_NE(base::MessageLoop::current(), working_loop_); |
+ working_loop_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&ModelSafeWorker::UnregisterForLoopDestructionAsync, |
+ this, |
+ unregister_done_callback)); |
+ } else { |
+ // The working loop is still unknown, probably because the model type |
+ // thread is blocked. Store the callback to be called from |
+ // SetWorkingLoopToCurrent. |
+ unregister_done_callback_ = unregister_done_callback; |
} |
} |