// Copyright 2013 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 TOOLS_ANDROID_FORWARDER2_SELF_DELETER_HELPER_H_ #define TOOLS_ANDROID_FORWARDER2_SELF_DELETER_HELPER_H_ #include #include "base/bind.h" #include "base/callback.h" #include "base/check_op.h" #include "base/location.h" #include "base/macros.h" #include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread_task_runner_handle.h" namespace base { class SingleThreadTaskRunner; } // namespace base namespace forwarder2 { // Helper template class to be used in the following case: // * T is the type of an object that implements some work through an internal // or worker thread. // * T wants the internal thread to invoke deletion of its own instance, on // the thread where the instance was created. // // To make this easier, do something like: // 1) Add a SelfDeleteHelper member to your class T, and default-initialize // it in its constructor. // 2) In the internal thread, to trigger self-deletion, call the // MaybeDeleteSoon() method on this member. // // MaybeDeleteSoon() posts a task on the message loop where the T instance was // created to delete it. The task will be safely ignored if the instance is // otherwise deleted. // // Usage example: // class Object { // public: // using ErrorCallback = base::OnceCallback)>; // // Object(ErrorCallback error_callback) // : self_deleter_helper_(this, std::move(error_callback)) { // } // // void StartWork() { // // Post a callback to DoSomethingOnWorkerThread() below to another // // thread. // } // // void DoSomethingOnWorkerThread() { // ... // if (error_happened) // self_deleter_helper_.MaybeDeleteSoon(); // } // // private: // SelfDeleterHelper self_deleter_helper_; // }; // // class ObjectOwner { // public: // ObjectOwner() // : object_(new Object(base::BindOnce(&ObjectOwner::DeleteObjectOnError, // base::Unretained(this))) { // // To keep this example simple base::Unretained(this) is used above but // // note that in a real world scenario the client would have to make sure // // that the ObjectOwner instance is still alive when // // DeleteObjectOnError() gets called below. This can be achieved by // // using a WeakPtr for instance. // } // // void StartWork() { // object_->StartWork(); // } // // private: // void DeleteObjectOnError(std::unique_ptr object) { // DCHECK(thread_checker_.CalledOnValidThread()); // DCHECK_EQ(object_, object); // // Do some extra work with |object| before it gets deleted... // object_.reset(); // ignore_result(object.release()); // } // // base::ThreadChecker thread_checker_; // std::unique_ptr object_; // }; // template class SelfDeleterHelper { public: using DeletionCallback = base::OnceCallback)>; SelfDeleterHelper(T* self_deleting_object, DeletionCallback deletion_callback) : construction_runner_(base::ThreadTaskRunnerHandle::Get()), self_deleting_object_(self_deleting_object), deletion_callback_(std::move(deletion_callback)) {} ~SelfDeleterHelper() { DCHECK(construction_runner_->RunsTasksInCurrentSequence()); } void MaybeSelfDeleteSoon() { DCHECK(!construction_runner_->RunsTasksInCurrentSequence()); construction_runner_->PostTask( FROM_HERE, base::BindOnce(&SelfDeleterHelper::SelfDelete, weak_ptr_factory_.GetWeakPtr())); } private: void SelfDelete() { DCHECK(construction_runner_->RunsTasksInCurrentSequence()); std::move(deletion_callback_).Run(base::WrapUnique(self_deleting_object_)); } const scoped_refptr construction_runner_; T* const self_deleting_object_; DeletionCallback deletion_callback_; // WeakPtrFactory's documentation says: // 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. base::WeakPtrFactory> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(SelfDeleterHelper); }; } // namespace forwarder2 #endif // TOOLS_ANDROID_FORWARDER2_SELF_DELETER_HELPER_H_