summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/sync/engine/all_status.cc7
-rw-r--r--chrome/browser/sync/engine/all_status.h7
-rw-r--r--chrome/browser/sync/engine/syncapi.cc29
-rw-r--r--chrome/browser/sync/engine/syncer.cc13
-rw-r--r--chrome/browser/sync/engine/syncer.h2
-rw-r--r--chrome/browser/sync/engine/syncer_command.cc4
-rw-r--r--chrome/browser/sync/engine/syncer_end_command.cc2
-rw-r--r--chrome/browser/sync/engine/syncer_thread.cc18
-rw-r--r--chrome/browser/sync/engine/syncer_thread.h7
-rw-r--r--chrome/browser/sync/engine/syncer_thread_unittest.cc39
-rw-r--r--chrome/browser/sync/engine/syncer_types.h9
-rw-r--r--chrome/browser/sync/engine/syncer_unittest.cc10
-rw-r--r--chrome/browser/sync/sessions/sync_session_unittest.cc4
-rw-r--r--chrome/browser/sync/syncable/syncable.cc12
-rw-r--r--chrome/browser/sync/syncable/syncable.h13
-rw-r--r--chrome/browser/sync/util/channel.h140
-rw-r--r--chrome/browser/sync/util/channel_unittest.cc32
-rw-r--r--chrome/chrome.gyp1
-rwxr-xr-xchrome/chrome_tests.gypi1
19 files changed, 268 insertions, 82 deletions
diff --git a/chrome/browser/sync/engine/all_status.cc b/chrome/browser/sync/engine/all_status.cc
index 64ea9a7..39509f4 100644
--- a/chrome/browser/sync/engine/all_status.cc
+++ b/chrome/browser/sync/engine/all_status.cc
@@ -50,6 +50,7 @@ AllStatus::AllStatus() : status_(init_status),
}
AllStatus::~AllStatus() {
+ syncer_thread_hookup_.reset();
delete channel_;
}
@@ -60,8 +61,7 @@ void AllStatus::WatchConnectionManager(ServerConnectionManager* conn_mgr) {
void AllStatus::WatchSyncerThread(SyncerThread* syncer_thread) {
syncer_thread_hookup_.reset(
- NewEventListenerHookup(syncer_thread->relay_channel(), this,
- &AllStatus::HandleSyncerEvent));
+ syncer_thread->relay_channel()->AddObserver(this));
}
AllStatus::Status AllStatus::CreateBlankStatus() const {
@@ -187,7 +187,7 @@ void AllStatus::HandleAuthWatcherEvent(const AuthWatcherEvent& auth_event) {
}
}
-void AllStatus::HandleSyncerEvent(const SyncerEvent& event) {
+void AllStatus::HandleChannelEvent(const SyncerEvent& event) {
ScopedStatusLockWithNotify lock(this);
switch (event.what_happened) {
case SyncerEvent::COMMITS_SUCCEEDED:
@@ -200,6 +200,7 @@ void AllStatus::HandleSyncerEvent(const SyncerEvent& event) {
// We're safe to use this value here because we don't call into the syncer
// or block on any processes.
lock.set_notify_plan(DONT_NOTIFY);
+ syncer_thread_hookup_.reset();
break;
case SyncerEvent::OVER_QUOTA:
LOG(WARNING) << "User has gone over quota.";
diff --git a/chrome/browser/sync/engine/all_status.h b/chrome/browser/sync/engine/all_status.h
index d34a15a..63edd17 100644
--- a/chrome/browser/sync/engine/all_status.h
+++ b/chrome/browser/sync/engine/all_status.h
@@ -13,6 +13,7 @@
#include "base/atomicops.h"
#include "base/lock.h"
#include "base/scoped_ptr.h"
+#include "chrome/browser/sync/util/channel.h"
#include "chrome/common/deprecated/event_sys.h"
namespace browser_sync {
@@ -26,7 +27,7 @@ struct AuthWatcherEvent;
struct ServerConnectionEvent;
struct SyncerEvent;
-class AllStatus {
+class AllStatus : public ChannelEventHandler<SyncerEvent> {
friend class ScopedStatusLockWithNotify;
public:
typedef EventChannel<AllStatusEvent, Lock> Channel;
@@ -97,7 +98,7 @@ class AllStatus {
void HandleAuthWatcherEvent(const AuthWatcherEvent& event);
void WatchSyncerThread(SyncerThread* syncer_thread);
- void HandleSyncerEvent(const SyncerEvent& event);
+ void HandleChannelEvent(const SyncerEvent& event);
// Returns a string description of the SyncStatus (currently just the ascii
// version of the enum). Will LOG(FATAL) if the status us out of range.
@@ -134,7 +135,7 @@ class AllStatus {
Status status_;
Channel* const channel_;
scoped_ptr<EventListenerHookup> conn_mgr_hookup_;
- scoped_ptr<EventListenerHookup> syncer_thread_hookup_;
+ scoped_ptr<ChannelHookup<SyncerEvent> > syncer_thread_hookup_;
scoped_ptr<EventListenerHookup> diskfull_hookup_;
scoped_ptr<EventListenerHookup> talk_mediator_hookup_;
diff --git a/chrome/browser/sync/engine/syncapi.cc b/chrome/browser/sync/engine/syncapi.cc
index d4867e6..ad6d4380 100644
--- a/chrome/browser/sync/engine/syncapi.cc
+++ b/chrome/browser/sync/engine/syncapi.cc
@@ -796,7 +796,9 @@ class BridgedGaiaAuthenticator : public gaia::GaiaAuthenticator {
// SyncManager's implementation: SyncManager::SyncInternal
class SyncManager::SyncInternal
: public net::NetworkChangeNotifier::Observer,
- public TalkMediator::Delegate {
+ public TalkMediator::Delegate,
+ public browser_sync::ChannelEventHandler<syncable::DirectoryChangeEvent>,
+ public browser_sync::ChannelEventHandler<SyncerEvent>{
static const int kDefaultNudgeDelayMilliseconds;
static const int kPreferencesNudgeDelayMilliseconds;
public:
@@ -864,7 +866,7 @@ class SyncManager::SyncInternal
// This listener is called upon completion of a syncable transaction, and
// builds the list of sync-engine initiated changes that will be forwarded to
// the SyncManager's Observers.
- void HandleChangeEvent(const syncable::DirectoryChangeEvent& event);
+ virtual void HandleChannelEvent(const syncable::DirectoryChangeEvent& event);
void HandleTransactionCompleteChangeEvent(
const syncable::DirectoryChangeEvent& event);
void HandleCalculateChangesChangeEventFromSyncApi(
@@ -873,7 +875,7 @@ class SyncManager::SyncInternal
const syncable::DirectoryChangeEvent& event);
// This listener is called by the syncer channel for all syncer events.
- void HandleSyncerEvent(const SyncerEvent& event);
+ virtual void HandleChannelEvent(const SyncerEvent& event);
// We have a direct hookup to the authwatcher to be notified for auth failures
// on startup, to serve our UI needs.
@@ -1087,10 +1089,11 @@ class SyncManager::SyncInternal
ChangeReorderBuffer change_buffers_[syncable::MODEL_TYPE_COUNT];
// The event listener hookup that is registered for HandleChangeEvent.
- scoped_ptr<EventListenerHookup> dir_change_hookup_;
+ scoped_ptr<browser_sync::ChannelHookup<syncable::DirectoryChangeEvent> >
+ dir_change_hookup_;
// The event listener hookup registered for HandleSyncerEvent.
- scoped_ptr<EventListenerHookup> syncer_event_;
+ scoped_ptr<browser_sync::ChannelHookup<SyncerEvent> > syncer_event_;
// The event listener hookup registered for HandleAuthWatcherEvent.
scoped_ptr<EventListenerHookup> authwatcher_hookup_;
@@ -1294,9 +1297,7 @@ bool SyncManager::SyncInternal::Init(
allstatus_.WatchSyncerThread(syncer_thread());
// Subscribe to the syncer thread's channel.
- syncer_event_.reset(
- NewEventListenerHookup(syncer_thread()->relay_channel(), this,
- &SyncInternal::HandleSyncerEvent));
+ syncer_event_.reset(syncer_thread()->relay_channel()->AddObserver(this));
bool attempting_auth = false;
std::string username, auth_token;
@@ -1521,7 +1522,7 @@ void SyncManager::SyncInternal::OnIPAddressChanged() {
// Listen to model changes, filter out ones initiated by the sync API, and
// saves the rest (hopefully just backend Syncer changes resulting from
// ApplyUpdates) to data_->changelist.
-void SyncManager::SyncInternal::HandleChangeEvent(
+void SyncManager::SyncInternal::HandleChannelEvent(
const syncable::DirectoryChangeEvent& event) {
if (event.todo == syncable::DirectoryChangeEvent::TRANSACTION_COMPLETE) {
HandleTransactionCompleteChangeEvent(event);
@@ -1694,7 +1695,7 @@ SyncManager::Status SyncManager::SyncInternal::ComputeAggregatedStatus() {
return return_status;
}
-void SyncManager::SyncInternal::HandleSyncerEvent(const SyncerEvent& event) {
+void SyncManager::SyncInternal::HandleChannelEvent(const SyncerEvent& event) {
if (!initialized()) {
// This could be the first time that the syncer has completed a full
// download; if so, we should signal that initialization is complete.
@@ -1778,9 +1779,7 @@ void SyncManager::SyncInternal::HandleAuthWatcherEvent(
<< "up directory change event listener!";
return;
}
- dir_change_hookup_.reset(NewEventListenerHookup(
- lookup->changes_channel(), this,
- &SyncInternal::HandleChangeEvent));
+ dir_change_hookup_.reset(lookup->AddChangeObserver(this));
}
if (InitialSyncEndedForAllEnabledTypes())
MarkAndNotifyInitializationComplete();
@@ -1942,9 +1941,7 @@ void SyncManager::SyncInternal::SetupForTestMode(
<< "up directory change event listener!";
return;
}
- dir_change_hookup_.reset(NewEventListenerHookup(
- lookup->changes_channel(), this,
- &SyncInternal::HandleChangeEvent));
+ dir_change_hookup_.reset(lookup->AddChangeObserver(this));
}
MarkAndNotifyInitializationComplete();
}
diff --git a/chrome/browser/sync/engine/syncer.cc b/chrome/browser/sync/engine/syncer.cc
index 24c471b..2956a04 100644
--- a/chrome/browser/sync/engine/syncer.cc
+++ b/chrome/browser/sync/engine/syncer.cc
@@ -55,24 +55,29 @@ using sessions::ConflictProgress;
Syncer::Syncer(sessions::SyncSessionContext* context)
: early_exit_requested_(false),
max_commit_batch_size_(kDefaultMaxCommitBatchSize),
- syncer_event_channel_(new SyncerEventChannel(SyncerEvent(
- SyncerEvent::SHUTDOWN_USE_WITH_CARE))),
+ syncer_event_channel_(new SyncerEventChannel()),
resolver_scoper_(context, &resolver_),
event_channel_scoper_(context, syncer_event_channel_.get()),
context_(context),
updates_source_(sync_pb::GetUpdatesCallerInfo::UNKNOWN),
pre_conflict_resolution_closure_(NULL) {
- shutdown_channel_.reset(new ShutdownChannel(this));
+ shutdown_channel_.reset(new ShutdownChannel());
ScopedDirLookup dir(context->directory_manager(), context->account_name());
// The directory must be good here.
CHECK(dir.good());
}
+Syncer::~Syncer() {
+ syncer_event_channel_->Notify(
+ SyncerEvent(SyncerEvent::SHUTDOWN_USE_WITH_CARE));
+ shutdown_channel_->Notify(SyncerShutdownEvent(this));
+}
+
void Syncer::RequestNudge(int milliseconds) {
SyncerEvent event(SyncerEvent::REQUEST_SYNC_NUDGE);
event.nudge_delay_milliseconds = milliseconds;
- syncer_event_channel_->NotifyListeners(event);
+ syncer_event_channel_->Notify(event);
}
bool Syncer::SyncShare(sessions::SyncSession::Delegate* delegate) {
diff --git a/chrome/browser/sync/engine/syncer.h b/chrome/browser/sync/engine/syncer.h
index df28ee4..27a8d70 100644
--- a/chrome/browser/sync/engine/syncer.h
+++ b/chrome/browser/sync/engine/syncer.h
@@ -76,7 +76,7 @@ class Syncer {
// The constructor may be called from a thread that is not the Syncer's
// dedicated thread, to allow some flexibility in the setup.
explicit Syncer(sessions::SyncSessionContext* context);
- ~Syncer() {}
+ ~Syncer();
// Called by other threads to tell the syncer to stop what it's doing
// and return early from SyncShare, if possible.
diff --git a/chrome/browser/sync/engine/syncer_command.cc b/chrome/browser/sync/engine/syncer_command.cc
index 2c58795..f95cf40 100644
--- a/chrome/browser/sync/engine/syncer_command.cc
+++ b/chrome/browser/sync/engine/syncer_command.cc
@@ -34,11 +34,11 @@ void SyncerCommand::SendNotifications(SyncSession* session) {
const sessions::SyncSessionSnapshot& snapshot(session->TakeSnapshot());
event.snapshot = &snapshot;
DCHECK(session->context()->syncer_event_channel());
- session->context()->syncer_event_channel()->NotifyListeners(event);
+ session->context()->syncer_event_channel()->Notify(event);
if (session->status_controller()->syncer_status().over_quota) {
SyncerEvent quota_event(SyncerEvent::OVER_QUOTA);
quota_event.snapshot = &snapshot;
- session->context()->syncer_event_channel()->NotifyListeners(quota_event);
+ session->context()->syncer_event_channel()->Notify(quota_event);
}
}
}
diff --git a/chrome/browser/sync/engine/syncer_end_command.cc b/chrome/browser/sync/engine/syncer_end_command.cc
index e1dae58..6d7f091 100644
--- a/chrome/browser/sync/engine/syncer_end_command.cc
+++ b/chrome/browser/sync/engine/syncer_end_command.cc
@@ -41,7 +41,7 @@ void SyncerEndCommand::ExecuteImpl(sessions::SyncSession* session) {
SyncerEvent event(SyncerEvent::SYNC_CYCLE_ENDED);
sessions::SyncSessionSnapshot snapshot(session->TakeSnapshot());
event.snapshot = &snapshot;
- session->context()->syncer_event_channel()->NotifyListeners(event);
+ session->context()->syncer_event_channel()->Notify(event);
}
} // namespace browser_sync
diff --git a/chrome/browser/sync/engine/syncer_thread.cc b/chrome/browser/sync/engine/syncer_thread.cc
index ed8b023..9fc69d4 100644
--- a/chrome/browser/sync/engine/syncer_thread.cc
+++ b/chrome/browser/sync/engine/syncer_thread.cc
@@ -74,8 +74,7 @@ SyncerThread::SyncerThread(sessions::SyncSessionContext* context,
session_context_(context),
disable_idle_detection_(false) {
DCHECK(context);
- syncer_event_relay_channel_.reset(new SyncerEventChannel(SyncerEvent(
- SyncerEvent::SHUTDOWN_USE_WITH_CARE)));
+ syncer_event_relay_channel_.reset(new SyncerEventChannel());
if (context->directory_manager()) {
directory_manager_hookup_.reset(NewEventListenerHookup(
@@ -90,6 +89,8 @@ SyncerThread::SyncerThread(sessions::SyncSessionContext* context,
SyncerThread::~SyncerThread() {
conn_mgr_hookup_.reset();
+ syncer_event_relay_channel_->Notify(SyncerEvent(
+ SyncerEvent::SHUTDOWN_USE_WITH_CARE));
syncer_event_relay_channel_.reset();
directory_manager_hookup_.reset();
syncer_events_.reset();
@@ -305,7 +306,7 @@ void SyncerThread::ThreadMainLoop() {
void SyncerThread::PauseUntilResumedOrQuit() {
LOG(INFO) << "Syncer thread entering pause.";
SyncerEvent event(SyncerEvent::PAUSED);
- relay_channel()->NotifyListeners(event);
+ relay_channel()->Notify(event);
// Thread will get stuck here until either a resume is requested
// or shutdown is started.
@@ -315,7 +316,7 @@ void SyncerThread::PauseUntilResumedOrQuit() {
// Notify that we have resumed if we are not shutting down.
if (!vault_.stop_syncer_thread_) {
SyncerEvent event(SyncerEvent::RESUMED);
- relay_channel()->NotifyListeners(event);
+ relay_channel()->Notify(event);
}
LOG(INFO) << "Syncer thread exiting pause.";
}
@@ -479,9 +480,9 @@ void SyncerThread::SetUpdatesSource(bool nudged, NudgeSource nudge_source,
vault_.syncer_->set_updates_source(updates_source);
}
-void SyncerThread::HandleSyncerEvent(const SyncerEvent& event) {
+void SyncerThread::HandleChannelEvent(const SyncerEvent& event) {
AutoLock lock(lock_);
- relay_channel()->NotifyListeners(event);
+ relay_channel()->Notify(event);
if (SyncerEvent::REQUEST_SYNC_NUDGE != event.what_happened) {
return;
}
@@ -500,9 +501,8 @@ void SyncerThread::HandleDirectoryManagerEvent(
session_context_->set_account_name(event.dirname);
vault_.syncer_ = new Syncer(session_context_.get());
- syncer_events_.reset(NewEventListenerHookup(
- session_context_->syncer_event_channel(), this,
- &SyncerThread::HandleSyncerEvent));
+ syncer_events_.reset(
+ session_context_->syncer_event_channel()->AddObserver(this));
vault_field_changed_.Broadcast();
}
}
diff --git a/chrome/browser/sync/engine/syncer_thread.h b/chrome/browser/sync/engine/syncer_thread.h
index 8801b63..af6417e 100644
--- a/chrome/browser/sync/engine/syncer_thread.h
+++ b/chrome/browser/sync/engine/syncer_thread.h
@@ -46,7 +46,8 @@ struct SyncerEvent;
struct SyncerShutdownEvent;
class SyncerThread : public base::RefCountedThreadSafe<SyncerThread>,
- public sessions::SyncSession::Delegate {
+ public sessions::SyncSession::Delegate,
+ public ChannelEventHandler<SyncerEvent> {
FRIEND_TEST_ALL_PREFIXES(SyncerThreadTest, CalculateSyncWaitTime);
FRIEND_TEST_ALL_PREFIXES(SyncerThreadTest, CalculatePollingWaitTime);
FRIEND_TEST_ALL_PREFIXES(SyncerThreadWithSyncerTest, Polling);
@@ -220,7 +221,7 @@ class SyncerThread : public base::RefCountedThreadSafe<SyncerThread>,
void* Run();
void HandleDirectoryManagerEvent(
const syncable::DirectoryManagerEvent& event);
- void HandleSyncerEvent(const SyncerEvent& event);
+ void HandleChannelEvent(const SyncerEvent& event);
// SyncSession::Delegate implementation.
virtual void OnSilencedUntil(const base::TimeTicks& silenced_until);
@@ -302,7 +303,7 @@ class SyncerThread : public base::RefCountedThreadSafe<SyncerThread>,
void NudgeSyncImpl(int milliseconds_from_now, NudgeSource source);
scoped_ptr<EventListenerHookup> directory_manager_hookup_;
- scoped_ptr<EventListenerHookup> syncer_events_;
+ scoped_ptr<ChannelHookup<SyncerEvent> > syncer_events_;
#if defined(OS_LINUX)
// On Linux, we need this information in order to query idle time.
diff --git a/chrome/browser/sync/engine/syncer_thread_unittest.cc b/chrome/browser/sync/engine/syncer_thread_unittest.cc
index 946978b..14f4e02 100644
--- a/chrome/browser/sync/engine/syncer_thread_unittest.cc
+++ b/chrome/browser/sync/engine/syncer_thread_unittest.cc
@@ -13,6 +13,7 @@
#include "chrome/browser/sync/engine/syncer_thread.h"
#include "chrome/browser/sync/engine/syncer_types.h"
#include "chrome/browser/sync/sessions/sync_session_context.h"
+#include "chrome/browser/sync/util/channel.h"
#include "chrome/test/sync/engine/mock_server_connection.h"
#include "chrome/test/sync/engine/test_directory_setter_upper.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -32,7 +33,8 @@ typedef testing::Test SyncerThreadTest;
typedef SyncerThread::WaitInterval WaitInterval;
class SyncerThreadWithSyncerTest : public testing::Test,
- public ModelSafeWorkerRegistrar {
+ public ModelSafeWorkerRegistrar,
+ public ChannelEventHandler<SyncerEvent> {
public:
SyncerThreadWithSyncerTest() : sync_cycle_ended_event_(false, false) {}
virtual void SetUp() {
@@ -45,8 +47,7 @@ class SyncerThreadWithSyncerTest : public testing::Test,
NULL, metadb_.manager(), this);
syncer_thread_ = new SyncerThread(context, allstatus_.get());
syncer_event_hookup_.reset(
- NewEventListenerHookup(syncer_thread_->relay_channel(), this,
- &SyncerThreadWithSyncerTest::HandleSyncerEvent));
+ syncer_thread_->relay_channel()->AddObserver(this));
allstatus_->WatchSyncerThread(syncer_thread_);
syncer_thread_->SetConnected(true);
syncable::ModelTypeBitSet expected_types;
@@ -54,8 +55,9 @@ class SyncerThreadWithSyncerTest : public testing::Test,
connection_->ExpectGetUpdatesRequestTypes(expected_types);
}
virtual void TearDown() {
- syncer_thread_ = NULL;
+ syncer_event_hookup_.reset();
allstatus_.reset();
+ syncer_thread_ = NULL;
connection_.reset();
metadb_.TearDown();
}
@@ -98,7 +100,7 @@ class SyncerThreadWithSyncerTest : public testing::Test,
private:
- void HandleSyncerEvent(const SyncerEvent& event) {
+ void HandleChannelEvent(const SyncerEvent& event) {
if (event.what_happened == SyncerEvent::SYNC_CYCLE_ENDED)
sync_cycle_ended_event_.Signal();
}
@@ -108,7 +110,7 @@ class SyncerThreadWithSyncerTest : public testing::Test,
scoped_ptr<AllStatus> allstatus_;
scoped_refptr<SyncerThread> syncer_thread_;
scoped_refptr<ModelSafeWorker> worker_;
- scoped_ptr<EventListenerHookup> syncer_event_hookup_;
+ scoped_ptr<ChannelHookup<SyncerEvent> > syncer_event_hookup_;
base::WaitableEvent sync_cycle_ended_event_;
DISALLOW_COPY_AND_ASSIGN(SyncerThreadWithSyncerTest);
};
@@ -715,9 +717,9 @@ ACTION_P(SignalEvent, event) {
event->Signal();
}
-class ListenerMock {
+class ListenerMock : public ChannelEventHandler<SyncerEvent> {
public:
- MOCK_METHOD1(HandleEvent, void(const SyncerEvent&));
+ MOCK_METHOD1(HandleChannelEvent, void(const SyncerEvent&));
};
// TODO(skrul): Bug 39070.
@@ -730,13 +732,10 @@ TEST_F(SyncerThreadWithSyncerTest, DISABLED_Pause) {
syncer_thread()->SetSyncerShortPollInterval(poll_interval);
ListenerMock listener;
- scoped_ptr<EventListenerHookup> hookup;
- hookup.reset(
- NewEventListenerHookup(syncer_thread()->relay_channel(),
- &listener,
- &ListenerMock::HandleEvent));
+ scoped_ptr<ChannelHookup<SyncerEvent> > hookup;
+ hookup.reset(syncer_thread()->relay_channel()->AddObserver(&listener));
- EXPECT_CALL(listener, HandleEvent(
+ EXPECT_CALL(listener, HandleChannelEvent(
Field(&SyncerEvent::what_happened, SyncerEvent::STATUS_CHANGED))).
Times(AnyNumber());
@@ -745,7 +744,7 @@ TEST_F(SyncerThreadWithSyncerTest, DISABLED_Pause) {
EXPECT_FALSE(syncer_thread()->RequestResume());
// Wait for the initial sync to complete.
- EXPECT_CALL(listener, HandleEvent(
+ EXPECT_CALL(listener, HandleChannelEvent(
Field(&SyncerEvent::what_happened, SyncerEvent::SYNC_CYCLE_ENDED))).
WillOnce(SignalEvent(&sync_cycle_ended_event));
ASSERT_TRUE(syncer_thread()->Start());
@@ -753,14 +752,14 @@ TEST_F(SyncerThreadWithSyncerTest, DISABLED_Pause) {
sync_cycle_ended_event.Wait();
// Request a pause.
- EXPECT_CALL(listener, HandleEvent(
+ EXPECT_CALL(listener, HandleChannelEvent(
Field(&SyncerEvent::what_happened, SyncerEvent::PAUSED))).
WillOnce(SignalEvent(&paused_event));
ASSERT_TRUE(syncer_thread()->RequestPause());
paused_event.Wait();
// Resuming the pause.
- EXPECT_CALL(listener, HandleEvent(
+ EXPECT_CALL(listener, HandleChannelEvent(
Field(&SyncerEvent::what_happened, SyncerEvent::RESUMED))).
WillOnce(SignalEvent(&resumed_event));
ASSERT_TRUE(syncer_thread()->RequestResume());
@@ -770,7 +769,7 @@ TEST_F(SyncerThreadWithSyncerTest, DISABLED_Pause) {
EXPECT_FALSE(syncer_thread()->RequestResume());
// Request a pause.
- EXPECT_CALL(listener, HandleEvent(
+ EXPECT_CALL(listener, HandleChannelEvent(
Field(&SyncerEvent::what_happened, SyncerEvent::PAUSED))).
WillOnce(SignalEvent(&paused_event));
ASSERT_TRUE(syncer_thread()->RequestPause());
@@ -780,11 +779,11 @@ TEST_F(SyncerThreadWithSyncerTest, DISABLED_Pause) {
syncer_thread()->NudgeSyncer(0, SyncerThread::kUnknown);
// Resuming will cause the nudge to be processed and a sync cycle to run.
- EXPECT_CALL(listener, HandleEvent(
+ EXPECT_CALL(listener, HandleChannelEvent(
Field(&SyncerEvent::what_happened, SyncerEvent::RESUMED))).
WillOnce(SignalEvent(&resumed_event));
// Wait for the sync cycle to run.
- EXPECT_CALL(listener, HandleEvent(
+ EXPECT_CALL(listener, HandleChannelEvent(
Field(&SyncerEvent::what_happened, SyncerEvent::SYNC_CYCLE_ENDED))).
WillOnce(SignalEvent(&sync_cycle_ended_event));
ASSERT_TRUE(syncer_thread()->RequestResume());
diff --git a/chrome/browser/sync/engine/syncer_types.h b/chrome/browser/sync/engine/syncer_types.h
index 762d526..a842e87 100644
--- a/chrome/browser/sync/engine/syncer_types.h
+++ b/chrome/browser/sync/engine/syncer_types.h
@@ -8,7 +8,7 @@
#include <map>
#include <vector>
-#include "chrome/common/deprecated/event_sys.h"
+#include "chrome/browser/sync/util/channel.h"
namespace syncable {
class BaseTransaction;
@@ -128,15 +128,16 @@ struct SyncerEvent {
};
struct SyncerShutdownEvent {
- typedef Syncer* EventType;
+ SyncerShutdownEvent(Syncer *syncer_ptr) : syncer(syncer_ptr) {}
+ Syncer* syncer;
static bool IsChannelShutdownEvent(Syncer* syncer) {
return true;
}
};
-typedef EventChannel<SyncerEvent, Lock> SyncerEventChannel;
+typedef Channel<SyncerEvent> SyncerEventChannel;
-typedef EventChannel<SyncerShutdownEvent, Lock> ShutdownChannel;
+typedef Channel<SyncerShutdownEvent> ShutdownChannel;
// This struct is passed between parts of the syncer during the processing of
// one sync loop. It lives on the stack. We don't expose the number of
diff --git a/chrome/browser/sync/engine/syncer_unittest.cc b/chrome/browser/sync/engine/syncer_unittest.cc
index 7573cde..f7946f5 100644
--- a/chrome/browser/sync/engine/syncer_unittest.cc
+++ b/chrome/browser/sync/engine/syncer_unittest.cc
@@ -103,7 +103,8 @@ const int64 kTestLogRequestTimestamp = 123456;
class SyncerTest : public testing::Test,
public SyncSession::Delegate,
- public ModelSafeWorkerRegistrar {
+ public ModelSafeWorkerRegistrar,
+ public ChannelEventHandler<SyncerEvent> {
protected:
SyncerTest() : syncer_(NULL) {}
@@ -138,7 +139,7 @@ class SyncerTest : public testing::Test,
}
}
- void HandleSyncerEvent(SyncerEvent event) {
+ void HandleChannelEvent(const SyncerEvent& event) {
LOG(INFO) << "HandleSyncerEvent in unittest " << event.what_happened;
// we only test for entry-specific events, not status changed ones.
switch (event.what_happened) {
@@ -185,8 +186,7 @@ class SyncerTest : public testing::Test,
ASSERT_TRUE(context_->syncer_event_channel());
ASSERT_TRUE(context_->resolver());
- hookup_.reset(NewEventListenerHookup(context_->syncer_event_channel(), this,
- &SyncerTest::HandleSyncerEvent));
+ hookup_.reset(context_->syncer_event_channel()->AddObserver(this));
session_.reset(new SyncSession(context_.get(), this));
ScopedDirLookup dir(syncdb_.manager(), syncdb_.name());
@@ -421,7 +421,7 @@ class SyncerTest : public testing::Test,
TestDirectorySetterUpper syncdb_;
scoped_ptr<MockConnectionManager> mock_server_;
- scoped_ptr<EventListenerHookup> hookup_;
+ scoped_ptr<ChannelHookup<SyncerEvent> > hookup_;
Syncer* syncer_;
diff --git a/chrome/browser/sync/sessions/sync_session_unittest.cc b/chrome/browser/sync/sessions/sync_session_unittest.cc
index 4251f0d..ae85137 100644
--- a/chrome/browser/sync/sessions/sync_session_unittest.cc
+++ b/chrome/browser/sync/sessions/sync_session_unittest.cc
@@ -88,8 +88,7 @@ class SyncSessionTest : public testing::Test,
TEST_F(SyncSessionTest, ScopedContextHelpers) {
ConflictResolver resolver;
- SyncerEventChannel* channel = new SyncerEventChannel(
- SyncerEvent(SyncerEvent::SHUTDOWN_USE_WITH_CARE));
+ SyncerEventChannel* channel = new SyncerEventChannel();
EXPECT_FALSE(context_->resolver());
EXPECT_FALSE(context_->syncer_event_channel());
{
@@ -100,6 +99,7 @@ TEST_F(SyncSessionTest, ScopedContextHelpers) {
}
EXPECT_FALSE(context_->resolver());
EXPECT_FALSE(context_->syncer_event_channel());
+ channel->Notify(SyncerEvent(SyncerEvent::SHUTDOWN_USE_WITH_CARE));
delete channel;
}
diff --git a/chrome/browser/sync/syncable/syncable.cc b/chrome/browser/sync/syncable/syncable.cc
index ae0307c..42e4867 100644
--- a/chrome/browser/sync/syncable/syncable.cc
+++ b/chrome/browser/sync/syncable/syncable.cc
@@ -172,7 +172,6 @@ Directory::Kernel::Kernel(const FilePath& db_path,
unsynced_metahandles(new MetahandleSet),
dirty_metahandles(new MetahandleSet),
channel(new Directory::Channel(syncable::DIRECTORY_DESTROYED)),
- changes_channel(new Directory::ChangesChannel(kShutdownChangesEvent)),
info_status(Directory::KERNEL_SHARE_INFO_VALID),
persisted_info(info.kernel_info),
cache_guid(info.cache_guid),
@@ -195,7 +194,7 @@ void Directory::Kernel::Release() {
Directory::Kernel::~Kernel() {
CHECK(0 == refcount);
delete channel;
- delete changes_channel;
+ changes_channel.Notify(kShutdownChangesEvent);
delete unsynced_metahandles;
delete unapplied_update_metahandles;
delete dirty_metahandles;
@@ -898,6 +897,11 @@ void Directory::CheckTreeInvariants(syncable::BaseTransaction* trans,
// pulling entries into RAM
}
+browser_sync::ChannelHookup<DirectoryChangeEvent>* Directory::AddChangeObserver(
+ browser_sync::ChannelEventHandler<DirectoryChangeEvent>* observer) {
+ return kernel_->changes_channel.AddObserver(observer);
+}
+
///////////////////////////////////////////////////////////////////////////////
// ScopedKernelLocks
@@ -954,14 +958,14 @@ void BaseTransaction::UnlockAndLog(OriginalEntries* originals_arg) {
// Tell listeners to calculate changes while we still have the mutex.
DirectoryChangeEvent event = { DirectoryChangeEvent::CALCULATE_CHANGES,
originals.get(), this, writer_ };
- dirkernel_->changes_channel->NotifyListeners(event);
+ dirkernel_->changes_channel.Notify(event);
dirkernel_->transaction_mutex.Release();
DirectoryChangeEvent complete_event =
{ DirectoryChangeEvent::TRANSACTION_COMPLETE,
NULL, NULL, INVALID };
- dirkernel_->changes_channel->NotifyListeners(complete_event);
+ dirkernel_->changes_channel.Notify(complete_event);
}
ReadTransaction::ReadTransaction(Directory* directory, const char* file,
diff --git a/chrome/browser/sync/syncable/syncable.h b/chrome/browser/sync/syncable/syncable.h
index b6e8dca..270d2bf 100644
--- a/chrome/browser/sync/syncable/syncable.h
+++ b/chrome/browser/sync/syncable/syncable.h
@@ -27,6 +27,7 @@
#include "chrome/browser/sync/syncable/path_name_cmp.h"
#include "chrome/browser/sync/syncable/syncable_id.h"
#include "chrome/browser/sync/syncable/model_type.h"
+#include "chrome/browser/sync/util/channel.h"
#include "chrome/browser/sync/util/dbgq.h"
#include "chrome/browser/sync/util/row_iterator.h"
#include "chrome/browser/sync/util/sync_types.h"
@@ -674,6 +675,8 @@ class Directory {
TakeSnapshotGetsOnlyDirtyHandlesTest);
public:
+ class EventListenerHookup;
+
// Various data that the Directory::Kernel we are backing (persisting data
// for) needs saved across runs of the application.
struct PersistedKernelInfo {
@@ -782,6 +785,9 @@ class Directory {
// Unique to each account / client pair.
std::string cache_guid() const;
+ browser_sync::ChannelHookup<DirectoryChangeEvent>* AddChangeObserver(
+ browser_sync::ChannelEventHandler<DirectoryChangeEvent>* observer);
+
protected: // for friends, mainly used by Entry constructors
EntryKernel* GetEntryByHandle(const int64 handle);
EntryKernel* GetEntryByHandle(const int64 metahandle, ScopedKernelLock* lock);
@@ -818,7 +824,6 @@ class Directory {
};
public:
typedef EventChannel<DirectoryEventTraits, Lock> Channel;
- typedef EventChannel<DirectoryChangeEvent, Lock> ChangesChannel;
typedef std::vector<int64> ChildHandles;
// Returns the child meta handles for given parent id.
@@ -871,9 +876,6 @@ class Directory {
inline Channel* channel() const {
return kernel_->channel;
}
- inline ChangesChannel* changes_channel() const {
- return kernel_->changes_channel;
- }
// Checks tree metadata consistency.
// If full_scan is false, the function will avoid pulling any entries from the
@@ -1000,7 +1002,8 @@ class Directory {
// The changes channel mutex is explicit because it must be locked
// while holding the transaction mutex and released after
// releasing the transaction mutex.
- ChangesChannel* const changes_channel;
+ browser_sync::Channel<DirectoryChangeEvent> changes_channel;
+
Lock changes_channel_mutex;
KernelShareInfoStatus info_status;
diff --git a/chrome/browser/sync/util/channel.h b/chrome/browser/sync/util/channel.h
new file mode 100644
index 0000000..ba516b6
--- /dev/null
+++ b/chrome/browser/sync/util/channel.h
@@ -0,0 +1,140 @@
+// Copyright (c) 2010 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_UTIL_CHANNEL_H_
+#define CHROME_BROWSER_SYNC_UTIL_CHANNEL_H_
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// OVERVIEW:
+//
+// A threadsafe container for a list of observers. Observers are able to
+// remove themselves during iteration, and can be added on any thread. This
+// allows observers to safely remove themselves during notifications. It
+// also provides a handler when an observer is added that will remove the
+// observer on destruction.
+//
+// It is expected that all observers are removed before destruction.
+// The channel owner should notify all observers to disconnect on shutdown if
+// needed to ensure this.
+//
+// TYPICAL USAGE:
+//
+// class MyWidget {
+// public:
+// ...
+//
+// class Observer : public ChannelEventHandler<FooEvent> {
+// public:
+// virtual void HandleChannelEvent(const FooEvent& w) = 0;
+// };
+//
+// ChannelHookup<MyEvent>* AddObserver(Observer* obs) {
+// return channel_.AddObserver(obs);
+// }
+//
+// void RemoveObserver(Observer* obs) {
+// channel_.RemoveObserver(obs);
+// }
+//
+// void NotifyFoo(FooEvent& event) {
+// channel_.Notify(event);
+// }
+//
+// private:
+// Channel<FooEvent> channel_;
+// };
+//
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "base/lock.h"
+#include "base/observer_list.h"
+
+namespace browser_sync {
+
+template <typename EventType>
+class Channel;
+
+class EventHandler {
+};
+
+template <typename EventType>
+class ChannelEventHandler : public EventHandler {
+ public:
+ virtual void HandleChannelEvent(const EventType& event) = 0;
+};
+
+// This class manages a connection to a channel. When it is destroyed, it
+// will remove the listener from the channel observer list.
+template <typename EventType>
+class ChannelHookup {
+ public:
+ ChannelHookup(Channel<EventType>* channel,
+ browser_sync::ChannelEventHandler<EventType>* handler)
+ : channel_(channel),
+ handler_(handler) {}
+ ~ChannelHookup() {
+ channel_->RemoveObserver(handler_);
+ }
+
+ private:
+ Channel<EventType>* channel_;
+ browser_sync::ChannelEventHandler<EventType>* handler_;
+};
+
+template <typename EventType>
+class Channel {
+ public:
+ typedef ObserverListBase<EventHandler> ChannelObserverList;
+
+ Channel() : locking_thread_(0) {}
+
+ ChannelHookup<EventType>* AddObserver(
+ ChannelEventHandler<EventType>* observer) {
+ AutoLock scoped_lock(event_handlers_mutex_);
+ event_handlers_.AddObserver(observer);
+ return new ChannelHookup<EventType>(this, observer);
+ }
+
+ void RemoveObserver(ChannelEventHandler<EventType>* observer) {
+ // This can be called in response to a notification, so we may already have
+ // locked this channel on this thread.
+ bool need_lock = (locking_thread_ != PlatformThread::CurrentId());
+ if (need_lock)
+ event_handlers_mutex_.Acquire();
+
+ event_handlers_mutex_.AssertAcquired();
+ event_handlers_.RemoveObserver(observer);
+ if (need_lock)
+ event_handlers_mutex_.Release();
+ }
+
+ void Notify(const EventType& event) {
+ AutoLock scoped_lock(event_handlers_mutex_);
+
+ // This may result in an observer trying to remove itself, so keep track
+ // of the thread we're locked on.
+ locking_thread_ = PlatformThread::CurrentId();
+
+ ChannelObserverList::Iterator it(event_handlers_);
+ EventHandler* obs;
+ while ((obs = it.GetNext()) != NULL) {
+ static_cast<ChannelEventHandler<EventType>* >(obs)->
+ HandleChannelEvent(event);
+ }
+
+ // Set back to an invalid thread id.
+ locking_thread_ = 0;
+ }
+
+ private:
+ Lock event_handlers_mutex_;
+ PlatformThreadId locking_thread_;
+ ObserverList<EventHandler> event_handlers_;
+};
+
+} // namespace browser_sync
+
+#endif // CHROME_BROWSER_SYNC_UTIL_CHANNEL_H_
diff --git a/chrome/browser/sync/util/channel_unittest.cc b/chrome/browser/sync/util/channel_unittest.cc
new file mode 100644
index 0000000..f2317dc
--- /dev/null
+++ b/chrome/browser/sync/util/channel_unittest.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 2010 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 "chrome/browser/sync/util/channel.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+struct TestEvent {
+ explicit TestEvent(int foo) : data(foo) {}
+ int data;
+};
+
+class TestObserver : public browser_sync::ChannelEventHandler<TestEvent> {
+ public:
+ virtual void HandleChannelEvent(const TestEvent& event) {
+ delete hookup;
+ hookup = 0;
+ }
+
+ browser_sync::ChannelHookup<TestEvent>* hookup;
+};
+
+TEST(ChannelTest, RemoveOnNotify) {
+ browser_sync::Channel<TestEvent> channel;
+ TestObserver observer;
+
+ observer.hookup = channel.AddObserver(&observer);
+
+ ASSERT_TRUE(0 != observer.hookup);
+ channel.Notify(TestEvent(1));
+ ASSERT_EQ(0, observer.hookup);
+}
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index 267966f..f17ec10 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -900,6 +900,7 @@
'browser/sync/syncable/syncable_columns.h',
'browser/sync/syncable/syncable_id.cc',
'browser/sync/syncable/syncable_id.h',
+ 'browser/sync/util/channel.h',
'browser/sync/util/character_set_converters.h',
'browser/sync/util/character_set_converters_posix.cc',
'browser/sync/util/character_set_converters_win.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 49690b4..50c785c 100755
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1851,6 +1851,7 @@
'browser/sync/syncable/directory_backing_store_unittest.cc',
'browser/sync/syncable/syncable_id_unittest.cc',
'browser/sync/syncable/syncable_unittest.cc',
+ 'browser/sync/util/channel_unittest.cc',
'browser/sync/util/crypto_helpers_unittest.cc',
'browser/sync/util/extensions_activity_monitor_unittest.cc',
'browser/sync/util/user_settings_unittest.cc',