Home | History | Annotate | Download | only in glue
      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