Commit 1ade3f86 authored by wez@chromium.org's avatar wez@chromium.org

Remove all but one use of WeakPtrFactory::DetachFromThread.

This CL changes WeakPtr in the following ways:
* Changes thread-bindings semantics so that WeakPtrs only become bound when the first one is dereferenced, or the owning factory invalidates them.
* Removes WeakPtrFactory::DetachFromThread.
* Renames SupportsWeakPtr::DetachFromThread  to DetachFromThreadHack.

Calling code changes to allow this:
* Unnecessary DetachFromThread() calls removed from PluginInfoMessageFilter, DhcpProxyScript[Adapter]FetcherWin and (Chromoting's) PolicyWatcherLinux.
* DetachFromThread() calls rendered unnecessary by change in binding semantics removed from IOThread, SearchProviderInstallData, RuleRegistryWithCache and GLSurfaceGlx.

WebGraphicsContext3DInProcessCommandBufferImpl uses the re-named DetachFromThreadHack() - bug 234964 tracks work to remove that use.

BUG=232143, 234964

Review URL: https://chromiumcodereview.appspot.com/14299011

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@202038 0039d316-1c4b-4281-b951-d872f2087c98
parent 1c98fddc
...@@ -8,17 +8,23 @@ namespace base { ...@@ -8,17 +8,23 @@ namespace base {
namespace internal { namespace internal {
WeakReference::Flag::Flag() : is_valid_(true) { WeakReference::Flag::Flag() : is_valid_(true) {
// Flags only become bound when checked for validity, or invalidated,
// so that we can check that later validity/invalidation operations on
// the same Flag take place on the same thread.
thread_checker_.DetachFromThread();
} }
void WeakReference::Flag::Invalidate() { void WeakReference::Flag::Invalidate() {
// The flag being invalidated with a single ref implies that there are no // The flag being invalidated with a single ref implies that there are no
// weak pointers in existence. Allow deletion on other thread in this case. // weak pointers in existence. Allow deletion on other thread in this case.
DCHECK(thread_checker_.CalledOnValidThread() || HasOneRef()); DCHECK(thread_checker_.CalledOnValidThread() || HasOneRef())
<< "WeakPtrs must be checked and invalidated on the same thread.";
is_valid_ = false; is_valid_ = false;
} }
bool WeakReference::Flag::IsValid() const { bool WeakReference::Flag::IsValid() const {
DCHECK(thread_checker_.CalledOnValidThread()); DCHECK(thread_checker_.CalledOnValidThread())
<< "WeakPtrs must be checked and invalidated on the same thread.";
return is_valid_; return is_valid_;
} }
...@@ -46,10 +52,10 @@ WeakReferenceOwner::~WeakReferenceOwner() { ...@@ -46,10 +52,10 @@ WeakReferenceOwner::~WeakReferenceOwner() {
} }
WeakReference WeakReferenceOwner::GetRef() const { WeakReference WeakReferenceOwner::GetRef() const {
// We also want to reattach to the current thread if all previous references // If we hold the last reference to the Flag then create a new one.
// have gone away.
if (!HasRefs()) if (!HasRefs())
flag_ = new WeakReference::Flag(); flag_ = new WeakReference::Flag();
return WeakReference(flag_); return WeakReference(flag_);
} }
......
...@@ -19,6 +19,9 @@ ...@@ -19,6 +19,9 @@
// void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); } // void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); }
// void WorkComplete(const Result& result) { ... } // void WorkComplete(const Result& result) { ... }
// private: // private:
// // Member variables should appear before the WeakPtrFactory, to ensure
// // that any WeakPtrs to Controller are invalidated before its members
// // variable's destructors are executed, rendering them invalid.
// WeakPtrFactory<Controller> weak_factory_; // WeakPtrFactory<Controller> weak_factory_;
// }; // };
// //
...@@ -44,17 +47,18 @@ ...@@ -44,17 +47,18 @@
// ------------------------- IMPORTANT: Thread-safety ------------------------- // ------------------------- IMPORTANT: Thread-safety -------------------------
// Weak pointers must always be dereferenced and invalidated on the same thread // Weak pointers may be passed safely between threads, but must always be
// otherwise checking the pointer would be racey. WeakPtrFactory enforces this // dereferenced and invalidated on the same thread otherwise checking the
// by binding itself to the current thread when a WeakPtr is first created // pointer would be racey.
// and un-binding only when those pointers are invalidated. WeakPtrs may still //
// be handed off to other threads, however, so long as they are only actually // To ensure correct use, the first time a WeakPtr issued by a WeakPtrFactory
// dereferenced on the originating thread. This includes posting tasks to the // is dereferenced, the factory and its WeakPtrs become bound to the calling
// thread using base::Bind() to invoke a method on the object via the WeakPtr. // thread, and cannot be dereferenced or invalidated on any other thread. Bound
// WeakPtrs can still be handed off to other threads, e.g. to use to post tasks
// Calling SupportsWeakPtr::DetachFromThread() can work around the limitations // back to object on the bound thread.
// above and cancel the thread binding of the object and all WeakPtrs pointing //
// to it, but it's not recommended and unsafe. See crbug.com/232143. // Invalidating the factory's WeakPtrs un-binds it from the thread, allowing it
// to be passed for a different thread to use or delete it.
#ifndef BASE_MEMORY_WEAK_PTR_H_ #ifndef BASE_MEMORY_WEAK_PTR_H_
#define BASE_MEMORY_WEAK_PTR_H_ #define BASE_MEMORY_WEAK_PTR_H_
...@@ -77,7 +81,7 @@ namespace internal { ...@@ -77,7 +81,7 @@ namespace internal {
class BASE_EXPORT WeakReference { class BASE_EXPORT WeakReference {
public: public:
// While Flag is bound to a specific thread, it may be deleted from another // Although Flag is bound to a specific thread, it may be deleted from another
// via base::WeakPtr::~WeakPtr(). // via base::WeakPtr::~WeakPtr().
class Flag : public RefCountedThreadSafe<Flag> { class Flag : public RefCountedThreadSafe<Flag> {
public: public:
...@@ -86,7 +90,8 @@ class BASE_EXPORT WeakReference { ...@@ -86,7 +90,8 @@ class BASE_EXPORT WeakReference {
void Invalidate(); void Invalidate();
bool IsValid() const; bool IsValid() const;
void DetachFromThread() { thread_checker_.DetachFromThread(); } // Remove this when crbug.com/234964 is addressed.
void DetachFromThreadHack() { thread_checker_.DetachFromThread(); }
private: private:
friend class base::RefCountedThreadSafe<Flag>; friend class base::RefCountedThreadSafe<Flag>;
...@@ -120,10 +125,9 @@ class BASE_EXPORT WeakReferenceOwner { ...@@ -120,10 +125,9 @@ class BASE_EXPORT WeakReferenceOwner {
void Invalidate(); void Invalidate();
// Indicates that this object will be used on another thread from now on. // Remove this when crbug.com/234964 is addressed.
// Do not use this in new code. See crbug.com/232143. void DetachFromThreadHack() {
void DetachFromThread() { if (flag_) flag_->DetachFromThreadHack();
if (flag_) flag_->DetachFromThread();
} }
private: private:
...@@ -269,13 +273,6 @@ class WeakPtrFactory { ...@@ -269,13 +273,6 @@ class WeakPtrFactory {
return weak_reference_owner_.HasRefs(); return weak_reference_owner_.HasRefs();
} }
// Indicates that this object will be used on another thread from now on.
// Do not use this in new code. See crbug.com/232143.
void DetachFromThread() {
DCHECK(ptr_);
weak_reference_owner_.DetachFromThread();
}
private: private:
internal::WeakReferenceOwner weak_reference_owner_; internal::WeakReferenceOwner weak_reference_owner_;
T* ptr_; T* ptr_;
...@@ -296,10 +293,12 @@ class SupportsWeakPtr : public internal::SupportsWeakPtrBase { ...@@ -296,10 +293,12 @@ class SupportsWeakPtr : public internal::SupportsWeakPtrBase {
return WeakPtr<T>(weak_reference_owner_.GetRef(), static_cast<T*>(this)); return WeakPtr<T>(weak_reference_owner_.GetRef(), static_cast<T*>(this));
} }
// Indicates that this object will be used on another thread from now on. // Removes the binding, if any, from this object to a particular thread.
// Do not use this in new code. See crbug.com/232143. // This is used in WebGraphicsContext3DInProcessCommandBufferImpl to work-
void DetachFromThread() { // around access to cmmand buffer objects by more than one thread.
weak_reference_owner_.DetachFromThread(); // Remove this when crbug.com/234964 is addressed.
void DetachFromThreadHack() {
weak_reference_owner_.DetachFromThreadHack();
} }
protected: protected:
......
...@@ -339,7 +339,7 @@ TEST(WeakPtrTest, MoveOwnershipExplicitlyObjectNotReferenced) { ...@@ -339,7 +339,7 @@ TEST(WeakPtrTest, MoveOwnershipExplicitlyObjectNotReferenced) {
// Case 1: The target is not bound to any thread yet. So calling // Case 1: The target is not bound to any thread yet. So calling
// DetachFromThread() is a no-op. // DetachFromThread() is a no-op.
Target target; Target target;
target.DetachFromThread(); target.DetachFromThreadHack();
// Case 2: The target is bound to main thread but no WeakPtr is pointing to // Case 2: The target is bound to main thread but no WeakPtr is pointing to
// it. In this case, it will be re-bound to any thread trying to get a // it. In this case, it will be re-bound to any thread trying to get a
...@@ -347,7 +347,7 @@ TEST(WeakPtrTest, MoveOwnershipExplicitlyObjectNotReferenced) { ...@@ -347,7 +347,7 @@ TEST(WeakPtrTest, MoveOwnershipExplicitlyObjectNotReferenced) {
{ {
WeakPtr<Target> weak_ptr = target.AsWeakPtr(); WeakPtr<Target> weak_ptr = target.AsWeakPtr();
} }
target.DetachFromThread(); target.DetachFromThreadHack();
} }
TEST(WeakPtrTest, MoveOwnershipExplicitly) { TEST(WeakPtrTest, MoveOwnershipExplicitly) {
...@@ -362,7 +362,7 @@ TEST(WeakPtrTest, MoveOwnershipExplicitly) { ...@@ -362,7 +362,7 @@ TEST(WeakPtrTest, MoveOwnershipExplicitly) {
EXPECT_EQ(&target, background.DeRef(arrow)); EXPECT_EQ(&target, background.DeRef(arrow));
// Detach from background thread. // Detach from background thread.
target.DetachFromThread(); target.DetachFromThreadHack();
// Re-bind to main thread. // Re-bind to main thread.
EXPECT_EQ(&target, arrow->target.get()); EXPECT_EQ(&target, arrow->target.get());
...@@ -500,7 +500,7 @@ TEST(WeakPtrDeathTest, WeakPtrCopyDoesNotChangeThreadBinding) { ...@@ -500,7 +500,7 @@ TEST(WeakPtrDeathTest, WeakPtrCopyDoesNotChangeThreadBinding) {
background.DeleteArrow(arrow_copy); background.DeleteArrow(arrow_copy);
} }
TEST(WeakPtrDeathTest, NonOwnerThreadDereferencesWeakPtr) { TEST(WeakPtrDeathTest, NonOwnerThreadDereferencesWeakPtrAfterReference) {
// The default style "fast" does not support multi-threaded tests // The default style "fast" does not support multi-threaded tests
// (introduces deadlock on Linux). // (introduces deadlock on Linux).
::testing::FLAGS_gtest_death_test_style = "threadsafe"; ::testing::FLAGS_gtest_death_test_style = "threadsafe";
...@@ -512,6 +512,7 @@ TEST(WeakPtrDeathTest, NonOwnerThreadDereferencesWeakPtr) { ...@@ -512,6 +512,7 @@ TEST(WeakPtrDeathTest, NonOwnerThreadDereferencesWeakPtr) {
// thread ownership can not be implicitly moved). // thread ownership can not be implicitly moved).
Arrow arrow; Arrow arrow;
arrow.target = target.AsWeakPtr(); arrow.target = target.AsWeakPtr();
arrow.target.get();
// Background thread tries to deref target, which violates thread ownership. // Background thread tries to deref target, which violates thread ownership.
BackgroundThread background; BackgroundThread background;
...@@ -519,23 +520,66 @@ TEST(WeakPtrDeathTest, NonOwnerThreadDereferencesWeakPtr) { ...@@ -519,23 +520,66 @@ TEST(WeakPtrDeathTest, NonOwnerThreadDereferencesWeakPtr) {
ASSERT_DEATH(background.DeRef(&arrow), ""); ASSERT_DEATH(background.DeRef(&arrow), "");
} }
TEST(WeakPtrDeathTest, NonOwnerThreadDeletesObject) { TEST(WeakPtrDeathTest, NonOwnerThreadDeletesWeakPtrAfterReference) {
// The default style "fast" does not support multi-threaded tests // The default style "fast" does not support multi-threaded tests
// (introduces deadlock on Linux). // (introduces deadlock on Linux).
::testing::FLAGS_gtest_death_test_style = "threadsafe"; ::testing::FLAGS_gtest_death_test_style = "threadsafe";
scoped_ptr<Target> target(new Target()); scoped_ptr<Target> target(new Target());
// Main thread creates an arrow referencing the Target (so target's thread
// ownership can not be implicitly moved). // Main thread creates an arrow referencing the Target.
Arrow arrow;
arrow.target = target->AsWeakPtr();
// Background thread tries to deref target, binding it to the thread.
BackgroundThread background;
background.Start();
background.DeRef(&arrow);
// Main thread deletes Target, violating thread binding.
Target* foo = target.release();
ASSERT_DEATH(delete foo, "");
}
TEST(WeakPtrDeathTest, NonOwnerThreadDeletesObjectAfterReference) {
// The default style "fast" does not support multi-threaded tests
// (introduces deadlock on Linux).
::testing::FLAGS_gtest_death_test_style = "threadsafe";
scoped_ptr<Target> target(new Target());
// Main thread creates an arrow referencing the Target, and references it, so
// that it becomes bound to the thread.
Arrow arrow; Arrow arrow;
arrow.target = target->AsWeakPtr(); arrow.target = target->AsWeakPtr();
arrow.target.get();
// Background thread tries to delete target, which violates thread ownership. // Background thread tries to delete target, volating thread binding.
BackgroundThread background; BackgroundThread background;
background.Start(); background.Start();
ASSERT_DEATH(background.DeleteTarget(target.release()), ""); ASSERT_DEATH(background.DeleteTarget(target.release()), "");
} }
TEST(WeakPtrDeathTest, NonOwnerThreadReferencesObjectAfterDeletion) {
// The default style "fast" does not support multi-threaded tests
// (introduces deadlock on Linux).
::testing::FLAGS_gtest_death_test_style = "threadsafe";
scoped_ptr<Target> target(new Target());
// Main thread creates an arrow referencing the Target.
Arrow arrow;
arrow.target = target->AsWeakPtr();
// Background thread tries to delete target, binding the object to the thread.
BackgroundThread background;
background.Start();
background.DeleteTarget(target.release());
// Main thread attempts to dereference the target, violating thread binding.
ASSERT_DEATH(arrow.target.get(), "");
}
#endif #endif
} // namespace base } // namespace base
...@@ -96,9 +96,6 @@ RulesRegistryWithCache::RulesRegistryWithCache( ...@@ -96,9 +96,6 @@ RulesRegistryWithCache::RulesRegistryWithCache(
ui_part->reset(storage_on_ui_.get()); ui_part->reset(storage_on_ui_.get());
// After construction, |this| continues to live only on |owner_thread|.
weak_ptr_factory_.DetachFromThread();
storage_on_ui_->Init(); storage_on_ui_->Init();
} }
......
...@@ -584,11 +584,6 @@ void IOThread::Init() { ...@@ -584,11 +584,6 @@ void IOThread::Init() {
FROM_HERE, FROM_HERE,
base::Bind(&IOThread::InitSystemRequestContext, base::Bind(&IOThread::InitSystemRequestContext,
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
// We constructed the weak pointer on the IO thread but it will be
// used on the UI thread. Call this to avoid a thread checker
// error.
weak_factory_.DetachFromThread();
} }
void IOThread::CleanUp() { void IOThread::CleanUp() {
......
...@@ -104,8 +104,6 @@ bool PluginInfoMessageFilter::OnMessageReceived(const IPC::Message& message, ...@@ -104,8 +104,6 @@ bool PluginInfoMessageFilter::OnMessageReceived(const IPC::Message& message,
} }
void PluginInfoMessageFilter::OnDestruct() const { void PluginInfoMessageFilter::OnDestruct() const {
const_cast<PluginInfoMessageFilter*>(this)->
weak_ptr_factory_.DetachFromThread();
const_cast<PluginInfoMessageFilter*>(this)-> const_cast<PluginInfoMessageFilter*>(this)->
weak_ptr_factory_.InvalidateWeakPtrs(); weak_ptr_factory_.InvalidateWeakPtrs();
......
...@@ -167,7 +167,6 @@ SearchProviderInstallData::SearchProviderInstallData( ...@@ -167,7 +167,6 @@ SearchProviderInstallData::SearchProviderInstallData(
// the given notification occurs. // the given notification occurs.
new GoogleURLObserver(profile, new GoogleURLChangeNotifier(AsWeakPtr()), new GoogleURLObserver(profile, new GoogleURLChangeNotifier(AsWeakPtr()),
ui_death_notification, ui_death_source); ui_death_notification, ui_death_source);
DetachFromThread();
} }
SearchProviderInstallData::~SearchProviderInstallData() { SearchProviderInstallData::~SearchProviderInstallData() {
......
...@@ -41,11 +41,6 @@ DhcpProxyScriptAdapterFetcher::DhcpProxyScriptAdapterFetcher( ...@@ -41,11 +41,6 @@ DhcpProxyScriptAdapterFetcher::DhcpProxyScriptAdapterFetcher(
DhcpProxyScriptAdapterFetcher::~DhcpProxyScriptAdapterFetcher() { DhcpProxyScriptAdapterFetcher::~DhcpProxyScriptAdapterFetcher() {
Cancel(); Cancel();
// The WeakPtr we passed to the worker thread may be destroyed on the
// worker thread. This detaches any outstanding WeakPtr state from
// the current thread.
base::SupportsWeakPtr<DhcpProxyScriptAdapterFetcher>::DetachFromThread();
} }
void DhcpProxyScriptAdapterFetcher::Fetch( void DhcpProxyScriptAdapterFetcher::Fetch(
......
...@@ -47,11 +47,6 @@ DhcpProxyScriptFetcherWin::DhcpProxyScriptFetcherWin( ...@@ -47,11 +47,6 @@ DhcpProxyScriptFetcherWin::DhcpProxyScriptFetcherWin(
DhcpProxyScriptFetcherWin::~DhcpProxyScriptFetcherWin() { DhcpProxyScriptFetcherWin::~DhcpProxyScriptFetcherWin() {
// Count as user-initiated if we are not yet in STATE_DONE. // Count as user-initiated if we are not yet in STATE_DONE.
Cancel(); Cancel();
// The WeakPtr we passed to the worker thread may be destroyed on the
// worker thread. This detaches any outstanding WeakPtr state from
// the current thread.
base::SupportsWeakPtr<DhcpProxyScriptFetcherWin>::DetachFromThread();
} }
int DhcpProxyScriptFetcherWin::Fetch(base::string16* utf16_text, int DhcpProxyScriptFetcherWin::Fetch(base::string16* utf16_text,
......
...@@ -51,12 +51,6 @@ class PolicyWatcherLinux : public PolicyWatcher { ...@@ -51,12 +51,6 @@ class PolicyWatcherLinux : public PolicyWatcher {
: PolicyWatcher(task_runner), : PolicyWatcher(task_runner),
config_dir_(config_dir), config_dir_(config_dir),
weak_factory_(this) { weak_factory_(this) {
// Detach the factory because we ensure that only the policy thread ever
// calls methods on this. Also, the API contract of having to call
// StopWatching() (which signals completion) after StartWatching()
// before this object can be destructed ensures there are no users of
// this object before it is destructed.
weak_factory_.DetachFromThread();
} }
virtual ~PolicyWatcherLinux() {} virtual ~PolicyWatcherLinux() {}
...@@ -84,8 +78,12 @@ class PolicyWatcherLinux : public PolicyWatcher { ...@@ -84,8 +78,12 @@ class PolicyWatcherLinux : public PolicyWatcher {
virtual void StopWatchingInternal() OVERRIDE { virtual void StopWatchingInternal() OVERRIDE {
DCHECK(OnPolicyWatcherThread()); DCHECK(OnPolicyWatcherThread());
// Cancel any inflight requests.
// Stop watching for changes to files in the policies directory.
watcher_.reset(); watcher_.reset();
// Orphan any pending OnFilePathChanged tasks.
weak_factory_.InvalidateWeakPtrs();
} }
private: private:
......
...@@ -240,9 +240,6 @@ class SGIVideoSyncVSyncProvider ...@@ -240,9 +240,6 @@ class SGIVideoSyncVSyncProvider
shim_((new SGIVideoSyncProviderThreadShim(window))->AsWeakPtr()), shim_((new SGIVideoSyncProviderThreadShim(window))->AsWeakPtr()),
cancel_vsync_flag_(shim_->cancel_vsync_flag()), cancel_vsync_flag_(shim_->cancel_vsync_flag()),
vsync_lock_(shim_->vsync_lock()) { vsync_lock_(shim_->vsync_lock()) {
// The WeakPtr is bound to the SGIVideoSyncThread. We only use it for
// PostTask.
shim_->DetachFromThread();
vsync_thread_->message_loop()->PostTask( vsync_thread_->message_loop()->PostTask(
FROM_HERE, FROM_HERE,
base::Bind(&SGIVideoSyncProviderThreadShim::Initialize, shim_)); base::Bind(&SGIVideoSyncProviderThreadShim::Initialize, shim_));
......
...@@ -268,10 +268,11 @@ static bool g_use_virtualized_gl_context = false; ...@@ -268,10 +268,11 @@ static bool g_use_virtualized_gl_context = false;
namespace { namespace {
// Also calls DetachFromThread on all GLES2Decoders before the lock is released // Also calls DetachFromThreadHack on all GLES2Decoders before the lock is
// to maintain the invariant that all decoders are unbounded while the lock is // released to maintain the invariant that all decoders are unbound while the
// not held. This is to workaround DumpRenderTree uses WGC3DIPCBI with shared // lock is not held. This is to workaround DumpRenderTree using WGC3DIPCBI with
// resources on different threads. // shared resources on different threads.
// Remove this as part of crbug.com/234964.
class AutoLockAndDecoderDetachThread { class AutoLockAndDecoderDetachThread {
public: public:
AutoLockAndDecoderDetachThread(base::Lock& lock, AutoLockAndDecoderDetachThread(base::Lock& lock,
...@@ -292,7 +293,7 @@ AutoLockAndDecoderDetachThread::AutoLockAndDecoderDetachThread( ...@@ -292,7 +293,7 @@ AutoLockAndDecoderDetachThread::AutoLockAndDecoderDetachThread(
void DetachThread(GLInProcessContext* context) { void DetachThread(GLInProcessContext* context) {
if (context->GetDecoder()) if (context->GetDecoder())
context->GetDecoder()->DetachFromThread(); context->GetDecoder()->DetachFromThreadHack();
} }
AutoLockAndDecoderDetachThread::~AutoLockAndDecoderDetachThread() { AutoLockAndDecoderDetachThread::~AutoLockAndDecoderDetachThread() {
......
...@@ -158,11 +158,7 @@ HRESULT UIAutomationClient::Context::EventHandler::HandleAutomationEvent( ...@@ -158,11 +158,7 @@ HRESULT UIAutomationClient::Context::EventHandler::HandleAutomationEvent(
base::WeakPtr<UIAutomationClient::Context> base::WeakPtr<UIAutomationClient::Context>
UIAutomationClient::Context::Create() { UIAutomationClient::Context::Create() {
Context* context = new Context(); Context* context = new Context();
base::WeakPtr<Context> context_ptr(context->weak_ptr_factory_.GetWeakPtr()); return context->weak_ptr_factory_.GetWeakPtr();
// Unbind from this thread so that the instance will bind to the automation
// thread when Initialize is called.
context->weak_ptr_factory_.DetachFromThread();
return context_ptr;
} }
void UIAutomationClient::Context::DeleteOnAutomationThread() { void UIAutomationClient::Context::DeleteOnAutomationThread() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment