1 // Copyright (c) 2012 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.
5 #ifndef CHROME_BROWSER_SYNC_GLUE_UI_MODEL_WORKER_H_
6 #define CHROME_BROWSER_SYNC_GLUE_UI_MODEL_WORKER_H_
8 #include "base/callback.h"
9 #include "base/compiler_specific.h"
10 #include "base/synchronization/condition_variable.h"
11 #include "base/synchronization/lock.h"
12 #include "sync/internal_api/public/engine/model_safe_worker.h"
13 #include "sync/internal_api/public/util/unrecoverable_error_info.h"
15 namespace browser_sync
{
17 // A syncer::ModelSafeWorker for UI models (e.g. bookmarks) that
18 // accepts work requests from the syncapi that need to be fulfilled
19 // from the MessageLoop home to the native model.
21 // Lifetime note: Instances of this class will generally be owned by the
22 // SyncerThread. When the SyncerThread _object_ is destroyed, the
23 // UIModelWorker will be destroyed. The SyncerThread object is destroyed
24 // after the actual syncer pthread has exited.
25 class UIModelWorker
: public syncer::ModelSafeWorker
{
29 // Called by the UI thread on shutdown of the sync service. Blocks until
30 // the UIModelWorker has safely met termination conditions, namely that
31 // no task scheduled by CallDoWorkFromModelSafeThreadAndWait remains un-
32 // processed and that syncapi will not schedule any further work for us to do.
35 // syncer::ModelSafeWorker implementation. Called on syncapi SyncerThread.
36 virtual syncer::SyncerError
DoWorkAndWaitUntilDone(
37 const syncer::WorkCallback
& work
) OVERRIDE
;
38 virtual syncer::ModelSafeGroup
GetModelSafeGroup() OVERRIDE
;
40 // Upon receiving this idempotent call, the syncer::ModelSafeWorker can
41 // assume no work will ever be scheduled again from now on. If it has any work
42 // that it has not yet completed, it must make sure to run it as soon as
43 // possible as the Syncer is trying to shut down. Called from the CoreThread.
44 void OnSyncerShutdownComplete();
46 // Callback from |pending_work_| to notify us that it has been run.
48 void OnTaskCompleted() { pending_work_
.Reset(); }
51 // The life-cycle of a UIModelWorker in three states.
53 // We hit the ground running in this state and remain until
54 // the UI loop calls Stop().
56 // Stop() sequence has been initiated, but we have not received word that
57 // the SyncerThread has terminated and doesn't need us anymore. Since the
58 // UI MessageLoop is not running at this point, we manually process any
59 // last pending_task_ that the Syncer throws at us, effectively dedicating
60 // the UI thread to terminating the Syncer.
61 RUNNING_MANUAL_SHUTDOWN_PUMP
,
62 // We have come to a complete stop, no scheduled work remains, and no work
63 // will be scheduled from now until our destruction.
67 virtual ~UIModelWorker();
69 // This is set by the UI thread, but is not explicitly thread safe, so only
70 // read this value from other threads when you know it is absolutely safe.
73 // We keep a reference to any task we have scheduled so we can gracefully
74 // force them to run if the syncer is trying to shutdown.
75 base::Closure pending_work_
;
77 // Set by the SyncCoreThread when Syncapi shutdown has completed and the
78 // SyncerThread has terminated, so no more work will be scheduled. Read by
79 // the UI thread in Stop().
80 bool syncapi_has_shutdown_
;
82 // We use a Lock for all data members and a ConditionVariable to synchronize.
83 // We do this instead of using a WaitableEvent and a bool condition in order
84 // to guard against races that could arise due to the fact that the lack of a
85 // barrier permits instructions to be reordered by compiler optimizations.
86 // Possible or not, that route makes for very fragile code due to existence
87 // of theoretical races.
90 // Used as a barrier at shutdown to ensure the SyncerThread terminates before
91 // we allow the UI thread to return from Stop(). This gets signalled whenever
92 // one of two events occur: a new pending_work_ task was scheduled, or the
93 // SyncerThread has terminated. We only care about (1) when we are in Stop(),
94 // because we have to manually Run() the task.
95 base::ConditionVariable syncapi_event_
;
97 DISALLOW_COPY_AND_ASSIGN(UIModelWorker
);
100 } // namespace browser_sync
102 #endif // CHROME_BROWSER_SYNC_GLUE_UI_MODEL_WORKER_H_