|  | // Copyright 2018 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 BASE_THREADING_SEQUENCE_BOUND_H_ | 
|  | #define BASE_THREADING_SEQUENCE_BOUND_H_ | 
|  |  | 
|  | #include <new> | 
|  | #include <type_traits> | 
|  |  | 
|  | #include "base/bind.h" | 
|  | #include "base/callback.h" | 
|  | #include "base/compiler_specific.h" | 
|  | #include "base/location.h" | 
|  | #include "base/memory/aligned_memory.h" | 
|  | #include "base/memory/ptr_util.h" | 
|  | #include "base/sequenced_task_runner.h" | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | // SequenceBound facilitates owning objects that live on a specified sequence, | 
|  | // which is potentially different than the owner's sequence.  It encapsulates | 
|  | // the work of posting tasks to the specified sequence to construct T, call | 
|  | // methods on T, and destroy T. | 
|  | // | 
|  | // It does not provide explicit access to the underlying object directly, to | 
|  | // prevent accidentally using it from the wrong sequence. | 
|  | // | 
|  | // Like std::unique_ptr<T>, a SequenceBound<T> may be moved between owners, | 
|  | // and posted across threads.  It may also be up-casted (only), to permit | 
|  | // SequenceBound to be used with interfaces. | 
|  | // | 
|  | // Basic usage looks like this: | 
|  | // | 
|  | //   // Some class that lives on |main_task_runner|. | 
|  | //   class MyClass { | 
|  | //    public: | 
|  | //     explicit MyClass(const char* widget_title) {} | 
|  | //     virtual ~MyClass() { ... } | 
|  | //     virtual void DoSomething(int arg) { ... } | 
|  | //   }; | 
|  | // | 
|  | //   // On any thread... | 
|  | //   scoped_refptr<SequencedTaskRunner> main_task_runner = ...; | 
|  | //   auto widget = SequenceBound<MyClass>(main_task_runner, "My Title"); | 
|  | //   widget.Post(&MyObject::DoSomething, 1234); | 
|  | // | 
|  | // Note that |widget| is constructed asynchronously on |main_task_runner|, | 
|  | // but calling Post() immediately is safe, since the actual call is posted | 
|  | // to |main_task_runner| as well. | 
|  | // | 
|  | // |widget| will be deleted on |main_task_runner| asynchronously when it goes | 
|  | // out of scope, or when Reset() is called. | 
|  | // | 
|  | // Here is a more complicated example that shows injection and upcasting: | 
|  | // | 
|  | //   // Some unrelated class that uses a |MyClass| to do something. | 
|  | //   class SomeConsumer { | 
|  | //    public: | 
|  | //    // Note that ownership of |widget| is given to us! | 
|  | //    explicit SomeConsumer(SequenceBound<MyClass> widget) | 
|  | //        : widget_(std::move(widget)) { ... } | 
|  | // | 
|  | //    ~SomeConsumer() { | 
|  | //      // |widget_| will be destroyed on the associated task runner. | 
|  | //    } | 
|  | // | 
|  | //     SequenceBound<MyClass> widget_; | 
|  | //   }; | 
|  | // | 
|  | //   // Implementation of MyClass. | 
|  | //   class MyDerivedClass : public MyClass { ... }; | 
|  | // | 
|  | //   auto widget = | 
|  | //     SequenceBound<MyDerivedClass>(main_task_runner, ctor args); | 
|  | //   auto c = new SomeConsumer(std::move(widget));  // upcasts to MyClass | 
|  |  | 
|  | namespace internal { | 
|  |  | 
|  | // If we can't cast |Base*| into |Derived*|, then it's a virtual base if and | 
|  | // only if |Base| is actually a base class of |Derived|.  Otherwise (including | 
|  | // unrelated types), it isn't.  We default to Derived* so that the | 
|  | // specialization below will apply when the cast to |Derived*| is valid. | 
|  | template <typename Base, typename Derived, typename = Derived*> | 
|  | struct is_virtual_base_of : public std::is_base_of<Base, Derived> {}; | 
|  |  | 
|  | // If we can cast |Base*| into |Derived*|, then it's definitely not a virtual | 
|  | // base.  When this happens, we'll match the default third template argument. | 
|  | template <typename Base, typename Derived> | 
|  | struct is_virtual_base_of<Base, | 
|  | Derived, | 
|  | decltype(static_cast<Derived*>( | 
|  | static_cast<Base*>(nullptr)))> : std::false_type { | 
|  | }; | 
|  |  | 
|  | };  // namespace internal | 
|  |  | 
|  | template <typename T> | 
|  | class SequenceBound { | 
|  | public: | 
|  | // Allow explicit null. | 
|  | SequenceBound() = default; | 
|  |  | 
|  | // Construct a new instance of |T| that will be accessed only on | 
|  | // |task_runner|.  One may post calls to it immediately upon return. | 
|  | // This is marked as NO_SANITIZE because cfi doesn't like that we're casting | 
|  | // uninitialized memory to a |T*|.  However, it's safe since (a) the cast is | 
|  | // defined (see http://eel.is/c++draft/basic.life#6 for details), and (b) we | 
|  | // don't use the resulting pointer in any way that requries it to be | 
|  | // constructed, except by posting such a access to |impl_task_runner_| after | 
|  | // posting construction there as well. | 
|  | template <typename... Args> | 
|  | SequenceBound(scoped_refptr<base::SequencedTaskRunner> task_runner, | 
|  | Args&&... args) NO_SANITIZE("cfi-unrelated-cast") | 
|  | : impl_task_runner_(std::move(task_runner)) { | 
|  | // Allocate space for but do not construct an instance of |T|. | 
|  | storage_ = AlignedAlloc(sizeof(T), alignof(T)); | 
|  | t_ = reinterpret_cast<T*>(storage_); | 
|  |  | 
|  | // Post construction to the impl thread. | 
|  | impl_task_runner_->PostTask( | 
|  | FROM_HERE, | 
|  | base::BindOnce(&ConstructOwnerRecord<Args...>, base::Unretained(t_), | 
|  | std::forward<Args>(args)...)); | 
|  | } | 
|  |  | 
|  | ~SequenceBound() { Reset(); } | 
|  |  | 
|  | // Move construction from the same type can just take the pointer without | 
|  | // adjusting anything.  This is required in addition to the move conversion | 
|  | // constructor below. | 
|  | SequenceBound(SequenceBound&& other) { MoveRecordFrom(other); } | 
|  |  | 
|  | // Move construction is supported from any type that's compatible with |T|. | 
|  | // This case handles |From| != |T|, so we must adjust the pointer offset. | 
|  | template <typename From> | 
|  | SequenceBound(SequenceBound<From>&& other) { | 
|  | MoveRecordFrom(other); | 
|  | } | 
|  |  | 
|  | SequenceBound& operator=(SequenceBound&& other) { | 
|  | // Clean up any object we currently own. | 
|  | Reset(); | 
|  | MoveRecordFrom(other); | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | template <typename From> | 
|  | SequenceBound<T>& operator=(SequenceBound<From>&& other) { | 
|  | // Clean up any object that we currently own. | 
|  | Reset(); | 
|  | MoveRecordFrom(other); | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | // Move everything from |other|, doing pointer adjustment as needed. | 
|  | // This method is marked as NO_SANITIZE since (a) it might run before the | 
|  | // posted ctor runs on |impl_task_runner_|, and (b) implicit conversions to | 
|  | // non-virtual base classes are allowed before construction by the standard. | 
|  | // See http://eel.is/c++draft/basic.life#6 for more information. | 
|  | template <typename From> | 
|  | void MoveRecordFrom(From&& other) NO_SANITIZE("cfi-unrelated-cast") { | 
|  | // |other| might be is_null(), but that's okay. | 
|  | impl_task_runner_ = std::move(other.impl_task_runner_); | 
|  |  | 
|  | // Note that static_cast<> isn't, in general, safe, since |other| might not | 
|  | // be constructed yet.  Implicit conversion is supported, as long as it | 
|  | // doesn't convert to a virtual base.  Of course, it allows only upcasts. | 
|  | t_ = other.t_; | 
|  |  | 
|  | // The original storage is kept unmodified, so we can free it later. | 
|  | storage_ = other.storage_; | 
|  |  | 
|  | other.storage_ = nullptr; | 
|  | other.t_ = nullptr; | 
|  | } | 
|  |  | 
|  | // Post a call to |method| to |impl_task_runner_|. | 
|  | template <typename... Args> | 
|  | void Post(const base::Location& from_here, | 
|  | void (T::*method)(Args...), | 
|  | Args&&... args) const { | 
|  | impl_task_runner_->PostTask( | 
|  | from_here, base::BindOnce( | 
|  | [](void (T::*method)(Args...), T* t, Args... args) { | 
|  | (t->*method)(std::forward<Args>(args)...); | 
|  | }, | 
|  | std::move(method), base::Unretained(t_), | 
|  | std::forward<Args>(args)...)); | 
|  | } | 
|  |  | 
|  | // TODO(liberato): Add PostOrCall(), to support cases where synchronous calls | 
|  | // are okay if it's the same task runner. | 
|  |  | 
|  | // TODO(liberato): Add PostAndReply() | 
|  |  | 
|  | // TODO(liberato): Allow creation of callbacks that bind to a weak pointer, | 
|  | // and thread-hop to |impl_task_runner_| if needed. | 
|  |  | 
|  | // Post destruction of any object we own, and return to the null state. | 
|  | void Reset() { | 
|  | if (is_null()) | 
|  | return; | 
|  |  | 
|  | // Destruct the object on the impl thread. | 
|  | impl_task_runner_->PostTask( | 
|  | FROM_HERE, base::BindOnce(&DeleteOwnerRecord, base::Unretained(t_), | 
|  | base::Unretained(storage_))); | 
|  |  | 
|  | impl_task_runner_ = nullptr; | 
|  | t_ = nullptr; | 
|  | storage_ = nullptr; | 
|  | } | 
|  |  | 
|  | // Return whether we own anything.  Note that this does not guarantee that any | 
|  | // previously owned object has been destroyed.  In particular, it will return | 
|  | // true immediately after a call to Reset(), though the underlying object | 
|  | // might still be pending destruction on the impl thread. | 
|  | bool is_null() const { return !t_; } | 
|  |  | 
|  | private: | 
|  | // Pointer to the object,  Pointer may be modified on the owning thread. | 
|  | T* t_ = nullptr; | 
|  |  | 
|  | // Original allocated storage for the object. | 
|  | void* storage_ = nullptr; | 
|  |  | 
|  | // The task runner on which all access to |t_| should happen. | 
|  | scoped_refptr<base::SequencedTaskRunner> impl_task_runner_; | 
|  |  | 
|  | // For move conversion. | 
|  | template <typename U> | 
|  | friend class SequenceBound; | 
|  |  | 
|  | // Run on impl thread to construct |t|'s storage. | 
|  | template <typename... Args> | 
|  | static void ConstructOwnerRecord(T* t, Args&&... args) { | 
|  | new (t) T(std::forward<Args>(args)...); | 
|  | } | 
|  |  | 
|  | // Destruct the object associated with |t|, and delete |storage|. | 
|  | static void DeleteOwnerRecord(T* t, void* storage) { | 
|  | t->~T(); | 
|  | AlignedFree(storage); | 
|  | } | 
|  |  | 
|  | // To preserve ownership semantics, we disallow copy construction / copy | 
|  | // assignment.  Move construction / assignment is fine. | 
|  | DISALLOW_COPY_AND_ASSIGN(SequenceBound); | 
|  | }; | 
|  |  | 
|  | }  // namespace base | 
|  |  | 
|  | #endif  // BASE_THREADING_SEQUENCE_BOUND_H_ |