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