1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef INCLUDE_PERFETTO_EXT_BASE_WEAK_PTR_H_
18 #define INCLUDE_PERFETTO_EXT_BASE_WEAK_PTR_H_
19 
20 #include "perfetto/ext/base/thread_checker.h"
21 
22 #include <memory>
23 
24 namespace perfetto {
25 namespace base {
26 
27 // A simple WeakPtr for single-threaded cases.
28 // Generally keep the WeakPtrFactory as last fields in classes: it makes the
29 // WeakPtr(s) invalidate as first thing in the class dtor.
30 // Usage:
31 // class MyClass {
32 //  MyClass() : weak_factory_(this) {}
33 //  WeakPtr<MyClass> GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
34 //
35 // private:
36 //  WeakPtrFactory<MyClass> weak_factory_;
37 // }
38 //
39 // int main() {
40 //  std::unique_ptr<MyClass> foo(new MyClass);
41 //  auto wptr = foo.GetWeakPtr();
42 //  ASSERT_TRUE(wptr);
43 //  ASSERT_EQ(foo.get(), wptr->get());
44 //  foo.reset();
45 //  ASSERT_FALSE(wptr);
46 //  ASSERT_EQ(nullptr, wptr->get());
47 // }
48 
49 template <typename T>
50 class WeakPtrFactory;  // Forward declaration, defined below.
51 
52 template <typename T>
53 class WeakPtr {
54  public:
WeakPtr()55   WeakPtr() {}
56   WeakPtr(const WeakPtr&) = default;
57   WeakPtr& operator=(const WeakPtr&) = default;
58   WeakPtr(WeakPtr&&) = default;
59   WeakPtr& operator=(WeakPtr&&) = default;
60 
get()61   T* get() const {
62     PERFETTO_DCHECK_THREAD(thread_checker);
63     return handle_ ? *handle_.get() : nullptr;
64   }
65   T* operator->() const { return get(); }
66   T& operator*() const { return *get(); }
67 
68   explicit operator bool() const { return !!get(); }
69 
70  private:
71   friend class WeakPtrFactory<T>;
WeakPtr(const std::shared_ptr<T * > & handle)72   explicit WeakPtr(const std::shared_ptr<T*>& handle) : handle_(handle) {}
73 
74   std::shared_ptr<T*> handle_;
75   PERFETTO_THREAD_CHECKER(thread_checker)
76 };
77 
78 template <typename T>
79 class WeakPtrFactory {
80  public:
WeakPtrFactory(T * owner)81   explicit WeakPtrFactory(T* owner)
82       : weak_ptr_(std::shared_ptr<T*>(new T* {owner})) {
83     PERFETTO_DCHECK_THREAD(thread_checker);
84   }
85 
~WeakPtrFactory()86   ~WeakPtrFactory() {
87     PERFETTO_DCHECK_THREAD(thread_checker);
88     *(weak_ptr_.handle_.get()) = nullptr;
89   }
90 
91   // Can be safely called on any thread, since it simply copies |weak_ptr_|.
92   // Note that any accesses to the returned pointer need to be made on the
93   // thread that created/reset the factory.
GetWeakPtr()94   WeakPtr<T> GetWeakPtr() const { return weak_ptr_; }
95 
96   // Reset the factory to a new owner & thread. May only be called before any
97   // weak pointers were passed out. Future weak pointers will be valid on the
98   // calling thread.
Reset(T * owner)99   void Reset(T* owner) {
100     // Reset thread checker to current thread.
101     PERFETTO_DETACH_FROM_THREAD(thread_checker);
102     PERFETTO_DCHECK_THREAD(thread_checker);
103 
104     // We should not have passed out any weak pointers yet at this point.
105     PERFETTO_DCHECK(weak_ptr_.handle_.use_count() == 1);
106 
107     weak_ptr_ = WeakPtr<T>(std::shared_ptr<T*>(new T* {owner}));
108   }
109 
110  private:
111   WeakPtrFactory(const WeakPtrFactory&) = delete;
112   WeakPtrFactory& operator=(const WeakPtrFactory&) = delete;
113 
114   WeakPtr<T> weak_ptr_;
115   PERFETTO_THREAD_CHECKER(thread_checker)
116 };
117 
118 }  // namespace base
119 }  // namespace perfetto
120 
121 #endif  // INCLUDE_PERFETTO_EXT_BASE_WEAK_PTR_H_
122