1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_SYNC_GLUE_UI_MODEL_WORKER_H_ 6 #define CHROME_BROWSER_SYNC_GLUE_UI_MODEL_WORKER_H_ 7 #pragma once 8 9 #include "base/callback.h" 10 #include "base/synchronization/lock.h" 11 #include "base/synchronization/condition_variable.h" 12 #include "base/task.h" 13 #include "chrome/browser/sync/engine/syncapi.h" 14 #include "chrome/browser/sync/engine/model_safe_worker.h" 15 16 namespace base { 17 class WaitableEvent; 18 } 19 20 class MessageLoop; 21 22 namespace browser_sync { 23 24 // A ModelSafeWorker for UI models (e.g. bookmarks) that accepts work requests 25 // from the syncapi that need to be fulfilled from the MessageLoop home to the 26 // native model. 27 // 28 // Lifetime note: Instances of this class will generally be owned by the 29 // SyncerThread. When the SyncerThread _object_ is destroyed, the 30 // UIModelWorker will be destroyed. The SyncerThread object is destroyed 31 // after the actual syncer pthread has exited. 32 class UIModelWorker : public browser_sync::ModelSafeWorker { 33 public: 34 UIModelWorker(); 35 virtual ~UIModelWorker(); 36 37 // A simple task to signal a waitable event after Run()ning a Closure. 38 class CallDoWorkAndSignalTask : public Task { 39 public: 40 CallDoWorkAndSignalTask(Callback0::Type* work, 41 base::WaitableEvent* work_done, 42 UIModelWorker* scheduler) 43 : work_(work), work_done_(work_done), scheduler_(scheduler) { 44 } 45 virtual ~CallDoWorkAndSignalTask() { } 46 47 // Task implementation. 48 virtual void Run(); 49 50 private: 51 // Task data - a closure and a waitable event to signal after the work has 52 // been done. 53 Callback0::Type* work_; 54 base::WaitableEvent* work_done_; 55 56 // The UIModelWorker responsible for scheduling us. 57 UIModelWorker* const scheduler_; 58 59 DISALLOW_COPY_AND_ASSIGN(CallDoWorkAndSignalTask); 60 }; 61 62 // Called by the UI thread on shutdown of the sync service. Blocks until 63 // the UIModelWorker has safely met termination conditions, namely that 64 // no task scheduled by CallDoWorkFromModelSafeThreadAndWait remains un- 65 // processed and that syncapi will not schedule any further work for us to do. 66 void Stop(); 67 68 // ModelSafeWorker implementation. Called on syncapi SyncerThread. 69 virtual void DoWorkAndWaitUntilDone(Callback0::Type* work); 70 virtual ModelSafeGroup GetModelSafeGroup(); 71 virtual bool CurrentThreadIsWorkThread(); 72 73 // Upon receiving this idempotent call, the ModelSafeWorker can 74 // assume no work will ever be scheduled again from now on. If it has any work 75 // that it has not yet completed, it must make sure to run it as soon as 76 // possible as the Syncer is trying to shut down. Called from the CoreThread. 77 void OnSyncerShutdownComplete(); 78 79 // Callback from |pending_work_| to notify us that it has been run. 80 // Called on ui loop. 81 void OnTaskCompleted() { pending_work_ = NULL; } 82 83 private: 84 // The life-cycle of a UIModelWorker in three states. 85 enum State { 86 // We hit the ground running in this state and remain until 87 // the UI loop calls Stop(). 88 WORKING, 89 // Stop() sequence has been initiated, but we have not received word that 90 // the SyncerThread has terminated and doesn't need us anymore. Since the 91 // UI MessageLoop is not running at this point, we manually process any 92 // last pending_task_ that the Syncer throws at us, effectively dedicating 93 // the UI thread to terminating the Syncer. 94 RUNNING_MANUAL_SHUTDOWN_PUMP, 95 // We have come to a complete stop, no scheduled work remains, and no work 96 // will be scheduled from now until our destruction. 97 STOPPED, 98 }; 99 100 // This is set by the UI thread, but is not explicitly thread safe, so only 101 // read this value from other threads when you know it is absolutely safe. 102 State state_; 103 104 // We keep a reference to any task we have scheduled so we can gracefully 105 // force them to run if the syncer is trying to shutdown. 106 Task* pending_work_; 107 108 // Set by the SyncCoreThread when Syncapi shutdown has completed and the 109 // SyncerThread has terminated, so no more work will be scheduled. Read by 110 // the UI thread in Stop(). 111 bool syncapi_has_shutdown_; 112 113 // We use a Lock for all data members and a ConditionVariable to synchronize. 114 // We do this instead of using a WaitableEvent and a bool condition in order 115 // to guard against races that could arise due to the fact that the lack of a 116 // barrier permits instructions to be reordered by compiler optimizations. 117 // Possible or not, that route makes for very fragile code due to existence 118 // of theoretical races. 119 base::Lock lock_; 120 121 // Used as a barrier at shutdown to ensure the SyncerThread terminates before 122 // we allow the UI thread to return from Stop(). This gets signalled whenever 123 // one of two events occur: a new pending_work_ task was scheduled, or the 124 // SyncerThread has terminated. We only care about (1) when we are in Stop(), 125 // because we have to manually Run() the task. 126 base::ConditionVariable syncapi_event_; 127 128 DISALLOW_COPY_AND_ASSIGN(UIModelWorker); 129 }; 130 131 } // namespace browser_sync 132 133 #endif // CHROME_BROWSER_SYNC_GLUE_UI_MODEL_WORKER_H_ 134