• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
CallDoWorkAndSignalTask(Callback0::Type * work,base::WaitableEvent * work_done,UIModelWorker * scheduler)40     CallDoWorkAndSignalTask(Callback0::Type* work,
41                             base::WaitableEvent* work_done,
42                             UIModelWorker* scheduler)
43         : work_(work), work_done_(work_done), scheduler_(scheduler) {
44     }
~CallDoWorkAndSignalTask()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.
OnTaskCompleted()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