summaryrefslogtreecommitdiffstats
path: root/sync
diff options
context:
space:
mode:
authorrlarocque@chromium.org <rlarocque@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-19 01:17:02 +0000
committerrlarocque@chromium.org <rlarocque@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-19 01:17:02 +0000
commitea29851b736ba58190146f5ce0bef59683ad8904 (patch)
treed5dea3dc7483b2d65601d87304b3282189f3dbb5 /sync
parent4f432a56da54cdbe213ae943944599072a690c75 (diff)
downloadchromium_src-ea29851b736ba58190146f5ce0bef59683ad8904.zip
chromium_src-ea29851b736ba58190146f5ce0bef59683ad8904.tar.gz
chromium_src-ea29851b736ba58190146f5ce0bef59683ad8904.tar.bz2
sync: Gracefully handle early shutdown
Introduce a new object to communicate cross-thread cancellation signals. This new object, the CancellationSignal, is protected by a lock. It allows the receiving thread to query whether or not a stop has been requested. It also allows the receiving thread to safely register a cross-thread callback to be invoked immediately when a stop is requested. We use two instances of this class to ensure we meet all the requirements for a safe and fast sync backend shutdown. The first instance is used with the HttpBridgeFactory to allow the UI thread to force it to drop all refereces to its RequestContextGetter immediately. This is an important part of our plan to ensure that all references to that object are released before ProfileSyncService::Shutdown() returns, which is necessary to avoid racy crashes at shutdown. (See crbug.com/236451) The second instance is used with the ServerConnectionManager and the Syncer. Once signalled, it ensures that any active connections are released (possibly decrementing another ref to the RequestContextGetter), that any blocking I/O is aborted, and that no more connections will be instantiated. It's important to prevent the creation of more connections because the HttpBridgeFactory might trigger a crash if we asked it to create another connection after it had been shut down. The syncer's interaction with the second cancelation signal is more passive. It does not execute any callbacks when the signal is sent. Instead, it queries the signal as it performs sync cycles, and will cut short any existing sync cycle if it notices the signal has been sent. Finally, this CL includes one important change to the initialization of the HttpBridgeFactory. In order to properly register with the cancellation signal while still allowing the creation of the user agent to occur on the sync thread, its initialization had to be split into two parts. This class now has an Init() method in addition to its constructor. BUG=236451 Review URL: https://chromiumcodereview.appspot.com/23717047 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@224014 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sync')
-rw-r--r--sync/engine/net/server_connection_manager.cc20
-rw-r--r--sync/engine/net/server_connection_manager.h13
-rw-r--r--sync/engine/sync_scheduler.h8
-rw-r--r--sync/engine/sync_scheduler_impl.cc18
-rw-r--r--sync/engine/sync_scheduler_impl.h5
-rw-r--r--sync/engine/sync_scheduler_unittest.cc9
-rw-r--r--sync/engine/syncer.cc13
-rw-r--r--sync/engine/syncer.h10
-rw-r--r--sync/engine/syncer_proto_util_unittest.cc8
-rw-r--r--sync/engine/syncer_unittest.cc7
-rw-r--r--sync/internal_api/http_bridge.cc47
-rw-r--r--sync/internal_api/http_bridge_unittest.cc16
-rw-r--r--sync/internal_api/internal_components_factory_impl.cc11
-rw-r--r--sync/internal_api/public/base/cancelation_observer.cc13
-rw-r--r--sync/internal_api/public/base/cancelation_observer.h25
-rw-r--r--sync/internal_api/public/base/cancelation_signal.cc52
-rw-r--r--sync/internal_api/public/base/cancelation_signal.h72
-rw-r--r--sync/internal_api/public/base/cancelation_signal_unittest.cc169
-rw-r--r--sync/internal_api/public/http_bridge.h32
-rw-r--r--sync/internal_api/public/http_post_provider_factory.h8
-rw-r--r--sync/internal_api/public/internal_components_factory.h4
-rw-r--r--sync/internal_api/public/internal_components_factory_impl.h3
-rw-r--r--sync/internal_api/public/sync_manager.h18
-rw-r--r--sync/internal_api/public/test/fake_sync_manager.h4
-rw-r--r--sync/internal_api/public/test/test_internal_components_factory.h3
-rw-r--r--sync/internal_api/sync_manager_impl.cc16
-rw-r--r--sync/internal_api/sync_manager_impl.h4
-rw-r--r--sync/internal_api/sync_manager_impl_unittest.cc10
-rw-r--r--sync/internal_api/syncapi_server_connection_manager.cc14
-rw-r--r--sync/internal_api/syncapi_server_connection_manager.h6
-rw-r--r--sync/internal_api/syncapi_server_connection_manager_unittest.cc35
-rw-r--r--sync/internal_api/test/fake_sync_manager.cc6
-rw-r--r--sync/internal_api/test/test_internal_components_factory.cc4
-rw-r--r--sync/sync_internal_api.gypi6
-rw-r--r--sync/sync_tests.gypi1
-rw-r--r--sync/test/engine/fake_sync_scheduler.cc2
-rw-r--r--sync/test/engine/fake_sync_scheduler.h2
-rw-r--r--sync/test/engine/mock_connection_manager.cc5
-rw-r--r--sync/test/engine/mock_connection_manager.h4
-rw-r--r--sync/test/engine/syncer_command_test.h5
-rw-r--r--sync/tools/sync_client.cc11
41 files changed, 579 insertions, 140 deletions
diff --git a/sync/engine/net/server_connection_manager.cc b/sync/engine/net/server_connection_manager.cc
index 0076543..99e62b0 100644
--- a/sync/engine/net/server_connection_manager.cc
+++ b/sync/engine/net/server_connection_manager.cc
@@ -16,6 +16,7 @@
#include "net/http/http_status_code.h"
#include "sync/engine/net/url_translator.h"
#include "sync/engine/syncer.h"
+#include "sync/internal_api/public/base/cancelation_signal.h"
#include "sync/protocol/sync.pb.h"
#include "sync/syncable/directory.h"
#include "url/gurl.h"
@@ -177,7 +178,8 @@ ServerConnectionManager::ServerConnectionManager(
const string& server,
int port,
bool use_ssl,
- bool use_oauth2_token)
+ bool use_oauth2_token,
+ CancelationSignal* cancelation_signal)
: sync_server_(server),
sync_server_port_(port),
use_ssl_(use_ssl),
@@ -185,10 +187,22 @@ ServerConnectionManager::ServerConnectionManager(
proto_sync_path_(kSyncServerSyncPath),
server_status_(HttpResponse::NONE),
terminated_(false),
- active_connection_(NULL) {
+ active_connection_(NULL),
+ cancelation_signal_(cancelation_signal),
+ signal_handler_registered_(false) {
+ signal_handler_registered_ = cancelation_signal_->TryRegisterHandler(this);
+ if (!signal_handler_registered_) {
+ // Calling a virtual function from a constructor. We can get away with it
+ // here because ServerConnectionManager::OnSignalReceived() is the function
+ // we want to call.
+ OnSignalReceived();
+ }
}
ServerConnectionManager::~ServerConnectionManager() {
+ if (signal_handler_registered_) {
+ cancelation_signal_->UnregisterHandler(this);
+ }
}
ServerConnectionManager::Connection*
@@ -348,7 +362,7 @@ ServerConnectionManager::Connection* ServerConnectionManager::MakeConnection()
return NULL; // For testing.
}
-void ServerConnectionManager::TerminateAllIO() {
+void ServerConnectionManager::OnSignalReceived() {
base::AutoLock lock(terminate_connection_lock_);
terminated_ = true;
if (active_connection_)
diff --git a/sync/engine/net/server_connection_manager.h b/sync/engine/net/server_connection_manager.h
index f9c4a54..7496a53 100644
--- a/sync/engine/net/server_connection_manager.h
+++ b/sync/engine/net/server_connection_manager.h
@@ -16,6 +16,7 @@
#include "base/threading/non_thread_safe.h"
#include "base/threading/thread_checker.h"
#include "sync/base/sync_export.h"
+#include "sync/internal_api/public/base/cancelation_observer.h"
#include "sync/syncable/syncable_id.h"
namespace sync_pb {
@@ -24,6 +25,8 @@ class ClientToServerMessage;
namespace syncer {
+class CancelationSignal;
+
namespace syncable {
class Directory;
}
@@ -125,7 +128,7 @@ class SYNC_EXPORT_PRIVATE ScopedServerStatusWatcher
// Use this class to interact with the sync server.
// The ServerConnectionManager currently supports POSTing protocol buffers.
//
-class SYNC_EXPORT_PRIVATE ServerConnectionManager {
+class SYNC_EXPORT_PRIVATE ServerConnectionManager : public CancelationObserver {
public:
// buffer_in - will be POSTed
// buffer_out - string will be overwritten with response
@@ -183,7 +186,8 @@ class SYNC_EXPORT_PRIVATE ServerConnectionManager {
ServerConnectionManager(const std::string& server,
int port,
bool use_ssl,
- bool use_oauth2_token);
+ bool use_oauth2_token,
+ CancelationSignal* cancelation_signal);
virtual ~ServerConnectionManager();
@@ -219,7 +223,7 @@ class SYNC_EXPORT_PRIVATE ServerConnectionManager {
// We expect this to get called on a different thread than the valid
// ThreadChecker thread, as we want to kill any pending http traffic without
// having to wait for the request to complete.
- virtual void TerminateAllIO();
+ virtual void OnSignalReceived() OVERRIDE FINAL;
void set_client_id(const std::string& client_id) {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -342,6 +346,9 @@ class SYNC_EXPORT_PRIVATE ServerConnectionManager {
void NotifyStatusChanged();
+ CancelationSignal* const cancelation_signal_;
+ bool signal_handler_registered_;
+
DISALLOW_COPY_AND_ASSIGN(ServerConnectionManager);
};
diff --git a/sync/engine/sync_scheduler.h b/sync/engine/sync_scheduler.h
index 923c7be..b31af82 100644
--- a/sync/engine/sync_scheduler.h
+++ b/sync/engine/sync_scheduler.h
@@ -75,11 +75,9 @@ class SYNC_EXPORT_PRIVATE SyncScheduler
// Note: must already be in CONFIGURATION mode.
virtual bool ScheduleConfiguration(const ConfigurationParams& params) = 0;
- // Request that any running syncer task stop as soon as possible and
- // cancel all scheduled tasks. This function can be called from any thread,
- // and should in fact be called from a thread that isn't the sync loop to
- // allow preempting ongoing sync cycles.
- virtual void RequestStop() = 0;
+ // Request that the syncer avoid starting any new tasks and prepare for
+ // shutdown.
+ virtual void Stop() = 0;
// The meat and potatoes. All three of the following methods will post a
// delayed task to attempt the actual nudge (see ScheduleNudgeImpl).
diff --git a/sync/engine/sync_scheduler_impl.cc b/sync/engine/sync_scheduler_impl.cc
index 93eb0fb..78010d7 100644
--- a/sync/engine/sync_scheduler_impl.cc
+++ b/sync/engine/sync_scheduler_impl.cc
@@ -174,7 +174,7 @@ SyncSchedulerImpl::SyncSchedulerImpl(const std::string& name,
SyncSchedulerImpl::~SyncSchedulerImpl() {
DCHECK(CalledOnValidThread());
- StopImpl();
+ Stop();
}
void SyncSchedulerImpl::OnCredentialsUpdated() {
@@ -643,17 +643,9 @@ void SyncSchedulerImpl::RestartWaiting() {
}
}
-void SyncSchedulerImpl::RequestStop() {
- syncer_->RequestEarlyExit(); // Safe to call from any thread.
- DCHECK(weak_handle_this_.IsInitialized());
- SDVLOG(3) << "Posting StopImpl";
- weak_handle_this_.Call(FROM_HERE,
- &SyncSchedulerImpl::StopImpl);
-}
-
-void SyncSchedulerImpl::StopImpl() {
+void SyncSchedulerImpl::Stop() {
DCHECK(CalledOnValidThread());
- SDVLOG(2) << "StopImpl called";
+ SDVLOG(2) << "Stop called";
// Kill any in-flight method calls.
weak_ptr_factory_.InvalidateWeakPtrs();
@@ -861,7 +853,7 @@ void SyncSchedulerImpl::OnReceivedClientInvalidationHintBufferSize(int size) {
void SyncSchedulerImpl::OnShouldStopSyncingPermanently() {
DCHECK(CalledOnValidThread());
SDVLOG(2) << "OnShouldStopSyncingPermanently";
- syncer_->RequestEarlyExit(); // Thread-safe.
+ Stop();
Notify(SyncEngineEvent::STOP_SYNCING_PERMANENTLY);
}
@@ -880,7 +872,7 @@ void SyncSchedulerImpl::OnSyncProtocolError(
if (ShouldRequestEarlyExit(
snapshot.model_neutral_state().sync_protocol_error)) {
SDVLOG(2) << "Sync Scheduler requesting early exit.";
- syncer_->RequestEarlyExit(); // Thread-safe.
+ Stop();
}
if (IsActionableError(snapshot.model_neutral_state().sync_protocol_error))
OnActionableError(snapshot);
diff --git a/sync/engine/sync_scheduler_impl.h b/sync/engine/sync_scheduler_impl.h
index b8dcce9..8492463 100644
--- a/sync/engine/sync_scheduler_impl.h
+++ b/sync/engine/sync_scheduler_impl.h
@@ -54,7 +54,7 @@ class SYNC_EXPORT_PRIVATE SyncSchedulerImpl
virtual void Start(Mode mode) OVERRIDE;
virtual bool ScheduleConfiguration(
const ConfigurationParams& params) OVERRIDE;
- virtual void RequestStop() OVERRIDE;
+ virtual void Stop() OVERRIDE;
virtual void ScheduleLocalNudge(
const base::TimeDelta& desired_delay,
ModelTypeSet types,
@@ -181,9 +181,6 @@ class SYNC_EXPORT_PRIVATE SyncSchedulerImpl
// Determines if we're allowed to contact the server right now.
bool CanRunNudgeJobNow(JobPriority priority);
- // 'Impl' here refers to real implementation of public functions.
- void StopImpl();
-
// If the scheduler's current state supports it, this will create a job based
// on the passed in parameters and coalesce it with any other pending jobs,
// then post a delayed task to run it. It may also choose to drop the job or
diff --git a/sync/engine/sync_scheduler_unittest.cc b/sync/engine/sync_scheduler_unittest.cc
index e0ea9a8..a5a00e9 100644
--- a/sync/engine/sync_scheduler_unittest.cc
+++ b/sync/engine/sync_scheduler_unittest.cc
@@ -11,6 +11,7 @@
#include "sync/engine/backoff_delay_provider.h"
#include "sync/engine/sync_scheduler_impl.h"
#include "sync/engine/syncer.h"
+#include "sync/internal_api/public/base/cancelation_signal.h"
#include "sync/internal_api/public/base/model_type_test_util.h"
#include "sync/notifier/invalidation_util.h"
#include "sync/notifier/object_id_invalidation_map.h"
@@ -41,6 +42,7 @@ using sync_pb::GetUpdatesCallerInfo;
class MockSyncer : public Syncer {
public:
+ MockSyncer();
MOCK_METHOD3(NormalSyncShare, bool(ModelTypeSet,
const sessions::NudgeTracker&,
sessions::SyncSession*));
@@ -51,6 +53,9 @@ class MockSyncer : public Syncer {
MOCK_METHOD2(PollSyncShare, bool(ModelTypeSet, sessions::SyncSession*));
};
+MockSyncer::MockSyncer()
+ : Syncer(NULL) {}
+
typedef std::vector<TimeTicks> SyncShareTimes;
void QuitLoopNow() {
@@ -126,7 +131,8 @@ class SyncSchedulerTest : public testing::Test {
workers.push_back(it->get());
}
- connection_.reset(new MockConnectionManager(directory()));
+ connection_.reset(new MockConnectionManager(directory(),
+ &cancelation_signal_));
connection_->SetServerReachable();
context_.reset(new SyncSessionContext(
connection_.get(), directory(), workers,
@@ -218,6 +224,7 @@ class SyncSchedulerTest : public testing::Test {
base::MessageLoop loop_;
base::WeakPtrFactory<SyncSchedulerTest> weak_ptr_factory_;
TestDirectorySetterUpper dir_maker_;
+ CancelationSignal cancelation_signal_;
scoped_ptr<MockConnectionManager> connection_;
scoped_ptr<SyncSessionContext> context_;
scoped_ptr<SyncSchedulerImpl> scheduler_;
diff --git a/sync/engine/syncer.cc b/sync/engine/syncer.cc
index 3d66ca3..cc379d9 100644
--- a/sync/engine/syncer.cc
+++ b/sync/engine/syncer.cc
@@ -19,6 +19,7 @@
#include "sync/engine/net/server_connection_manager.h"
#include "sync/engine/process_commit_response_command.h"
#include "sync/engine/syncer_types.h"
+#include "sync/internal_api/public/base/cancelation_signal.h"
#include "sync/internal_api/public/base/unique_position.h"
#include "sync/internal_api/public/util/syncer_error.h"
#include "sync/sessions/nudge_tracker.h"
@@ -43,20 +44,14 @@ using sessions::StatusController;
using sessions::SyncSession;
using sessions::NudgeTracker;
-Syncer::Syncer()
- : early_exit_requested_(false) {
+Syncer::Syncer(syncer::CancelationSignal* cancelation_signal)
+ : cancelation_signal_(cancelation_signal) {
}
Syncer::~Syncer() {}
bool Syncer::ExitRequested() {
- base::AutoLock lock(early_exit_requested_lock_);
- return early_exit_requested_;
-}
-
-void Syncer::RequestEarlyExit() {
- base::AutoLock lock(early_exit_requested_lock_);
- early_exit_requested_ = true;
+ return cancelation_signal_->IsSignalled();
}
bool Syncer::NormalSyncShare(ModelTypeSet request_types,
diff --git a/sync/engine/syncer.h b/sync/engine/syncer.h
index e1e5eac..132f6ef 100644
--- a/sync/engine/syncer.h
+++ b/sync/engine/syncer.h
@@ -21,6 +21,8 @@
namespace syncer {
+class CancelationSignal;
+
// A Syncer provides a control interface for driving the individual steps
// of the sync cycle. Each cycle (hopefully) moves the client into closer
// synchronization with the server. The individual steps are modeled
@@ -35,13 +37,10 @@ class SYNC_EXPORT_PRIVATE Syncer {
public:
typedef std::vector<int64> UnsyncedMetaHandles;
- Syncer();
+ Syncer(CancelationSignal* cancelation_signal);
virtual ~Syncer();
- // Called by other threads to tell the syncer to stop what it's doing
- // and return early from SyncShare, if possible.
bool ExitRequested();
- void RequestEarlyExit();
// Fetches and applies updates, resolves conflicts and commits local changes
// for |request_types| as necessary until client and server states are in
@@ -79,8 +78,7 @@ class SYNC_EXPORT_PRIVATE Syncer {
sessions::SyncSession* session,
sync_pb::GetUpdatesCallerInfo::GetUpdatesSource source);
- bool early_exit_requested_;
- base::Lock early_exit_requested_lock_;
+ syncer::CancelationSignal* const cancelation_signal_;
friend class SyncerTest;
FRIEND_TEST_ALL_PREFIXES(SyncerTest, NameClashWithResolver);
diff --git a/sync/engine/syncer_proto_util_unittest.cc b/sync/engine/syncer_proto_util_unittest.cc
index c288132..ff37e56 100644
--- a/sync/engine/syncer_proto_util_unittest.cc
+++ b/sync/engine/syncer_proto_util_unittest.cc
@@ -10,6 +10,7 @@
#include "base/compiler_specific.h"
#include "base/message_loop/message_loop.h"
#include "base/time/time.h"
+#include "sync/internal_api/public/base/cancelation_signal.h"
#include "sync/internal_api/public/base/model_type_test_util.h"
#include "sync/protocol/bookmark_specifics.pb.h"
#include "sync/protocol/password_specifics.pb.h"
@@ -254,8 +255,8 @@ TEST_F(SyncerProtoUtilTest, AddRequestBirthday) {
class DummyConnectionManager : public ServerConnectionManager {
public:
- DummyConnectionManager()
- : ServerConnectionManager("unused", 0, false, false),
+ DummyConnectionManager(CancelationSignal* signal)
+ : ServerConnectionManager("unused", 0, false, false, signal),
send_error_(false),
access_denied_(false) {}
@@ -290,7 +291,8 @@ class DummyConnectionManager : public ServerConnectionManager {
};
TEST_F(SyncerProtoUtilTest, PostAndProcessHeaders) {
- DummyConnectionManager dcm;
+ CancelationSignal signal;
+ DummyConnectionManager dcm(&signal);
ClientToServerMessage msg;
SyncerProtoUtil::SetProtocolVersion(&msg);
msg.set_share("required");
diff --git a/sync/engine/syncer_unittest.cc b/sync/engine/syncer_unittest.cc
index 5e2bbf5..b1a9646 100644
--- a/sync/engine/syncer_unittest.cc
+++ b/sync/engine/syncer_unittest.cc
@@ -30,6 +30,7 @@
#include "sync/engine/syncer.h"
#include "sync/engine/syncer_proto_util.h"
#include "sync/engine/traffic_recorder.h"
+#include "sync/internal_api/public/base/cancelation_signal.h"
#include "sync/internal_api/public/base/model_type.h"
#include "sync/internal_api/public/engine/model_safe_worker.h"
#include "sync/protocol/bookmark_specifics.pb.h"
@@ -204,7 +205,8 @@ class SyncerTest : public testing::Test,
virtual void SetUp() {
dir_maker_.SetUp();
- mock_server_.reset(new MockConnectionManager(directory()));
+ mock_server_.reset(new MockConnectionManager(directory(),
+ &cancelation_signal_));
EnableDatatype(BOOKMARKS);
EnableDatatype(NIGORI);
EnableDatatype(PREFERENCES);
@@ -228,7 +230,7 @@ class SyncerTest : public testing::Test,
false, // force enable pre-commit GU avoidance experiment
"fake_invalidator_client_id"));
context_->set_routing_info(routing_info);
- syncer_ = new Syncer();
+ syncer_ = new Syncer(&cancelation_signal_);
syncable::ReadTransaction trans(FROM_HERE, directory());
syncable::Directory::Metahandles children;
@@ -504,6 +506,7 @@ class SyncerTest : public testing::Test,
FakeEncryptor encryptor_;
scoped_refptr<ExtensionsActivity> extensions_activity_;
scoped_ptr<MockConnectionManager> mock_server_;
+ CancelationSignal cancelation_signal_;
Syncer* syncer_;
diff --git a/sync/internal_api/http_bridge.cc b/sync/internal_api/http_bridge.cc
index 0b3697f..48305eb 100644
--- a/sync/internal_api/http_bridge.cc
+++ b/sync/internal_api/http_bridge.cc
@@ -19,6 +19,7 @@
#include "net/url_request/url_fetcher.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_status.h"
+#include "sync/internal_api/public/base/cancelation_signal.h"
namespace syncer {
@@ -58,20 +59,45 @@ HttpBridge::RequestContextGetter::GetNetworkTaskRunner() const {
HttpBridgeFactory::HttpBridgeFactory(
net::URLRequestContextGetter* baseline_context_getter,
- const std::string& user_agent,
- const NetworkTimeUpdateCallback& network_time_update_callback)
- : request_context_getter_(
- new HttpBridge::RequestContextGetter(
- baseline_context_getter, user_agent)),
- network_time_update_callback_(network_time_update_callback) {
+ const NetworkTimeUpdateCallback& network_time_update_callback,
+ CancelationSignal* cancelation_signal)
+ : baseline_request_context_getter_(baseline_context_getter),
+ network_time_update_callback_(network_time_update_callback),
+ cancelation_signal_(cancelation_signal) {
+ // Registration should never fail. This should happen on the UI thread during
+ // init. It would be impossible for a shutdown to have been requested at this
+ // point.
+ bool result = cancelation_signal_->TryRegisterHandler(this);
+ DCHECK(result);
}
HttpBridgeFactory::~HttpBridgeFactory() {
+ cancelation_signal_->UnregisterHandler(this);
+}
+
+void HttpBridgeFactory::Init(const std::string& user_agent) {
+ base::AutoLock lock(context_getter_lock_);
+
+ if (!baseline_request_context_getter_.get()) {
+ // Uh oh. We've been aborted before we finsihed initializing.
+ // There's no point in initializating further; let's just return
+ // right away.
+ }
+
+ request_context_getter_ =
+ new HttpBridge::RequestContextGetter(
+ baseline_request_context_getter_, user_agent);
}
HttpPostProviderInterface* HttpBridgeFactory::Create() {
base::AutoLock lock(context_getter_lock_);
+
+ // If we've been asked to shut down (something which may happen asynchronously
+ // and at pretty much any time), then we won't have a request_context_getter_.
+ // Some external mechanism must ensure that this function is not called after
+ // we've been asked to shut down.
CHECK(request_context_getter_.get());
+
HttpBridge* http = new HttpBridge(request_context_getter_.get(),
network_time_update_callback_);
http->AddRef();
@@ -82,10 +108,13 @@ void HttpBridgeFactory::Destroy(HttpPostProviderInterface* http) {
static_cast<HttpBridge*>(http)->Release();
}
-void HttpBridgeFactory::Shutdown() {
+void HttpBridgeFactory::OnSignalReceived() {
base::AutoLock lock(context_getter_lock_);
- // Release |request_context_getter_| as soon as possible so that it is
- // destroyed in the right order on its network task runner.
+ // Release |baseline_request_context_getter_| as soon as possible so that it
+ // is destroyed in the right order on its network task runner. The
+ // |request_context_getter_| has a reference to the baseline, so we must
+ // drop our reference to it, too.
+ baseline_request_context_getter_ = NULL;
request_context_getter_ = NULL;
}
diff --git a/sync/internal_api/http_bridge_unittest.cc b/sync/internal_api/http_bridge_unittest.cc
index 9cb37df..e1dc6de 100644
--- a/sync/internal_api/http_bridge_unittest.cc
+++ b/sync/internal_api/http_bridge_unittest.cc
@@ -9,6 +9,7 @@
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request_test_util.h"
+#include "sync/internal_api/public/base/cancelation_signal.h"
#include "sync/internal_api/public/http_bridge.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -407,14 +408,16 @@ TEST_F(SyncHttpBridgeTest, AbortAndReleaseBeforeFetchComplete) {
void HttpBridgeRunOnSyncThread(
net::URLRequestContextGetter* baseline_context_getter,
+ CancelationSignal* factory_cancelation_signal,
syncer::HttpPostProviderFactory** bridge_factory_out,
syncer::HttpPostProviderInterface** bridge_out,
base::WaitableEvent* signal_when_created,
base::WaitableEvent* wait_for_shutdown) {
- scoped_ptr<syncer::HttpPostProviderFactory> bridge_factory(
+ scoped_ptr<syncer::HttpBridgeFactory> bridge_factory(
new syncer::HttpBridgeFactory(baseline_context_getter,
- "test",
- NetworkTimeUpdateCallback()));
+ NetworkTimeUpdateCallback(),
+ factory_cancelation_signal));
+ bridge_factory->Init("test");
*bridge_factory_out = bridge_factory.get();
HttpPostProviderInterface* bridge = bridge_factory->Create();
@@ -447,18 +450,21 @@ TEST_F(SyncHttpBridgeTest, RequestContextGetterReleaseOrder) {
base::WaitableEvent signal_when_created(false, false);
base::WaitableEvent wait_for_shutdown(false, false);
+ CancelationSignal release_request_context_signal;
+
// Create bridge factory and factory on sync thread and wait for the creation
// to finish.
sync_thread.message_loop()->PostTask(FROM_HERE,
base::Bind(&HttpBridgeRunOnSyncThread,
base::Unretained(baseline_context_getter.get()),
- &factory, &bridge, &signal_when_created, &wait_for_shutdown));
+ &release_request_context_signal ,&factory, &bridge,
+ &signal_when_created, &wait_for_shutdown));
signal_when_created.Wait();
// Simulate sync shutdown by aborting bridge and shutting down factory on
// frontend.
bridge->Abort();
- factory->Shutdown();
+ release_request_context_signal.Signal();
// Wait for sync's RequestContextGetter to be cleared on IO thread and
// check for reference count.
diff --git a/sync/internal_api/internal_components_factory_impl.cc b/sync/internal_api/internal_components_factory_impl.cc
index d5fc102..6ccb143 100644
--- a/sync/internal_api/internal_components_factory_impl.cc
+++ b/sync/internal_api/internal_components_factory_impl.cc
@@ -21,15 +21,20 @@ InternalComponentsFactoryImpl::InternalComponentsFactoryImpl(
InternalComponentsFactoryImpl::~InternalComponentsFactoryImpl() { }
scoped_ptr<SyncScheduler> InternalComponentsFactoryImpl::BuildScheduler(
- const std::string& name, sessions::SyncSessionContext* context) {
+ const std::string& name,
+ sessions::SyncSessionContext* context,
+ CancelationSignal* cancelation_signal) {
scoped_ptr<BackoffDelayProvider> delay(BackoffDelayProvider::FromDefaults());
if (switches_.backoff_override == BACKOFF_SHORT_INITIAL_RETRY_OVERRIDE)
delay.reset(BackoffDelayProvider::WithShortInitialRetryOverride());
- return scoped_ptr<SyncScheduler>(
- new SyncSchedulerImpl(name, delay.release(), context, new Syncer()));
+ return scoped_ptr<SyncScheduler>(new SyncSchedulerImpl(
+ name,
+ delay.release(),
+ context,
+ new Syncer(cancelation_signal)));
}
scoped_ptr<sessions::SyncSessionContext>
diff --git a/sync/internal_api/public/base/cancelation_observer.cc b/sync/internal_api/public/base/cancelation_observer.cc
new file mode 100644
index 0000000..f50b6a3
--- /dev/null
+++ b/sync/internal_api/public/base/cancelation_observer.cc
@@ -0,0 +1,13 @@
+// Copyright 2013 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.
+
+#include "sync/internal_api/public/base/cancelation_observer.h"
+
+namespace syncer {
+
+CancelationObserver::CancelationObserver() {}
+
+CancelationObserver::~CancelationObserver() {}
+
+} // namespace syncer
diff --git a/sync/internal_api/public/base/cancelation_observer.h b/sync/internal_api/public/base/cancelation_observer.h
new file mode 100644
index 0000000..7e67787
--- /dev/null
+++ b/sync/internal_api/public/base/cancelation_observer.h
@@ -0,0 +1,25 @@
+// Copyright 2013 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 SYNC_INTERNAL_API_PUBLIC_BASE_CANCELATION_OBSERVER_H_
+#define SYNC_INTERNAL_API_PUBLIC_BASE_CANCELATION_OBSERVER_H_
+
+#include "sync/base/sync_export.h"
+
+namespace syncer {
+
+// Interface for classes that handle signals from the CancelationSignal.
+class SYNC_EXPORT CancelationObserver {
+ public:
+ CancelationObserver();
+ virtual ~CancelationObserver() = 0;
+
+ // This may be called from a foreign thread while the CancelationSignal's lock
+ // is held. The callee should avoid performing slow or blocking operations.
+ virtual void OnSignalReceived() = 0;
+};
+
+} // namespace syncer
+
+#endif // SYNC_INTERNAL_API_PUBLIC_BASE_CANCELATION_OBSERVER_H_
diff --git a/sync/internal_api/public/base/cancelation_signal.cc b/sync/internal_api/public/base/cancelation_signal.cc
new file mode 100644
index 0000000..94a479b
--- /dev/null
+++ b/sync/internal_api/public/base/cancelation_signal.cc
@@ -0,0 +1,52 @@
+// Copyright 2013 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.
+
+#include "sync/internal_api/public/base/cancelation_signal.h"
+
+#include "base/logging.h"
+#include "sync/internal_api/public/base/cancelation_observer.h"
+
+namespace syncer {
+
+CancelationSignal::CancelationSignal()
+ : signalled_(false),
+ handler_(NULL) { }
+
+CancelationSignal::~CancelationSignal() {
+ DCHECK(!handler_);
+}
+
+bool CancelationSignal::TryRegisterHandler(CancelationObserver* handler) {
+ base::AutoLock lock(signal_lock_);
+ DCHECK(!handler_);
+
+ if (signalled_)
+ return false;
+
+ handler_ = handler;
+ return true;
+}
+
+void CancelationSignal::UnregisterHandler(CancelationObserver* handler) {
+ base::AutoLock lock(signal_lock_);
+ DCHECK_EQ(handler_, handler);
+ handler_ = NULL;
+}
+
+bool CancelationSignal::IsSignalled() {
+ base::AutoLock lock(signal_lock_);
+ return signalled_;
+}
+
+void CancelationSignal::Signal() {
+ base::AutoLock lock(signal_lock_);
+ DCHECK(!signalled_);
+
+ signalled_ = true;
+ if (handler_) {
+ handler_->OnSignalReceived();
+ }
+}
+
+} // namespace syncer
diff --git a/sync/internal_api/public/base/cancelation_signal.h b/sync/internal_api/public/base/cancelation_signal.h
new file mode 100644
index 0000000..a074b62
--- /dev/null
+++ b/sync/internal_api/public/base/cancelation_signal.h
@@ -0,0 +1,72 @@
+// Copyright 2013 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 SYNC_INTERNAL_API_PUBLIC_BASE_CANCELATION_SIGNAL_H_
+#define SYNC_INTERNAL_API_PUBLIC_BASE_CANCELATION_SIGNAL_H_
+
+#include "base/synchronization/lock.h"
+#include "sync/base/sync_export.h"
+
+namespace syncer {
+
+class CancelationObserver;
+
+// This class is used to allow one thread to request that another abort and
+// return early.
+//
+// The signalling thread owns this class and my call Signal() at any time.
+// After that call, this class' IsSignalled() will always return true. The
+// intended use case is that the task intending to support early exit will
+// periodically check the value of IsSignalled() to see if it should return
+// early.
+//
+// The receiving task may also choose to register an CancelationObserver whose
+// OnSignalReceived() method will be executed on the signaller's thread when
+// Signal() is called. This may be used for sending an early Signal() to a
+// WaitableEvent. The registration of the handler is necessarily racy. If
+// Signal() is executes before TryRegisterHandler(), TryRegisterHandler() will
+// not perform any registration and return false. That function's caller must
+// handle this case.
+//
+// This class supports only one handler, though it could easily support multiple
+// observers if we found a use case for such a feature.
+class SYNC_EXPORT_PRIVATE CancelationSignal {
+ public:
+ CancelationSignal();
+ ~CancelationSignal();
+
+ // Tries to register a handler to be invoked when Signal() is called.
+ //
+ // If Signal() has already been called, returns false without registering
+ // the handler. Returns true when the registration is successful.
+ //
+ // If the registration was successful, the handler must be unregistered with
+ // UnregisterHandler before this CancelationSignal is destroyed.
+ bool TryRegisterHandler(CancelationObserver* handler);
+
+ // Unregisters the abort handler.
+ void UnregisterHandler(CancelationObserver* handler);
+
+ // Returns true if Signal() has been called.
+ bool IsSignalled();
+
+ // Sets the stop_requested_ flag and calls the OnSignalReceived() method of
+ // the registered handler, if there is one registered at the time.
+ // SignalReceived() will be called with the |signal_lock_| held.
+ void Signal();
+
+ private:
+ // Protects all members of this class.
+ base::Lock signal_lock_;
+
+ // True if Signal() has been invoked.
+ bool signalled_;
+
+ // The registered abort handler. May be NULL.
+ CancelationObserver* handler_;
+};
+
+} // namespace syncer
+
+#endif // SYNC_INTERNAL_API_PUBLIC_BASE_CANCELATION_SIGNAL_H_
diff --git a/sync/internal_api/public/base/cancelation_signal_unittest.cc b/sync/internal_api/public/base/cancelation_signal_unittest.cc
new file mode 100644
index 0000000..613e756
--- /dev/null
+++ b/sync/internal_api/public/base/cancelation_signal_unittest.cc
@@ -0,0 +1,169 @@
+// Copyright 2013 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.
+
+#include "sync/internal_api/public/base/cancelation_signal.h"
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "sync/internal_api/public/base/cancelation_observer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace syncer {
+
+class BlockingTask : public CancelationObserver {
+ public:
+ BlockingTask(CancelationSignal* cancel_signal);
+ virtual ~BlockingTask();
+
+ // Starts the |exec_thread_| and uses it to execute DoRun().
+ void RunAsync(base::WaitableEvent* task_done_signal);
+
+ // Blocks until canceled. Signals |task_done_signal| when finished.
+ void Run(base::WaitableEvent* task_done_signal);
+
+ // Implementation of CancelationObserver.
+ // Wakes up the thread blocked in Run().
+ virtual void OnSignalReceived() OVERRIDE;
+
+ // Checks if we ever did successfully start waiting for |event_|. Be careful
+ // with this. The flag itself is thread-unsafe, and the event that flips it
+ // is racy.
+ bool WasStarted();
+
+ private:
+ base::WaitableEvent event_;
+ base::Thread exec_thread_;
+ CancelationSignal* cancel_signal_;
+ bool was_started_;
+};
+
+BlockingTask::BlockingTask(CancelationSignal* cancel_signal)
+ : event_(true, false),
+ exec_thread_("BlockingTaskBackgroundThread"),
+ cancel_signal_(cancel_signal),
+ was_started_(false) { }
+
+BlockingTask::~BlockingTask() {}
+
+void BlockingTask::RunAsync(base::WaitableEvent* task_done_signal) {
+ exec_thread_.Start();
+ exec_thread_.message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&BlockingTask::Run,
+ base::Unretained(this),
+ base::Unretained(task_done_signal)));
+}
+
+void BlockingTask::Run(base::WaitableEvent* task_done_signal) {
+ if (cancel_signal_->TryRegisterHandler(this)) {
+ DCHECK(!event_.IsSignaled());
+ was_started_ = true;
+ event_.Wait();
+ }
+ task_done_signal->Signal();
+}
+
+void BlockingTask::OnSignalReceived() {
+ event_.Signal();
+}
+
+bool BlockingTask::WasStarted() {
+ return was_started_;
+}
+
+class CancelationSignalTest : public ::testing::Test {
+ public:
+ CancelationSignalTest();
+ virtual ~CancelationSignalTest();
+
+ // Starts the blocking task on a background thread.
+ void StartBlockingTask();
+
+ // Cancels the blocking task.
+ void CancelBlocking();
+
+ // Verifies that the background task is not running. This could be beacause
+ // it was canceled early or because it was canceled after it was started.
+ //
+ // This method may block for a brief period of time while waiting for the
+ // background thread to make progress.
+ bool VerifyTaskDone();
+
+ // Verifies that the background task was canceled early.
+ //
+ // This method may block for a brief period of time while waiting for the
+ // background thread to make progress.
+ bool VerifyTaskNotStarted();
+
+ private:
+ base::MessageLoop main_loop_;
+
+ CancelationSignal signal_;
+ base::WaitableEvent task_done_event_;
+ BlockingTask blocking_task_;
+};
+
+CancelationSignalTest::CancelationSignalTest()
+ : task_done_event_(false, false), blocking_task_(&signal_) {}
+
+CancelationSignalTest::~CancelationSignalTest() {}
+
+void CancelationSignalTest::StartBlockingTask() {
+ blocking_task_.RunAsync(&task_done_event_);
+}
+
+void CancelationSignalTest::CancelBlocking() {
+ signal_.Signal();
+}
+
+bool CancelationSignalTest::VerifyTaskDone() {
+ // Wait until BlockingTask::Run() has finished.
+ task_done_event_.Wait();
+ return true;
+}
+
+bool CancelationSignalTest::VerifyTaskNotStarted() {
+ // Wait until BlockingTask::Run() has finished.
+ task_done_event_.Wait();
+
+ // Verify the background thread never started blocking.
+ return !blocking_task_.WasStarted();
+}
+
+class FakeCancelationObserver : public CancelationObserver {
+ virtual void OnSignalReceived() OVERRIDE { }
+};
+
+TEST(CancelationSignalTest_SingleThread, CheckFlags) {
+ FakeCancelationObserver observer;
+ CancelationSignal signal;
+
+ EXPECT_FALSE(signal.IsSignalled());
+ signal.Signal();
+ EXPECT_TRUE(signal.IsSignalled());
+ EXPECT_FALSE(signal.TryRegisterHandler(&observer));
+}
+
+// Send the cancelation signal before the task is started. This will ensure
+// that the task will never be attempted.
+TEST_F(CancelationSignalTest, CancelEarly) {
+ CancelBlocking();
+ StartBlockingTask();
+ EXPECT_TRUE(VerifyTaskNotStarted());
+}
+
+// Send the cancelation signal after the request to start the task has been
+// posted. This is racy. The signal to stop may arrive before the signal to
+// run the task. If that happens, we end up with another instance of the
+// CancelEarly test defined earlier. If the signal requesting a stop arrives
+// after the task has been started, it should end up stopping the task.
+TEST_F(CancelationSignalTest, Cancel) {
+ StartBlockingTask();
+ CancelBlocking();
+ EXPECT_TRUE(VerifyTaskDone());
+}
+
+} // namespace syncer
diff --git a/sync/internal_api/public/http_bridge.h b/sync/internal_api/public/http_bridge.h
index cbee771..be49aa7 100644
--- a/sync/internal_api/public/http_bridge.h
+++ b/sync/internal_api/public/http_bridge.h
@@ -19,6 +19,7 @@
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
#include "sync/base/sync_export.h"
+#include "sync/internal_api/public/base/cancelation_observer.h"
#include "sync/internal_api/public/http_post_provider_factory.h"
#include "sync/internal_api/public/http_post_provider_interface.h"
#include "url/gurl.h"
@@ -37,6 +38,8 @@ class URLFetcher;
namespace syncer {
+class CancelationSignal;
+
// Callback for updating the network time.
// Params:
// const base::Time& network_time - the new network time.
@@ -229,31 +232,44 @@ class SYNC_EXPORT_PRIVATE HttpBridge
DISALLOW_COPY_AND_ASSIGN(HttpBridge);
};
-class SYNC_EXPORT HttpBridgeFactory : public HttpPostProviderFactory {
+class SYNC_EXPORT HttpBridgeFactory : public HttpPostProviderFactory,
+ public CancelationObserver {
public:
HttpBridgeFactory(
net::URLRequestContextGetter* baseline_context_getter,
- const std::string& user_agent,
- const NetworkTimeUpdateCallback& network_time_update_callback);
+ const NetworkTimeUpdateCallback& network_time_update_callback,
+ CancelationSignal* cancelation_signal);
virtual ~HttpBridgeFactory();
// HttpPostProviderFactory:
+ virtual void Init(const std::string& user_agent) OVERRIDE;
virtual HttpPostProviderInterface* Create() OVERRIDE;
virtual void Destroy(HttpPostProviderInterface* http) OVERRIDE;
- virtual void Shutdown() OVERRIDE;
+
+ // CancelationObserver implementation:
+ virtual void OnSignalReceived() OVERRIDE;
private:
- // Protects |request_context_getter_|.
+ // Protects |request_context_getter_| and |baseline_request_context_getter_|.
base::Lock context_getter_lock_;
+ // This request context is the starting point for the request_context_getter_
+ // that we eventually use to make requests. During shutdown we must drop all
+ // references to it before the ProfileSyncService's Shutdown() call is
+ // complete.
+ scoped_refptr<net::URLRequestContextGetter> baseline_request_context_getter_;
+
// This request context is built on top of the baseline context and shares
- // common components. It's mostly used on sync thread when creating
- // connection but is released as soon as possible during shutdown. Protected
- // by |context_getter_lock_|.
+ // common components. Takes a reference to the
+ // baseline_request_context_getter_. It's mostly used on sync thread when
+ // creating connection but is released as soon as possible during shutdown.
+ // Protected by |context_getter_lock_|.
scoped_refptr<HttpBridge::RequestContextGetter> request_context_getter_;
NetworkTimeUpdateCallback network_time_update_callback_;
+ CancelationSignal* const cancelation_signal_;
+
DISALLOW_COPY_AND_ASSIGN(HttpBridgeFactory);
};
diff --git a/sync/internal_api/public/http_post_provider_factory.h b/sync/internal_api/public/http_post_provider_factory.h
index 8e6b93e..9346651 100644
--- a/sync/internal_api/public/http_post_provider_factory.h
+++ b/sync/internal_api/public/http_post_provider_factory.h
@@ -5,6 +5,8 @@
#ifndef SYNC_INTERNAL_API_PUBLIC_HTTP_POST_PROVIDER_FACTORY_H_
#define SYNC_INTERNAL_API_PUBLIC_HTTP_POST_PROVIDER_FACTORY_H_
+#include <string>
+
#include "sync/base/sync_export.h"
namespace syncer {
@@ -19,6 +21,8 @@ class SYNC_EXPORT HttpPostProviderFactory {
public:
virtual ~HttpPostProviderFactory() {}
+ virtual void Init(const std::string& user_agent) = 0;
+
// Obtain a new HttpPostProviderInterface instance, owned by caller.
virtual HttpPostProviderInterface* Create() = 0;
@@ -28,10 +32,6 @@ class SYNC_EXPORT HttpPostProviderFactory {
// reference counted, which is useful if a particular implementation uses
// multiple threads to serve network requests.
virtual void Destroy(HttpPostProviderInterface* http) = 0;
-
- // Clean up when the factory is no longer needed. Create() must not be
- // called after Shutdown() is called. Can be called from any thread.
- virtual void Shutdown() = 0;
};
} // namespace syncer
diff --git a/sync/internal_api/public/internal_components_factory.h b/sync/internal_api/public/internal_components_factory.h
index 86509ec..616457d 100644
--- a/sync/internal_api/public/internal_components_factory.h
+++ b/sync/internal_api/public/internal_components_factory.h
@@ -21,6 +21,7 @@ namespace syncer {
class ExtensionsActivity;
class ServerConnectionManager;
class SyncEngineEventListener;
+class CancelationSignal;
class SyncScheduler;
class TrafficRecorder;
@@ -75,7 +76,8 @@ class SYNC_EXPORT InternalComponentsFactory {
virtual scoped_ptr<SyncScheduler> BuildScheduler(
const std::string& name,
- sessions::SyncSessionContext* context) = 0;
+ sessions::SyncSessionContext* context,
+ CancelationSignal* cancelation_signal) = 0;
virtual scoped_ptr<sessions::SyncSessionContext> BuildContext(
ServerConnectionManager* connection_manager,
diff --git a/sync/internal_api/public/internal_components_factory_impl.h b/sync/internal_api/public/internal_components_factory_impl.h
index 148dd07..7b5c697 100644
--- a/sync/internal_api/public/internal_components_factory_impl.h
+++ b/sync/internal_api/public/internal_components_factory_impl.h
@@ -21,7 +21,8 @@ class SYNC_EXPORT InternalComponentsFactoryImpl
virtual scoped_ptr<SyncScheduler> BuildScheduler(
const std::string& name,
- sessions::SyncSessionContext* context) OVERRIDE;
+ sessions::SyncSessionContext* context,
+ syncer::CancelationSignal* cancelation_signal) OVERRIDE;
virtual scoped_ptr<sessions::SyncSessionContext> BuildContext(
ServerConnectionManager* connection_manager,
diff --git a/sync/internal_api/public/sync_manager.h b/sync/internal_api/public/sync_manager.h
index 3f5316b..735e5ed 100644
--- a/sync/internal_api/public/sync_manager.h
+++ b/sync/internal_api/public/sync_manager.h
@@ -45,6 +45,7 @@ class JsEventHandler;
class SyncEncryptionHandler;
class SyncScheduler;
struct UserShare;
+class CancelationSignal;
namespace sessions {
class SyncSessionSnapshot;
@@ -299,6 +300,9 @@ class SYNC_EXPORT SyncManager : public syncer::InvalidationHandler {
// |keystore_encryption_enabled| determines whether we enable the keystore
// encryption functionality in the cryptographer/nigori.
// |report_unrecoverable_error_function| may be NULL.
+ // |cancelation_signal| carries shutdown requests across threads. This one
+ // will be used to cut short any network I/O and tell the syncer to exit
+ // early.
//
// TODO(akalin): Replace the |post_factory| parameter with a
// URLFetcher parameter.
@@ -320,7 +324,8 @@ class SYNC_EXPORT SyncManager : public syncer::InvalidationHandler {
Encryptor* encryptor,
scoped_ptr<UnrecoverableErrorHandler> unrecoverable_error_handler,
ReportUnrecoverableErrorFunction report_unrecoverable_error_function,
- bool use_oauth2_token) = 0;
+ bool use_oauth2_token,
+ CancelationSignal* cancelation_signal) = 0;
// Throw an unrecoverable error from a transaction (mostly used for
// testing).
@@ -392,17 +397,6 @@ class SYNC_EXPORT SyncManager : public syncer::InvalidationHandler {
// to the syncapi model.
virtual void SaveChanges() = 0;
- // Initiates shutdown of various components in the sync engine. Must be
- // called from the main thread to allow preempting ongoing tasks on the sync
- // loop (that may be blocked on I/O). The semantics of |callback| are the
- // same as with StartConfigurationMode. If provided and a scheduler / sync
- // loop exists, it will be invoked from the sync loop by the scheduler to
- // notify that all work has been flushed + cancelled, and it is idle.
- // If no scheduler exists, the callback is run immediately (from the loop
- // this was created on, which is the sync loop), as sync is effectively
- // stopped.
- virtual void StopSyncingForShutdown() = 0;
-
// Issue a final SaveChanges, and close sqlite handles.
virtual void ShutdownOnSyncThread() = 0;
diff --git a/sync/internal_api/public/test/fake_sync_manager.h b/sync/internal_api/public/test/fake_sync_manager.h
index be06ea5..300921c 100644
--- a/sync/internal_api/public/test/fake_sync_manager.h
+++ b/sync/internal_api/public/test/fake_sync_manager.h
@@ -92,7 +92,8 @@ class FakeSyncManager : public SyncManager {
Encryptor* encryptor,
scoped_ptr<UnrecoverableErrorHandler> unrecoverable_error_handler,
ReportUnrecoverableErrorFunction report_unrecoverable_error_function,
- bool use_oauth2_token) OVERRIDE;
+ bool use_oauth2_token,
+ CancelationSignal* cancelation_signal) OVERRIDE;
virtual void ThrowUnrecoverableError() OVERRIDE;
virtual ModelTypeSet InitialSyncEndedTypes() OVERRIDE;
virtual ModelTypeSet GetTypesWithEmptyProgressMarkerToken(
@@ -114,7 +115,6 @@ class FakeSyncManager : public SyncManager {
virtual void RemoveObserver(Observer* observer) OVERRIDE;
virtual SyncStatus GetDetailedStatus() const OVERRIDE;
virtual void SaveChanges() OVERRIDE;
- virtual void StopSyncingForShutdown() OVERRIDE;
virtual void ShutdownOnSyncThread() OVERRIDE;
virtual UserShare* GetUserShare() OVERRIDE;
virtual const std::string cache_guid() OVERRIDE;
diff --git a/sync/internal_api/public/test/test_internal_components_factory.h b/sync/internal_api/public/test/test_internal_components_factory.h
index d846094..c899676 100644
--- a/sync/internal_api/public/test/test_internal_components_factory.h
+++ b/sync/internal_api/public/test/test_internal_components_factory.h
@@ -27,7 +27,8 @@ class TestInternalComponentsFactory : public InternalComponentsFactory {
virtual scoped_ptr<SyncScheduler> BuildScheduler(
const std::string& name,
- sessions::SyncSessionContext* context) OVERRIDE;
+ sessions::SyncSessionContext* context,
+ syncer::CancelationSignal* cancelation_signal) OVERRIDE;
virtual scoped_ptr<sessions::SyncSessionContext> BuildContext(
ServerConnectionManager* connection_manager,
diff --git a/sync/internal_api/sync_manager_impl.cc b/sync/internal_api/sync_manager_impl.cc
index 091ed28..f79213d 100644
--- a/sync/internal_api/sync_manager_impl.cc
+++ b/sync/internal_api/sync_manager_impl.cc
@@ -19,6 +19,7 @@
#include "sync/engine/sync_scheduler.h"
#include "sync/engine/syncer_types.h"
#include "sync/internal_api/change_reorder_buffer.h"
+#include "sync/internal_api/public/base/cancelation_signal.h"
#include "sync/internal_api/public/base/model_type.h"
#include "sync/internal_api/public/base_node.h"
#include "sync/internal_api/public/configure_reason.h"
@@ -354,12 +355,14 @@ void SyncManagerImpl::Init(
Encryptor* encryptor,
scoped_ptr<UnrecoverableErrorHandler> unrecoverable_error_handler,
ReportUnrecoverableErrorFunction report_unrecoverable_error_function,
- bool use_oauth2_token) {
+ bool use_oauth2_token,
+ CancelationSignal* cancelation_signal) {
CHECK(!initialized_);
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(post_factory.get());
DCHECK(!credentials.email.empty());
DCHECK(!credentials.sync_token.empty());
+ DCHECK(cancelation_signal);
DVLOG(1) << "SyncManager starting Init...";
weak_handle_this_ = MakeWeakHandle(weak_ptr_factory_.GetWeakPtr());
@@ -419,7 +422,7 @@ void SyncManagerImpl::Init(
connection_manager_.reset(new SyncAPIServerConnectionManager(
sync_server_and_path, port, use_ssl, use_oauth2_token,
- post_factory.release()));
+ post_factory.release(), cancelation_signal));
connection_manager_->set_client_id(directory()->cache_guid());
connection_manager_->AddListener(this);
@@ -447,7 +450,7 @@ void SyncManagerImpl::Init(
invalidator_client_id).Pass();
session_context_->set_account_name(credentials.email);
scheduler_ = internal_components_factory->BuildScheduler(
- name_, session_context_.get()).Pass();
+ name_, session_context_.get(), cancelation_signal).Pass();
scheduler_->Start(SyncScheduler::CONFIGURATION_MODE);
@@ -618,13 +621,6 @@ void SyncManagerImpl::RemoveObserver(SyncManager::Observer* observer) {
observers_.RemoveObserver(observer);
}
-void SyncManagerImpl::StopSyncingForShutdown() {
- DVLOG(2) << "StopSyncingForShutdown";
- scheduler_->RequestStop();
- if (connection_manager_)
- connection_manager_->TerminateAllIO();
-}
-
void SyncManagerImpl::ShutdownOnSyncThread() {
DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/sync/internal_api/sync_manager_impl.h b/sync/internal_api/sync_manager_impl.h
index 03d6636..0283065 100644
--- a/sync/internal_api/sync_manager_impl.h
+++ b/sync/internal_api/sync_manager_impl.h
@@ -81,7 +81,8 @@ class SYNC_EXPORT_PRIVATE SyncManagerImpl :
scoped_ptr<UnrecoverableErrorHandler> unrecoverable_error_handler,
ReportUnrecoverableErrorFunction
report_unrecoverable_error_function,
- bool use_oauth2_token) OVERRIDE;
+ bool use_oauth2_token,
+ CancelationSignal* cancelation_signal) OVERRIDE;
virtual void ThrowUnrecoverableError() OVERRIDE;
virtual ModelTypeSet InitialSyncEndedTypes() OVERRIDE;
virtual ModelTypeSet GetTypesWithEmptyProgressMarkerToken(
@@ -106,7 +107,6 @@ class SYNC_EXPORT_PRIVATE SyncManagerImpl :
virtual void RemoveObserver(SyncManager::Observer* observer) OVERRIDE;
virtual SyncStatus GetDetailedStatus() const OVERRIDE;
virtual void SaveChanges() OVERRIDE;
- virtual void StopSyncingForShutdown() OVERRIDE;
virtual void ShutdownOnSyncThread() OVERRIDE;
virtual UserShare* GetUserShare() OVERRIDE;
virtual const std::string cache_guid() OVERRIDE;
diff --git a/sync/internal_api/sync_manager_impl_unittest.cc b/sync/internal_api/sync_manager_impl_unittest.cc
index 614a914..dc47365 100644
--- a/sync/internal_api/sync_manager_impl_unittest.cc
+++ b/sync/internal_api/sync_manager_impl_unittest.cc
@@ -24,6 +24,7 @@
#include "base/test/values_test_util.h"
#include "base/values.h"
#include "sync/engine/sync_scheduler.h"
+#include "sync/internal_api/public/base/cancelation_signal.h"
#include "sync/internal_api/public/base/model_type_test_util.h"
#include "sync/internal_api/public/change_record.h"
#include "sync/internal_api/public/engine/model_safe_worker.h"
@@ -729,13 +730,13 @@ class TestHttpPostProviderInterface : public HttpPostProviderInterface {
class TestHttpPostProviderFactory : public HttpPostProviderFactory {
public:
virtual ~TestHttpPostProviderFactory() {}
+ virtual void Init(const std::string& user_agent) OVERRIDE { }
virtual HttpPostProviderInterface* Create() OVERRIDE {
return new TestHttpPostProviderInterface();
}
virtual void Destroy(HttpPostProviderInterface* http) OVERRIDE {
delete static_cast<TestHttpPostProviderInterface*>(http);
}
- virtual void Shutdown() OVERRIDE {}
};
class SyncManagerObserverMock : public SyncManager::Observer {
@@ -836,7 +837,8 @@ class SyncManagerTest : public testing::Test,
scoped_ptr<UnrecoverableErrorHandler>(
new TestUnrecoverableErrorHandler).Pass(),
NULL,
- false);
+ false,
+ &cancelation_signal_);
sync_manager_.GetEncryptionHandler()->AddObserver(&encryption_observer_);
@@ -1019,6 +1021,7 @@ class SyncManagerTest : public testing::Test,
protected:
FakeEncryptor encryptor_;
SyncManagerImpl sync_manager_;
+ CancelationSignal cancelation_signal_;
WeakHandle<JsBackend> js_backend_;
StrictMock<SyncManagerObserverMock> manager_observer_;
StrictMock<SyncEncryptionHandlerObserverMock> encryption_observer_;
@@ -2797,7 +2800,8 @@ class ComponentsFactory : public TestInternalComponentsFactory {
virtual scoped_ptr<SyncScheduler> BuildScheduler(
const std::string& name,
- sessions::SyncSessionContext* context) OVERRIDE {
+ sessions::SyncSessionContext* context,
+ CancelationSignal* stop_handle) OVERRIDE {
*session_context_ = context;
return scheduler_to_use_.Pass();
}
diff --git a/sync/internal_api/syncapi_server_connection_manager.cc b/sync/internal_api/syncapi_server_connection_manager.cc
index 1ebe01fe..ccfa6e6 100644
--- a/sync/internal_api/syncapi_server_connection_manager.cc
+++ b/sync/internal_api/syncapi_server_connection_manager.cc
@@ -92,8 +92,13 @@ SyncAPIServerConnectionManager::SyncAPIServerConnectionManager(
int port,
bool use_ssl,
bool use_oauth2_token,
- HttpPostProviderFactory* factory)
- : ServerConnectionManager(server, port, use_ssl, use_oauth2_token),
+ HttpPostProviderFactory* factory,
+ CancelationSignal* cancelation_signal)
+ : ServerConnectionManager(server,
+ port,
+ use_ssl,
+ use_oauth2_token,
+ cancelation_signal),
post_provider_factory_(factory) {
DCHECK(post_provider_factory_.get());
}
@@ -105,9 +110,4 @@ SyncAPIServerConnectionManager::MakeConnection() {
return new SyncAPIBridgedConnection(this, post_provider_factory_.get());
}
-void SyncAPIServerConnectionManager::TerminateAllIO() {
- ServerConnectionManager::TerminateAllIO();
- post_provider_factory_->Shutdown();
-}
-
} // namespace syncer
diff --git a/sync/internal_api/syncapi_server_connection_manager.h b/sync/internal_api/syncapi_server_connection_manager.h
index 21ede83..4805045 100644
--- a/sync/internal_api/syncapi_server_connection_manager.h
+++ b/sync/internal_api/syncapi_server_connection_manager.h
@@ -55,14 +55,16 @@ class SYNC_EXPORT_PRIVATE SyncAPIServerConnectionManager
int port,
bool use_ssl,
bool use_oauth2_token,
- HttpPostProviderFactory* factory);
+ HttpPostProviderFactory* factory,
+ CancelationSignal* cancelation_signal);
virtual ~SyncAPIServerConnectionManager();
// ServerConnectionManager overrides.
virtual Connection* MakeConnection() OVERRIDE;
- virtual void TerminateAllIO() OVERRIDE;
private:
+ FRIEND_TEST_ALL_PREFIXES(SyncAPIServerConnectionManagerTest,
+ VeryEarlyAbortPost);
FRIEND_TEST_ALL_PREFIXES(SyncAPIServerConnectionManagerTest, EarlyAbortPost);
FRIEND_TEST_ALL_PREFIXES(SyncAPIServerConnectionManagerTest, AbortPost);
diff --git a/sync/internal_api/syncapi_server_connection_manager_unittest.cc b/sync/internal_api/syncapi_server_connection_manager_unittest.cc
index e5b611c..543455e 100644
--- a/sync/internal_api/syncapi_server_connection_manager_unittest.cc
+++ b/sync/internal_api/syncapi_server_connection_manager_unittest.cc
@@ -12,6 +12,7 @@
#include "base/threading/thread.h"
#include "base/time/time.h"
#include "net/base/net_errors.h"
+#include "sync/internal_api/public/base/cancelation_signal.h"
#include "sync/internal_api/public/http_post_provider_factory.h"
#include "sync/internal_api/public/http_post_provider_interface.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -57,25 +58,45 @@ class BlockingHttpPost : public HttpPostProviderInterface {
class BlockingHttpPostFactory : public HttpPostProviderFactory {
public:
virtual ~BlockingHttpPostFactory() {}
+ virtual void Init(const std::string& user_agent) OVERRIDE {}
virtual HttpPostProviderInterface* Create() OVERRIDE {
return new BlockingHttpPost();
}
virtual void Destroy(HttpPostProviderInterface* http) OVERRIDE {
delete static_cast<BlockingHttpPost*>(http);
}
- virtual void Shutdown() OVERRIDE {}
};
} // namespace
+// Ask the ServerConnectionManager to stop before it is created.
+TEST(SyncAPIServerConnectionManagerTest, VeryEarlyAbortPost) {
+ CancelationSignal signal;
+ signal.Signal();
+ SyncAPIServerConnectionManager server(
+ "server", 0, true, false, new BlockingHttpPostFactory(), &signal);
+
+ ServerConnectionManager::PostBufferParams params;
+ ScopedServerStatusWatcher watcher(&server, &params.response);
+
+ bool result = server.PostBufferToPath(
+ &params, "/testpath", "testauth", &watcher);
+
+ EXPECT_FALSE(result);
+ EXPECT_EQ(HttpResponse::CONNECTION_UNAVAILABLE,
+ params.response.server_status);
+}
+
+// Ask the ServerConnectionManager to stop before its first request is made.
TEST(SyncAPIServerConnectionManagerTest, EarlyAbortPost) {
+ CancelationSignal signal;
SyncAPIServerConnectionManager server(
- "server", 0, true, false, new BlockingHttpPostFactory());
+ "server", 0, true, false, new BlockingHttpPostFactory(), &signal);
ServerConnectionManager::PostBufferParams params;
ScopedServerStatusWatcher watcher(&server, &params.response);
- server.TerminateAllIO();
+ signal.Signal();
bool result = server.PostBufferToPath(
&params, "/testpath", "testauth", &watcher);
@@ -84,9 +105,11 @@ TEST(SyncAPIServerConnectionManagerTest, EarlyAbortPost) {
params.response.server_status);
}
+// Ask the ServerConnectionManager to stop during a request.
TEST(SyncAPIServerConnectionManagerTest, AbortPost) {
+ CancelationSignal signal;
SyncAPIServerConnectionManager server(
- "server", 0, true, false, new BlockingHttpPostFactory());
+ "server", 0, true, false, new BlockingHttpPostFactory(), &signal);
ServerConnectionManager::PostBufferParams params;
ScopedServerStatusWatcher watcher(&server, &params.response);
@@ -95,8 +118,8 @@ TEST(SyncAPIServerConnectionManagerTest, AbortPost) {
ASSERT_TRUE(abort_thread.Start());
abort_thread.message_loop()->PostDelayedTask(
FROM_HERE,
- base::Bind(&ServerConnectionManager::TerminateAllIO,
- base::Unretained(&server)),
+ base::Bind(&CancelationSignal::Signal,
+ base::Unretained(&signal)),
TestTimeouts::tiny_timeout());
bool result = server.PostBufferToPath(
diff --git a/sync/internal_api/test/fake_sync_manager.cc b/sync/internal_api/test/fake_sync_manager.cc
index cac310b..362b74e 100644
--- a/sync/internal_api/test/fake_sync_manager.cc
+++ b/sync/internal_api/test/fake_sync_manager.cc
@@ -91,7 +91,8 @@ void FakeSyncManager::Init(
Encryptor* encryptor,
scoped_ptr<UnrecoverableErrorHandler> unrecoverable_error_handler,
ReportUnrecoverableErrorFunction report_unrecoverable_error_function,
- bool use_oauth2_token) {
+ bool use_oauth2_token,
+ CancelationSignal* cancelation_signal) {
sync_task_runner_ = base::ThreadTaskRunnerHandle::Get();
PurgePartiallySyncedTypes();
@@ -209,9 +210,6 @@ void FakeSyncManager::SaveChanges() {
// Do nothing.
}
-void FakeSyncManager::StopSyncingForShutdown() {
-}
-
void FakeSyncManager::ShutdownOnSyncThread() {
DCHECK(sync_task_runner_->RunsTasksOnCurrentThread());
test_user_share_.TearDown();
diff --git a/sync/internal_api/test/test_internal_components_factory.cc b/sync/internal_api/test/test_internal_components_factory.cc
index 03d2d82..1493e36 100644
--- a/sync/internal_api/test/test_internal_components_factory.cc
+++ b/sync/internal_api/test/test_internal_components_factory.cc
@@ -22,7 +22,9 @@ TestInternalComponentsFactory::TestInternalComponentsFactory(
TestInternalComponentsFactory::~TestInternalComponentsFactory() { }
scoped_ptr<SyncScheduler> TestInternalComponentsFactory::BuildScheduler(
- const std::string& name, sessions::SyncSessionContext* context) {
+ const std::string& name,
+ sessions::SyncSessionContext* context,
+ syncer::CancelationSignal* cancelation_signal) {
return scoped_ptr<SyncScheduler>(new FakeSyncScheduler());
}
diff --git a/sync/sync_internal_api.gypi b/sync/sync_internal_api.gypi
index a22195a..be3ce71 100644
--- a/sync/sync_internal_api.gypi
+++ b/sync/sync_internal_api.gypi
@@ -32,6 +32,10 @@
'internal_api/js_sync_encryption_handler_observer.h',
'internal_api/js_sync_manager_observer.cc',
'internal_api/js_sync_manager_observer.h',
+ 'internal_api/public/base/cancelation_observer.cc',
+ 'internal_api/public/base/cancelation_observer.h',
+ 'internal_api/public/base/cancelation_signal.cc',
+ 'internal_api/public/base/cancelation_signal.h',
'internal_api/public/base/enum_set.h',
'internal_api/public/base/invalidation.cc',
'internal_api/public/base/invalidation.h',
@@ -73,9 +77,9 @@
'internal_api/public/sessions/sync_session_snapshot.h',
'internal_api/public/sync_encryption_handler.cc',
'internal_api/public/sync_encryption_handler.h',
- 'internal_api/public/sync_manager_factory.h',
'internal_api/public/sync_manager.cc',
'internal_api/public/sync_manager.h',
+ 'internal_api/public/sync_manager_factory.h',
'internal_api/public/user_share.h',
'internal_api/public/util/experiments.h',
'internal_api/public/util/immutable.h',
diff --git a/sync/sync_tests.gypi b/sync/sync_tests.gypi
index 07165af..93d6ed8 100644
--- a/sync/sync_tests.gypi
+++ b/sync/sync_tests.gypi
@@ -226,6 +226,7 @@
'..',
],
'sources': [
+ 'internal_api/public/base/cancelation_signal_unittest.cc',
'internal_api/public/base/enum_set_unittest.cc',
'internal_api/public/base/node_ordinal_unittest.cc',
'internal_api/public/base/ordinal_unittest.cc',
diff --git a/sync/test/engine/fake_sync_scheduler.cc b/sync/test/engine/fake_sync_scheduler.cc
index 1e0c7e8..5d45494 100644
--- a/sync/test/engine/fake_sync_scheduler.cc
+++ b/sync/test/engine/fake_sync_scheduler.cc
@@ -13,7 +13,7 @@ FakeSyncScheduler::~FakeSyncScheduler() {}
void FakeSyncScheduler::Start(Mode mode) {
}
-void FakeSyncScheduler::RequestStop() {
+void FakeSyncScheduler::Stop() {
}
void FakeSyncScheduler::ScheduleLocalNudge(
diff --git a/sync/test/engine/fake_sync_scheduler.h b/sync/test/engine/fake_sync_scheduler.h
index 11a63cc..95bdfa9 100644
--- a/sync/test/engine/fake_sync_scheduler.h
+++ b/sync/test/engine/fake_sync_scheduler.h
@@ -20,7 +20,7 @@ class FakeSyncScheduler : public SyncScheduler {
virtual ~FakeSyncScheduler();
virtual void Start(Mode mode) OVERRIDE;
- virtual void RequestStop() OVERRIDE;
+ virtual void Stop() OVERRIDE;
virtual void ScheduleLocalNudge(
const base::TimeDelta& desired_delay,
ModelTypeSet types,
diff --git a/sync/test/engine/mock_connection_manager.cc b/sync/test/engine/mock_connection_manager.cc
index 5bf2b4b..009b5a1 100644
--- a/sync/test/engine/mock_connection_manager.cc
+++ b/sync/test/engine/mock_connection_manager.cc
@@ -33,8 +33,9 @@ using syncable::WriteTransaction;
static char kValidAuthToken[] = "AuthToken";
static char kCacheGuid[] = "kqyg7097kro6GSUod+GSg==";
-MockConnectionManager::MockConnectionManager(syncable::Directory* directory)
- : ServerConnectionManager("unused", 0, false, false),
+MockConnectionManager::MockConnectionManager(syncable::Directory* directory,
+ CancelationSignal* signal)
+ : ServerConnectionManager("unused", 0, false, false, signal),
server_reachable_(true),
conflict_all_commits_(false),
conflict_n_commits_(0),
diff --git a/sync/test/engine/mock_connection_manager.h b/sync/test/engine/mock_connection_manager.h
index 83de59a..afeaac8 100644
--- a/sync/test/engine/mock_connection_manager.h
+++ b/sync/test/engine/mock_connection_manager.h
@@ -15,6 +15,7 @@
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_vector.h"
+#include "base/synchronization/lock.h"
#include "sync/engine/net/server_connection_manager.h"
#include "sync/internal_api/public/base/model_type.h"
#include "sync/internal_api/public/base/unique_position.h"
@@ -32,7 +33,8 @@ class MockConnectionManager : public ServerConnectionManager {
virtual ~MidCommitObserver() {}
};
- explicit MockConnectionManager(syncable::Directory*);
+ MockConnectionManager(syncable::Directory*,
+ CancelationSignal* signal);
virtual ~MockConnectionManager();
// Overridden ServerConnectionManager functions.
diff --git a/sync/test/engine/syncer_command_test.h b/sync/test/engine/syncer_command_test.h
index 6e1f672..28e3207 100644
--- a/sync/test/engine/syncer_command_test.h
+++ b/sync/test/engine/syncer_command_test.h
@@ -15,6 +15,7 @@
#include "sync/engine/model_changing_syncer_command.h"
#include "sync/engine/traffic_recorder.h"
#include "sync/internal_api/debug_info_event_listener.h"
+#include "sync/internal_api/public/base/cancelation_signal.h"
#include "sync/internal_api/public/engine/model_safe_worker.h"
#include "sync/sessions/debug_info_getter.h"
#include "sync/sessions/sync_session.h"
@@ -104,7 +105,8 @@ class SyncerCommandTestBase : public testing::Test,
// Install a MockServerConnection. Resets the context. By default,
// the context does not have a MockServerConnection attached.
void ConfigureMockServerConnection() {
- mock_server_.reset(new MockConnectionManager(directory()));
+ mock_server_.reset(new MockConnectionManager(directory(),
+ &cancelation_signal_));
ResetContext();
}
@@ -169,6 +171,7 @@ class SyncerCommandTestBase : public testing::Test,
DebugInfoEventListener debug_info_event_listener_;
scoped_refptr<ExtensionsActivity> extensions_activity_;
TrafficRecorder traffic_recorder_;
+ CancelationSignal cancelation_signal_;
DISALLOW_COPY_AND_ASSIGN(SyncerCommandTestBase);
};
diff --git a/sync/tools/sync_client.cc b/sync/tools/sync_client.cc
index b677531..95c4211 100644
--- a/sync/tools/sync_client.cc
+++ b/sync/tools/sync_client.cc
@@ -27,6 +27,7 @@
#include "net/dns/host_resolver.h"
#include "net/http/transport_security_state.h"
#include "net/url_request/url_request_test_util.h"
+#include "sync/internal_api/public/base/cancelation_signal.h"
#include "sync/internal_api/public/base/model_type.h"
#include "sync/internal_api/public/base_node.h"
#include "sync/internal_api/public/engine/passive_model_worker.h"
@@ -334,10 +335,12 @@ int SyncClientMain(int argc, char* argv[]) {
const char kUserAgent[] = "sync_client";
// TODO(akalin): Replace this with just the context getter once
// HttpPostProviderFactory is removed.
+ CancelationSignal factory_cancelation_signal;
scoped_ptr<HttpPostProviderFactory> post_factory(
new HttpBridgeFactory(context_getter.get(),
- kUserAgent,
- base::Bind(&StubNetworkTimeUpdateCallback)));
+ base::Bind(&StubNetworkTimeUpdateCallback),
+ &factory_cancelation_signal));
+ post_factory->Init(kUserAgent);
// Used only when committing bookmarks, so it's okay to leave this
// as NULL.
ExtensionsActivity* extensions_activity = NULL;
@@ -349,6 +352,7 @@ int SyncClientMain(int argc, char* argv[]) {
InternalComponentsFactory::ENCRYPTION_KEYSTORE,
InternalComponentsFactory::BACKOFF_NORMAL
};
+ CancelationSignal scm_cancelation_signal;
sync_manager->Init(database_dir.path(),
WeakHandle<JsEventHandler>(
@@ -368,7 +372,8 @@ int SyncClientMain(int argc, char* argv[]) {
&null_encryptor,
scoped_ptr<UnrecoverableErrorHandler>(
new LoggingUnrecoverableErrorHandler).Pass(),
- &LogUnrecoverableErrorContext, false);
+ &LogUnrecoverableErrorContext, false,
+ &scm_cancelation_signal);
// TODO(akalin): Avoid passing in model parameters multiple times by
// organizing handling of model types.
invalidator->UpdateCredentials(credentials.email, credentials.sync_token);