Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6861)

Unified Diff: chrome/browser/sync/engine/syncapi.cc

Issue 7044059: [Sync] Ensure all accesses to SyncInternal's observers are thread safe. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: fix Created 9 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | tools/valgrind/tsan/suppressions.txt » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/sync/engine/syncapi.cc
diff --git a/chrome/browser/sync/engine/syncapi.cc b/chrome/browser/sync/engine/syncapi.cc
index 3546df4da92605e92423f708b6ed00cf3a873014..5d84638fb9ed148c307e41c470d512f8c9687c44 100644
--- a/chrome/browser/sync/engine/syncapi.cc
+++ b/chrome/browser/sync/engine/syncapi.cc
@@ -1237,6 +1237,8 @@ class SyncManager::SyncInternal
virtual void StoreState(const std::string& cookie);
+ bool HaveObservers();
akalin 2011/06/08 22:39:38 make const
Nicolas Zea 2011/06/08 23:10:23 Done.
+
void AddObserver(SyncManager::Observer* observer);
void RemoveObserver(SyncManager::Observer* observer);
@@ -1527,6 +1529,9 @@ class SyncManager::SyncInternal
MessageLoop* core_message_loop_;
+ // We have to lock around every observers_ access because it can get accessed
+ // from any thread and added to/removed from on the core thread.
+ base::Lock observers_lock_;
akalin 2011/06/08 22:39:38 make mutable
Nicolas Zea 2011/06/08 23:10:23 Done.
ObserverList<SyncManager::Observer> observers_;
browser_sync::JsEventRouter* parent_router_;
@@ -1588,6 +1593,22 @@ class SyncManager::SyncInternal
const int SyncManager::SyncInternal::kDefaultNudgeDelayMilliseconds = 200;
const int SyncManager::SyncInternal::kPreferencesNudgeDelayMilliseconds = 2000;
+// We have to read the current observer list while holding a lock because it
+// can be added/removed from another thread. We then notify the actual observers
+// while the lock is released.
akalin 2011/06/08 22:39:38 Add a TODO explaining the problem with notifying g
Nicolas Zea 2011/06/08 23:10:23 Done.
+#define NOTIFY_SYNCMANAGER_OBSERVERS(function) \
akalin 2011/06/08 22:39:38 I think it would be cleaner to define a utility fu
Nicolas Zea 2011/06/08 23:10:23 Done.
+ do { \
+ ObserverList<SyncManager::Observer> temp_observers; \
+ { \
+ base::AutoLock lock(observers_lock_); \
+ ObserverListBase<SyncManager::Observer>::Iterator it(observers_); \
+ SyncManager::Observer* obs; \
+ while ((obs = it.GetNext()) != NULL) \
+ temp_observers.AddObserver(obs); \
+ } \
+ FOR_EACH_OBSERVER(SyncManager::Observer, temp_observers, function); \
+ } while (0)
+
SyncManager::Observer::~Observer() {}
SyncManager::SyncManager() {
@@ -1808,8 +1829,8 @@ void SyncManager::SyncInternal::BootstrapEncryption(
nigori.CopyFrom(node.GetNigoriSpecifics());
Cryptographer::UpdateResult result = cryptographer->Update(nigori);
if (result == Cryptographer::NEEDS_PASSPHRASE) {
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnPassphraseRequired(sync_api::REASON_DECRYPTION));
+ NOTIFY_SYNCMANAGER_OBSERVERS(
+ OnPassphraseRequired(sync_api::REASON_DECRYPTION));
}
// Refresh list of encrypted datatypes.
@@ -1823,10 +1844,10 @@ void SyncManager::SyncInternal::BootstrapEncryption(
}
void SyncManager::SyncInternal::StartSyncingNormally() {
- // Start the syncer thread. This won't actually
- // result in any syncing until at least the
- // DirectoryManager broadcasts the OPENED event,
- // and a valid server connection is detected.
+ // Start the syncer thread. This won't actually
+ // result in any syncing until at least the
+ // DirectoryManager broadcasts the OPENED event,
+ // and a valid server connection is detected.
if (syncer_thread()) // NULL during certain unittests.
syncer_thread()->Start(SyncerThread::NORMAL_MODE, NULL);
}
@@ -1845,8 +1866,7 @@ void SyncManager::SyncInternal::MarkAndNotifyInitializationComplete() {
}
// Notify that initialization is complete.
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnInitializationComplete());
+ NOTIFY_SYNCMANAGER_OBSERVERS(OnInitializationComplete());
}
void SyncManager::SyncInternal::SendNotification() {
@@ -1864,8 +1884,7 @@ bool SyncManager::SyncInternal::OpenDirectory() {
bool share_opened = dir_manager()->Open(username_for_share());
DCHECK(share_opened);
if (!share_opened) {
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnStopSyncingPermanently());
+ NOTIFY_SYNCMANAGER_OBSERVERS(OnStopSyncingPermanently());
LOG(ERROR) << "Could not open share for:" << username_for_share();
return false;
@@ -1949,8 +1968,7 @@ void SyncManager::SyncInternal::UpdateEnabledTypes() {
}
void SyncManager::SyncInternal::RaiseAuthNeededEvent() {
- FOR_EACH_OBSERVER(
- SyncManager::Observer, observers_,
+ NOTIFY_SYNCMANAGER_OBSERVERS(
OnAuthError(AuthError(AuthError::INVALID_GAIA_CREDENTIALS)));
}
@@ -1972,7 +1990,7 @@ void SyncManager::SyncInternal::SetPassphrase(
// We do not accept empty passphrases.
if (passphrase.empty()) {
VLOG(1) << "Rejecting empty passphrase.";
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
+ NOTIFY_SYNCMANAGER_OBSERVERS(
OnPassphraseRequired(sync_api::REASON_SET_PASSPHRASE_FAILED));
return;
}
@@ -1985,7 +2003,7 @@ void SyncManager::SyncInternal::SetPassphrase(
if (cryptographer->has_pending_keys()) {
if (!cryptographer->DecryptPendingKeys(params)) {
VLOG(1) << "Passphrase failed to decrypt pending keys.";
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
+ NOTIFY_SYNCMANAGER_OBSERVERS(
OnPassphraseRequired(sync_api::REASON_SET_PASSPHRASE_FAILED));
return;
}
@@ -2031,8 +2049,7 @@ void SyncManager::SyncInternal::SetPassphrase(
std::string bootstrap_token;
cryptographer->GetBootstrapToken(&bootstrap_token);
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnPassphraseAccepted(bootstrap_token));
+ NOTIFY_SYNCMANAGER_OBSERVERS(OnPassphraseAccepted(bootstrap_token));
}
bool SyncManager::SyncInternal::IsUsingExplicitPassphrase() {
@@ -2150,8 +2167,7 @@ void SyncManager::SyncInternal::ReEncryptEverything(WriteTransaction* trans) {
}
}
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnEncryptionComplete(encrypted_types));
+ NOTIFY_SYNCMANAGER_OBSERVERS(OnEncryptionComplete(encrypted_types));
}
SyncManager::~SyncManager() {
@@ -2244,13 +2260,11 @@ void SyncManager::SyncInternal::OnServerConnectionEvent(
allstatus_.HandleServerConnectionEvent(event);
if (event.connection_code ==
browser_sync::HttpResponse::SERVER_CONNECTION_OK) {
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnAuthError(AuthError::None()));
+ NOTIFY_SYNCMANAGER_OBSERVERS(OnAuthError(AuthError::None()));
}
if (event.connection_code == browser_sync::HttpResponse::SYNC_AUTH_ERROR) {
- FOR_EACH_OBSERVER(
- SyncManager::Observer, observers_,
+ NOTIFY_SYNCMANAGER_OBSERVERS(
OnAuthError(AuthError(AuthError::INVALID_GAIA_CREDENTIALS)));
}
}
@@ -2260,14 +2274,14 @@ void SyncManager::SyncInternal::HandleTransactionCompleteChangeEvent(
// This notification happens immediately after the transaction mutex is
// released. This allows work to be performed without blocking other threads
// from acquiring a transaction.
- if (observers_.size() <= 0)
+ if (!HaveObservers())
return;
// Call commit.
for (int i = 0; i < syncable::MODEL_TYPE_COUNT; ++i) {
if (models_with_changes.test(i)) {
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnChangesComplete(syncable::ModelTypeFromInt(i)));
+ NOTIFY_SYNCMANAGER_OBSERVERS(
+ OnChangesComplete(syncable::ModelTypeFromInt(i)));
}
}
}
@@ -2277,7 +2291,7 @@ ModelTypeBitSet SyncManager::SyncInternal::HandleTransactionEndingChangeEvent(
// This notification happens immediately before a syncable WriteTransaction
// falls out of scope. It happens while the channel mutex is still held,
// and while the transaction mutex is held, so it cannot be re-entrant.
- if (observers_.size() <= 0 || ChangeBuffersAreEmpty())
+ if (!HaveObservers() || ChangeBuffersAreEmpty())
return ModelTypeBitSet();
// This will continue the WriteTransaction using a read only wrapper.
@@ -2294,8 +2308,7 @@ ModelTypeBitSet SyncManager::SyncInternal::HandleTransactionEndingChangeEvent(
vector<ChangeRecord> ordered_changes;
change_buffers_[i].GetAllChangesInTreeOrder(&read_trans, &ordered_changes);
if (!ordered_changes.empty()) {
- FOR_EACH_OBSERVER(
- SyncManager::Observer, observers_,
+ NOTIFY_SYNCMANAGER_OBSERVERS(
OnChangesApplied(syncable::ModelTypeFromInt(i), &read_trans,
&ordered_changes[0], ordered_changes.size()));
models_with_changes.set(i, true);
@@ -2444,7 +2457,7 @@ void SyncManager::SyncInternal::RequestNudgeWithDataTypes(
void SyncManager::SyncInternal::OnSyncEngineEvent(
const SyncEngineEvent& event) {
- if (observers_.size() <= 0) {
+ if (!HaveObservers()) {
VLOG(0) << "OnSyncEngineEvent returning because observers_.size() is zero";
return;
}
@@ -2492,13 +2505,13 @@ void SyncManager::SyncInternal::OnSyncEngineEvent(
// yet, prompt the user for a passphrase.
if (cryptographer->has_pending_keys()) {
VLOG(1) << "OnPassPhraseRequired Sent";
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnPassphraseRequired(sync_api::REASON_DECRYPTION));
+ NOTIFY_SYNCMANAGER_OBSERVERS(
+ OnPassphraseRequired(sync_api::REASON_DECRYPTION));
} else if (!cryptographer->is_ready()) {
VLOG(1) << "OnPassphraseRequired sent because cryptographer is not "
<< "ready";
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnPassphraseRequired(sync_api::REASON_ENCRYPTION));
+ NOTIFY_SYNCMANAGER_OBSERVERS(
+ OnPassphraseRequired(sync_api::REASON_ENCRYPTION));
}
// If everything is in order(we have the passphrase) then there is no
// need to inform the listeners. They will just wait for sync
@@ -2515,8 +2528,7 @@ void SyncManager::SyncInternal::OnSyncEngineEvent(
if (!event.snapshot->has_more_to_sync) {
VLOG(1) << "OnSyncCycleCompleted sent";
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnSyncCycleCompleted(event.snapshot));
+ NOTIFY_SYNCMANAGER_OBSERVERS(OnSyncCycleCompleted(event.snapshot));
}
// This is here for tests, which are still using p2p notifications.
@@ -2537,26 +2549,22 @@ void SyncManager::SyncInternal::OnSyncEngineEvent(
}
if (event.what_happened == SyncEngineEvent::STOP_SYNCING_PERMANENTLY) {
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnStopSyncingPermanently());
+ NOTIFY_SYNCMANAGER_OBSERVERS(OnStopSyncingPermanently());
return;
}
if (event.what_happened == SyncEngineEvent::CLEAR_SERVER_DATA_SUCCEEDED) {
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnClearServerDataSucceeded());
+ NOTIFY_SYNCMANAGER_OBSERVERS(OnClearServerDataSucceeded());
return;
}
if (event.what_happened == SyncEngineEvent::CLEAR_SERVER_DATA_FAILED) {
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnClearServerDataFailed());
+ NOTIFY_SYNCMANAGER_OBSERVERS(OnClearServerDataFailed());
return;
}
if (event.what_happened == SyncEngineEvent::UPDATED_TOKEN) {
- FOR_EACH_OBSERVER(SyncManager::Observer, observers_,
- OnUpdatedToken(event.updated_token));
+ NOTIFY_SYNCMANAGER_OBSERVERS(OnUpdatedToken(event.updated_token));
return;
}
}
@@ -2860,13 +2868,20 @@ void SyncManager::SyncInternal::StoreState(
lookup->SaveChanges();
}
+bool SyncManager::SyncInternal::HaveObservers() {
+ base::AutoLock lock(observers_lock_);
+ return observers_.size() > 0;
+}
+
void SyncManager::SyncInternal::AddObserver(
SyncManager::Observer* observer) {
+ base::AutoLock lock(observers_lock_);
observers_.AddObserver(observer);
}
void SyncManager::SyncInternal::RemoveObserver(
SyncManager::Observer* observer) {
+ base::AutoLock lock(observers_lock_);
observers_.RemoveObserver(observer);
}
« no previous file with comments | « no previous file | tools/valgrind/tsan/suppressions.txt » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698