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

Side by Side Diff: chrome/browser/sync/syncable/syncable.cc

Issue 7046067: [Sync] Fix use of ObserverList by multiple threads. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: sync to head 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/sync/syncable/syncable.h ('k') | tools/valgrind/tsan/suppressions.txt » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/sync/syncable/syncable.h" 5 #include "chrome/browser/sync/syncable/syncable.h"
6 6
7 #include "build/build_config.h" 7 #include "build/build_config.h"
8 8
9 #include <sys/stat.h> 9 #include <sys/stat.h>
10 #if defined(OS_POSIX) 10 #if defined(OS_POSIX)
(...skipping 366 matching lines...) Expand 10 before | Expand all | Expand 10 after
377 377
378 void Directory::Kernel::AddRef() { 378 void Directory::Kernel::AddRef() {
379 base::subtle::NoBarrier_AtomicIncrement(&refcount, 1); 379 base::subtle::NoBarrier_AtomicIncrement(&refcount, 1);
380 } 380 }
381 381
382 void Directory::Kernel::Release() { 382 void Directory::Kernel::Release() {
383 if (!base::subtle::NoBarrier_AtomicIncrement(&refcount, -1)) 383 if (!base::subtle::NoBarrier_AtomicIncrement(&refcount, -1))
384 delete this; 384 delete this;
385 } 385 }
386 386
387 void Directory::Kernel::AddChangeListener(
388 DirectoryChangeListener* listener) {
389 base::AutoLock lock(change_listeners_lock_);
390 change_listeners_.AddObserver(listener);
391 }
392
393 void Directory::Kernel::RemoveChangeListener(
394 DirectoryChangeListener* listener) {
395 base::AutoLock lock(change_listeners_lock_);
396 change_listeners_.RemoveObserver(listener);
397 }
398
399 // Note: it is possible that a listener will remove itself after we
400 // have made a copy, but before the copy is consumed. This could
401 // theoretically result in accessing a garbage pointer, but can only
402 // occur when an about:sync window is closed in the middle of a
403 // notification. See crbug.com/85481.
404 void Directory::Kernel::CopyChangeListeners(
405 ObserverList<DirectoryChangeListener>* change_listeners) {
406 DCHECK_EQ(0U, change_listeners->size());
407 base::AutoLock lock(change_listeners_lock_);
408 ObserverListBase<DirectoryChangeListener>::Iterator it(change_listeners_);
409 DirectoryChangeListener* obs;
410 while ((obs = it.GetNext()) != NULL)
411 change_listeners->AddObserver(obs);
412 }
413
387 Directory::Kernel::~Kernel() { 414 Directory::Kernel::~Kernel() {
388 CHECK_EQ(0, refcount); 415 CHECK_EQ(0, refcount);
389 delete channel; 416 delete channel;
390 delete unsynced_metahandles; 417 delete unsynced_metahandles;
391 delete unapplied_update_metahandles; 418 delete unapplied_update_metahandles;
392 delete dirty_metahandles; 419 delete dirty_metahandles;
393 delete metahandles_to_purge; 420 delete metahandles_to_purge;
394 delete parent_id_child_index; 421 delete parent_id_child_index;
395 delete client_tag_index; 422 delete client_tag_index;
396 delete ids_index; 423 delete ids_index;
(...skipping 756 matching lines...) Expand 10 before | Expand all | Expand 10 after
1153 if (elapsed_ms > max_ms) { 1180 if (elapsed_ms > max_ms) {
1154 VLOG(1) << "Cutting Invariant check short after " << elapsed_ms 1181 VLOG(1) << "Cutting Invariant check short after " << elapsed_ms
1155 << "ms. Processed " << entries_done << "/" << handles.size() 1182 << "ms. Processed " << entries_done << "/" << handles.size()
1156 << " entries"; 1183 << " entries";
1157 return; 1184 return;
1158 } 1185 }
1159 } 1186 }
1160 } 1187 }
1161 1188
1162 void Directory::AddChangeListener(DirectoryChangeListener* listener) { 1189 void Directory::AddChangeListener(DirectoryChangeListener* listener) {
1163 kernel_->change_listeners_.AddObserver(listener); 1190 kernel_->AddChangeListener(listener);
1164 } 1191 }
1165 1192
1166 void Directory::RemoveChangeListener(DirectoryChangeListener* listener) { 1193 void Directory::RemoveChangeListener(DirectoryChangeListener* listener) {
1167 kernel_->change_listeners_.RemoveObserver(listener); 1194 kernel_->RemoveChangeListener(listener);
1168 } 1195 }
1169 1196
1170 /////////////////////////////////////////////////////////////////////////////// 1197 ///////////////////////////////////////////////////////////////////////////////
1171 // ScopedKernelLock 1198 // ScopedKernelLock
1172 1199
1173 ScopedKernelLock::ScopedKernelLock(const Directory* dir) 1200 ScopedKernelLock::ScopedKernelLock(const Directory* dir)
1174 : scoped_lock_(dir->kernel_->mutex), dir_(const_cast<Directory*>(dir)) { 1201 : scoped_lock_(dir->kernel_->mutex), dir_(const_cast<Directory*>(dir)) {
1175 } 1202 }
1176 1203
1177 /////////////////////////////////////////////////////////////////////////// 1204 ///////////////////////////////////////////////////////////////////////////
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
1231 const base::TimeDelta elapsed = base::TimeTicks::Now() - time_acquired_; 1258 const base::TimeDelta elapsed = base::TimeTicks::Now() - time_acquired_;
1232 if (LOG_IS_ON(INFO) && 1259 if (LOG_IS_ON(INFO) &&
1233 (1 <= logging::GetVlogLevelHelper( 1260 (1 <= logging::GetVlogLevelHelper(
1234 source_file_, ::strlen(source_file_))) && 1261 source_file_, ::strlen(source_file_))) &&
1235 (elapsed.InMilliseconds() > 50)) { 1262 (elapsed.InMilliseconds() > 50)) {
1236 logging::LogMessage(source_file_, line_, logging::LOG_INFO).stream() 1263 logging::LogMessage(source_file_, line_, logging::LOG_INFO).stream()
1237 << name_ << " transaction completed in " << elapsed.InSecondsF() 1264 << name_ << " transaction completed in " << elapsed.InSecondsF()
1238 << " seconds."; 1265 << " seconds.";
1239 } 1266 }
1240 1267
1268 ObserverList<DirectoryChangeListener> change_listeners;
1269 dirkernel_->CopyChangeListeners(&change_listeners);
1270
1241 if (NULL == originals.get() || originals->empty() || 1271 if (NULL == originals.get() || originals->empty() ||
1242 (dirkernel_->change_listeners_.size() == 0)) { 1272 (change_listeners.size() == 0)) {
1243 dirkernel_->transaction_mutex.Release(); 1273 dirkernel_->transaction_mutex.Release();
1244 return false; 1274 return false;
1245 } 1275 }
1246 1276
1247 if (writer_ == syncable::SYNCAPI) { 1277 if (writer_ == syncable::SYNCAPI) {
1248 FOR_EACH_OBSERVER(DirectoryChangeListener, 1278 FOR_EACH_OBSERVER(DirectoryChangeListener,
1249 dirkernel_->change_listeners_, 1279 change_listeners,
1250 HandleCalculateChangesChangeEventFromSyncApi( 1280 HandleCalculateChangesChangeEventFromSyncApi(
1251 *originals.get(), 1281 *originals.get(),
1252 writer_, 1282 writer_,
1253 this)); 1283 this));
1254 } else { 1284 } else {
1255 FOR_EACH_OBSERVER(DirectoryChangeListener, 1285 FOR_EACH_OBSERVER(DirectoryChangeListener,
1256 dirkernel_->change_listeners_, 1286 change_listeners,
1257 HandleCalculateChangesChangeEventFromSyncer( 1287 HandleCalculateChangesChangeEventFromSyncer(
1258 *originals.get(), 1288 *originals.get(),
1259 writer_, 1289 writer_,
1260 this)); 1290 this));
1261 } 1291 }
1262 1292
1263 // Set |*models_with_changes| to the union of the return values of 1293 // Set |*models_with_changes| to the union of the return values of
1264 // the HandleTransactionEndingChangeEvent call to each 1294 // the HandleTransactionEndingChangeEvent call to each
1265 // DirectoryChangeListener. 1295 // DirectoryChangeListener.
1266 { 1296 {
1267 ObserverList<DirectoryChangeListener>::Iterator it( 1297 ObserverList<DirectoryChangeListener>::Iterator it(change_listeners);
1268 dirkernel_->change_listeners_);
1269 DirectoryChangeListener* obs = NULL; 1298 DirectoryChangeListener* obs = NULL;
1270 while ((obs = it.GetNext()) != NULL) { 1299 while ((obs = it.GetNext()) != NULL) {
1271 *models_with_changes |= obs->HandleTransactionEndingChangeEvent(this); 1300 *models_with_changes |= obs->HandleTransactionEndingChangeEvent(this);
1272 } 1301 }
1273 }; 1302 };
1274 1303
1275 // Release the transaction. Note, once the transaction is released this thread 1304 // Release the transaction. Note, once the transaction is released this thread
1276 // can be interrupted by another that was waiting for the transaction, 1305 // can be interrupted by another that was waiting for the transaction,
1277 // resulting in this code possibly being interrupted with another thread 1306 // resulting in this code possibly being interrupted with another thread
1278 // performing following the same code path. From this point foward, only 1307 // performing following the same code path. From this point foward, only
1279 // local state can be touched. 1308 // local state can be touched.
1280 dirkernel_->transaction_mutex.Release(); 1309 dirkernel_->transaction_mutex.Release();
1281 return true; 1310 return true;
1282 } 1311 }
1283 1312
1284 void BaseTransaction::NotifyTransactionComplete( 1313 void BaseTransaction::NotifyTransactionComplete(
1285 ModelTypeBitSet models_with_changes) { 1314 ModelTypeBitSet models_with_changes) {
1286 FOR_EACH_OBSERVER(DirectoryChangeListener, 1315 ObserverList<DirectoryChangeListener> change_listeners;
1287 dirkernel_->change_listeners_, 1316 dirkernel_->CopyChangeListeners(&change_listeners);
1288 HandleTransactionCompleteChangeEvent( 1317 FOR_EACH_OBSERVER(DirectoryChangeListener,
1289 models_with_changes)); 1318 change_listeners,
1319 HandleTransactionCompleteChangeEvent(
1320 models_with_changes));
1290 } 1321 }
1291 1322
1292 ReadTransaction::ReadTransaction(Directory* directory, const char* file, 1323 ReadTransaction::ReadTransaction(Directory* directory, const char* file,
1293 int line) 1324 int line)
1294 : BaseTransaction(directory, "Read", file, line, INVALID) { 1325 : BaseTransaction(directory, "Read", file, line, INVALID) {
1295 } 1326 }
1296 1327
1297 ReadTransaction::ReadTransaction(const ScopedDirLookup& scoped_dir, 1328 ReadTransaction::ReadTransaction(const ScopedDirLookup& scoped_dir,
1298 const char* file, int line) 1329 const char* file, int line)
1299 : BaseTransaction(scoped_dir.operator -> (), "Read", file, line, INVALID) { 1330 : BaseTransaction(scoped_dir.operator -> (), "Read", file, line, INVALID) {
(...skipping 701 matching lines...) Expand 10 before | Expand all | Expand 10 after
2001 CHECK(result); 2032 CHECK(result);
2002 for (iterator i = GetParentChildIndexLowerBound(lock, parent_id), 2033 for (iterator i = GetParentChildIndexLowerBound(lock, parent_id),
2003 end = GetParentChildIndexUpperBound(lock, parent_id); 2034 end = GetParentChildIndexUpperBound(lock, parent_id);
2004 i != end; ++i) { 2035 i != end; ++i) {
2005 DCHECK_EQ(parent_id, (*i)->ref(PARENT_ID)); 2036 DCHECK_EQ(parent_id, (*i)->ref(PARENT_ID));
2006 result->push_back((*i)->ref(META_HANDLE)); 2037 result->push_back((*i)->ref(META_HANDLE));
2007 } 2038 }
2008 } 2039 }
2009 2040
2010 } // namespace syncable 2041 } // namespace syncable
OLDNEW
« no previous file with comments | « chrome/browser/sync/syncable/syncable.h ('k') | tools/valgrind/tsan/suppressions.txt » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698