1b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Use of this source code is governed by a BSD-style license that can be 3b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// found in the LICENSE file. 4b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 5b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/threading/thread_collision_warner.h" 6b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 7b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/logging.h" 8b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/threading/platform_thread.h" 9b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 10b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace base { 11b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 12b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid DCheckAsserter::warn() { 13b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat NOTREACHED() << "Thread Collision"; 14b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 15b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 16b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratstatic subtle::Atomic32 CurrentThread() { 17b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const PlatformThreadId current_thread_id = PlatformThread::CurrentId(); 18b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // We need to get the thread id into an atomic data type. This might be a 19b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // truncating conversion, but any loss-of-information just increases the 20b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // chance of a fault negative, not a false positive. 21b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const subtle::Atomic32 atomic_thread_id = 22b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat static_cast<subtle::Atomic32>(current_thread_id); 23b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 24b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat return atomic_thread_id; 25b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 26b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 27b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ThreadCollisionWarner::EnterSelf() { 28b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // If the active thread is 0 then I'll write the current thread ID 29b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // if two or more threads arrive here only one will succeed to 30b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // write on valid_thread_id_ the current thread ID. 31b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat subtle::Atomic32 current_thread_id = CurrentThread(); 32b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 33b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat int previous_value = subtle::NoBarrier_CompareAndSwap(&valid_thread_id_, 34b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 0, 35b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat current_thread_id); 36b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (previous_value != 0 && previous_value != current_thread_id) { 37b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // gotcha! a thread is trying to use the same class and that is 38b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // not current thread. 39b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat asserter_->warn(); 40b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 41b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 42b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat subtle::NoBarrier_AtomicIncrement(&counter_, 1); 43b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 44b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 45b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ThreadCollisionWarner::Enter() { 46b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat subtle::Atomic32 current_thread_id = CurrentThread(); 47b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 48b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (subtle::NoBarrier_CompareAndSwap(&valid_thread_id_, 49b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 0, 50b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat current_thread_id) != 0) { 51b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // gotcha! another thread is trying to use the same class. 52b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat asserter_->warn(); 53b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 54b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 55b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat subtle::NoBarrier_AtomicIncrement(&counter_, 1); 56b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 57b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 58b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratvoid ThreadCollisionWarner::Leave() { 59b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat if (subtle::Barrier_AtomicIncrement(&counter_, -1) == 0) { 60b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat subtle::NoBarrier_Store(&valid_thread_id_, 0); 61b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 62b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} 63b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 64b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace base 65