1 // Copyright 2016 The Fuchsia Authors
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6
7 #pragma once
8
9 #include <fbl/arena.h>
10 #include <fbl/atomic.h>
11 #include <fbl/intrusive_double_list.h>
12 #include <fbl/macros.h>
13 #include <fbl/mutex.h>
14 #include <fbl/ref_ptr.h>
15 #include <kernel/lockdep.h>
16 #include <stdint.h>
17 #include <zircon/types.h>
18
19 class Dispatcher;
20 class Handle;
21
22 // HandleOwner wraps a Handle in a unique_ptr-like object that has single
23 // ownership of the Handle and deletes it whenever it falls out of scope.
24 class HandleOwner {
25 public:
26 HandleOwner() = default;
HandleOwner(decltype (nullptr))27 HandleOwner(decltype(nullptr)) : h_(nullptr) {}
28
HandleOwner(Handle * h)29 explicit HandleOwner(Handle* h) : h_(h) {}
30
31 HandleOwner(const HandleOwner&) = delete;
32 HandleOwner& operator=(const HandleOwner&) = delete;
33
HandleOwner(HandleOwner && other)34 HandleOwner(HandleOwner&& other) : h_(other.release()) {}
35
36 HandleOwner& operator=(HandleOwner&& other) {
37 reset(other.release());
38 return *this;
39 }
40
~HandleOwner()41 ~HandleOwner() {
42 Destroy();
43 }
44
45 Handle* operator->() const {
46 return h_;
47 }
48
get()49 Handle* get() const {
50 return h_;
51 }
52
release()53 Handle* release() {
54 Handle* h = h_;
55 h_ = nullptr;
56 return h;
57 }
58
reset(Handle * h)59 void reset(Handle* h) {
60 Destroy();
61 h_ = h;
62 }
63
swap(HandleOwner & other)64 void swap(HandleOwner& other) {
65 Handle* h = h_;
66 h_ = other.h_;
67 other.h_ = h;
68 }
69
70 explicit operator bool() const { return h_ != nullptr; }
71
72 private:
73 // Defined inline below.
74 inline void Destroy();
75
76 Handle* h_ = nullptr;
77 };
78
79 // A Handle is how a specific process refers to a specific Dispatcher.
80 class Handle final : public fbl::DoublyLinkedListable<Handle*> {
81 public:
82 // The handle arena's mutex. This is public since it protects
83 // other things like |Dispatcher::handle_count_|.
84 DECLARE_SINGLETON_MUTEX(ArenaLock);
85
86 // Returns the Dispatcher to which this instance points.
dispatcher()87 const fbl::RefPtr<Dispatcher>& dispatcher() const { return dispatcher_; }
88
89 // Returns the process that owns this instance. Used to guarantee
90 // that one process may not access a handle owned by a different process.
process_id()91 zx_koid_t process_id() const {
92 return process_id_.load(fbl::memory_order_relaxed);
93 }
94
95 // Sets the value returned by process_id().
96 void set_process_id(zx_koid_t pid);
97
98 // Returns the |rights| parameter that was provided when this instance
99 // was created.
rights()100 uint32_t rights() const {
101 return rights_;
102 }
103
104 // Returns true if this handle has all of the desired rights bits set.
HasRights(zx_rights_t desired)105 bool HasRights(zx_rights_t desired) const {
106 return (rights_ & desired) == desired;
107 }
108
109 // Returns a value that can be decoded by Handle::FromU32() to derive a
110 // pointer to this instance. ProcessDispatcher will XOR this with its
111 // |handle_rand_| to create the zx_handle_t value that user space sees.
base_value()112 uint32_t base_value() const {
113 return base_value_;
114 }
115
116 // To be called once during bring up.
117 static void Init();
118
119 // Maps an integer obtained by Handle::base_value() back to a Handle.
120 static Handle* FromU32(uint32_t value);
121
122 // Get the number of outstanding handles for a given dispatcher.
123 static uint32_t Count(const fbl::RefPtr<const Dispatcher>&);
124
125 // Should only be called by diagnostics.cpp.
126 struct diagnostics {
127 // Dumps internal details of the handle table using printf().
128 static void DumpTableInfo();
129
130 // Returns the number of outstanding handles.
131 static size_t OutstandingHandles();
132 };
133
134 // Handle should never be created by anything other than Make or Dup.
135 static HandleOwner Make(
136 fbl::RefPtr<Dispatcher> dispatcher, zx_rights_t rights);
137 static HandleOwner Dup(Handle* source, zx_rights_t rights);
138
139 private:
140 DISALLOW_COPY_ASSIGN_AND_MOVE(Handle);
141
142 // Called only by Make.
143 Handle(fbl::RefPtr<Dispatcher> dispatcher,
144 zx_rights_t rights, uint32_t base_value);
145 // Called only by Dup.
146 Handle(Handle* rhs, zx_rights_t rights, uint32_t base_value);
147
148 // Private subroutines of Make and Dup.
149 static void* Alloc(const fbl::RefPtr<Dispatcher>&, const char* what,
150 uint32_t* base_value);
151 static uint32_t GetNewBaseValue(void* addr);
152
153 // Handle should never be destroyed by anything other than Delete,
154 // which uses TearDown to do the actual destruction.
155 ~Handle() = default;
156 void TearDown() TA_EXCL(ArenaLock::Get());
157 void Delete();
158
159 // Only HandleOwner is allowed to call Delete.
160 friend class HandleOwner;
161
162 // process_id_ is atomic because threads from different processes can
163 // access it concurrently, while holding different instances of
164 // handle_table_lock_.
165 fbl::atomic<zx_koid_t> process_id_;
166 fbl::RefPtr<Dispatcher> dispatcher_;
167 const zx_rights_t rights_;
168 const uint32_t base_value_;
169
170 // The handle arena.
171 static fbl::Arena TA_GUARDED(ArenaLock::Get()) arena_;
172
173 // NOTE! This can return an invalid address. It must be checked
174 // against the arena bounds before being cast to a Handle*.
IndexToHandle(uint32_t index)175 static uintptr_t IndexToHandle(uint32_t index) TA_NO_THREAD_SAFETY_ANALYSIS {
176 return reinterpret_cast<uintptr_t>(arena_.start()) + index * sizeof(Handle);
177 }
178
HandleToIndex(Handle * handle)179 static uint32_t HandleToIndex(Handle* handle) TA_NO_THREAD_SAFETY_ANALYSIS {
180 return static_cast<uint32_t>(
181 handle - reinterpret_cast<Handle*>(arena_.start()));
182 }
183 };
184
185 // This can't be defined directly in the HandleOwner class definition
186 // because Handle is an incomplete type at that point.
Destroy()187 inline void HandleOwner::Destroy() {
188 if (h_)
189 h_->Delete();
190 }
191