blob: 19c56a2f71dcd210063c26183febb25f953fa192 [file] [log] [blame]
// 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 <memory>
#include "base/bind.h"
#include "base/callback.h"
#include "base/location.h"
#include "base/logging.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<T> 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:
// typedef base::Callback<void (std::unique_ptr<Object>)> ErrorCallback;
//
// Object(const ErrorCallback& error_callback)
// : self_deleter_helper_(this, error_callback) {
// }
//
// void StartWork() {
// // Post a callback to DoSomethingOnWorkerThread() below to another
// // thread.
// }
//
// void DoSomethingOnWorkerThread() {
// ...
// if (error_happened)
// self_deleter_helper_.MaybeDeleteSoon();
// }
//
// private:
// SelfDeleterHelper<MySelfDeletingClass> self_deleter_helper_;
// };
//
// class ObjectOwner {
// public:
// ObjectOwner()
// : object_(new Object(base::Bind(&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<ObjectOwner> for instance.
// }
//
// void StartWork() {
// object_->StartWork();
// }
//
// private:
// void DeleteObjectOnError(std::unique_ptr<Object> 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> object_;
// };
//
template <typename T>
class SelfDeleterHelper {
public:
typedef base::Callback<void(std::unique_ptr<T>)> DeletionCallback;
SelfDeleterHelper(T* self_deleting_object,
const DeletionCallback& deletion_callback)
: construction_runner_(base::ThreadTaskRunnerHandle::Get()),
self_deleting_object_(self_deleting_object),
deletion_callback_(deletion_callback),
weak_ptr_factory_(this) {}
~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());
deletion_callback_.Run(base::WrapUnique(self_deleting_object_));
}
const scoped_refptr<base::SingleThreadTaskRunner> construction_runner_;
T* const self_deleting_object_;
const 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<SelfDeleterHelper<T> > weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(SelfDeleterHelper);
};
} // namespace forwarder2
#endif // TOOLS_ANDROID_FORWARDER2_SELF_DELETER_HELPER_H_