1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef LIB_ZX_OBJECT_H_
6 #define LIB_ZX_OBJECT_H_
7 
8 #include <zircon/syscalls.h>
9 #include <zircon/types.h>
10 #include <lib/zx/object_traits.h>
11 #include <lib/zx/time.h>
12 
13 namespace zx {
14 
15 class port;
16 class profile;
17 
18 // Wraps and takes ownership of a handle to an object.
19 //
20 // Used for code that wants to operate generically on the zx_handle_t value
21 // inside a |zx::object| and doesn't otherwise need a template parameter.
22 //
23 // The handle is automatically closed when the wrapper is destroyed.
24 class object_base {
25 public:
26     void reset(zx_handle_t value = ZX_HANDLE_INVALID) {
27         close();
28         value_ = value;
29     }
30 
is_valid()31     bool is_valid() const { return value_ != ZX_HANDLE_INVALID; }
32     explicit operator bool() const { return is_valid(); }
33 
get()34     zx_handle_t get() const { return value_; }
35 
36     // Reset the underlying handle, and then get the address of the
37     // underlying internal handle storage.
38     //
39     // Note: The intended purpose is to facilitate interactions with C
40     // APIs which expect to be provided a pointer to a handle used as
41     // an out parameter.
reset_and_get_address()42     zx_handle_t* reset_and_get_address() {
43         reset();
44         return &value_;
45     }
46 
release()47     __attribute__((warn_unused_result)) zx_handle_t release() {
48         zx_handle_t result = value_;
49         value_ = ZX_HANDLE_INVALID;
50         return result;
51     }
52 
53 protected:
object_base()54     constexpr object_base() : value_(ZX_HANDLE_INVALID) {}
55 
object_base(zx_handle_t value)56     explicit object_base(zx_handle_t value) : value_(value) {}
57 
~object_base()58     ~object_base() { close(); }
59 
60     object_base(const object_base&) = delete;
61 
62     void operator=(const object_base&) = delete;
63 
close()64     void close() {
65         if (value_ != ZX_HANDLE_INVALID) {
66             zx_handle_close(value_);
67             value_ = ZX_HANDLE_INVALID;
68         }
69     }
70 
71     zx_handle_t value_;
72 };
73 
74 // Provides type-safe access to operations on a handle.
75 template <typename T> class object : public object_base {
76 public:
77     constexpr object() = default;
78 
object(zx_handle_t value)79     explicit object(zx_handle_t value) : object_base(value) {}
80 
object(object<U> && other)81     template <typename U> object(object<U>&& other) : object_base(other.release()) {
82         static_assert(is_same<T, void>::value, "Receiver must be compatible.");
83     }
84 
85     template <typename U> object<T>& operator=(object<U>&& other) {
86         static_assert(is_same<T, void>::value, "Receiver must be compatible.");
87         reset(other.release());
88         return *this;
89     }
90 
swap(object<T> & other)91     void swap(object<T>& other) {
92         zx_handle_t tmp = value_;
93         value_ = other.value_;
94         other.value_ = tmp;
95     }
96 
duplicate(zx_rights_t rights,object<T> * result)97     zx_status_t duplicate(zx_rights_t rights, object<T>* result) const {
98         static_assert(object_traits<T>::supports_duplication,
99                       "Object must support duplication.");
100         zx_handle_t h = ZX_HANDLE_INVALID;
101         zx_status_t status = zx_handle_duplicate(value_, rights, &h);
102         result->reset(h);
103         return status;
104     }
105 
replace(zx_rights_t rights,object<T> * result)106     zx_status_t replace(zx_rights_t rights, object<T>* result) {
107         zx_handle_t h = ZX_HANDLE_INVALID;
108         zx_status_t status = zx_handle_replace(value_, rights, &h);
109         // We store ZX_HANDLE_INVALID to value_ before calling reset on result
110         // in case result == this.
111         value_ = ZX_HANDLE_INVALID;
112         result->reset(h);
113         return status;
114     }
115 
wait_one(zx_signals_t signals,zx::time deadline,zx_signals_t * pending)116     zx_status_t wait_one(zx_signals_t signals, zx::time deadline,
117                          zx_signals_t* pending) const {
118         static_assert(object_traits<T>::supports_wait, "Object is not waitable.");
119         return zx_object_wait_one(value_, signals, deadline.get(), pending);
120     }
121 
wait_async(const object<port> & port,uint64_t key,zx_signals_t signals,uint32_t options)122     zx_status_t wait_async(const object<port>& port, uint64_t key,
123                            zx_signals_t signals, uint32_t options) const {
124         static_assert(object_traits<T>::supports_wait, "Object is not waitable.");
125         return zx_object_wait_async(value_, port.get(), key, signals, options);
126     }
127 
wait_many(zx_wait_item_t * wait_items,uint32_t count,zx::time deadline)128     static zx_status_t wait_many(zx_wait_item_t* wait_items, uint32_t count, zx::time deadline) {
129         static_assert(object_traits<T>::supports_wait, "Object is not waitable.");
130         return zx_object_wait_many(wait_items, count, deadline.get());
131     }
132 
signal(uint32_t clear_mask,uint32_t set_mask)133     zx_status_t signal(uint32_t clear_mask, uint32_t set_mask) const {
134         static_assert(object_traits<T>::supports_user_signal,
135                       "Object must support user signals.");
136         return zx_object_signal(get(), clear_mask, set_mask);
137     }
138 
signal_peer(uint32_t clear_mask,uint32_t set_mask)139     zx_status_t signal_peer(uint32_t clear_mask, uint32_t set_mask) const {
140         static_assert(object_traits<T>::supports_user_signal,
141                       "Object must support user signals.");
142         static_assert(object_traits<T>::has_peer_handle,
143                       "Object must have peer object.");
144         return zx_object_signal_peer(get(), clear_mask, set_mask);
145     }
146 
get_info(uint32_t topic,void * buffer,size_t buffer_size,size_t * actual_count,size_t * avail_count)147     zx_status_t get_info(uint32_t topic, void* buffer,
148                          size_t buffer_size,
149                          size_t* actual_count, size_t* avail_count) const {
150         return zx_object_get_info(get(), topic, buffer, buffer_size, actual_count, avail_count);
151     }
152 
get_child(uint64_t koid,zx_rights_t rights,object<void> * result)153     zx_status_t get_child(uint64_t koid, zx_rights_t rights,
154                           object<void>* result) const {
155         // Allow for |result| and |this| being the same container, though that
156         // can only happen for |T=void|, due to strict aliasing.
157         object<void> h;
158         zx_status_t status = zx_object_get_child(
159             value_, koid, rights, h.reset_and_get_address());
160         result->reset(h.release());
161         return status;
162     }
163 
get_property(uint32_t property,void * value,size_t size)164     zx_status_t get_property(uint32_t property, void* value,
165                              size_t size) const {
166         return zx_object_get_property(get(), property, value, size);
167     }
168 
set_property(uint32_t property,const void * value,size_t size)169     zx_status_t set_property(uint32_t property, const void* value,
170                              size_t size) const {
171         return zx_object_set_property(get(), property, value, size);
172     }
173 
get_cookie(const object_base & scope,uint64_t * cookie)174     zx_status_t get_cookie(const object_base& scope, uint64_t *cookie) const {
175         return zx_object_get_cookie(get(), scope.get(), cookie);
176     }
177 
set_cookie(const object_base & scope,uint64_t cookie)178     zx_status_t set_cookie(const object_base& scope, uint64_t cookie) const {
179         return zx_object_set_cookie(get(), scope.get(), cookie);
180     }
181 
set_profile(const object<profile> & profile,uint32_t options)182     zx_status_t set_profile(const object<profile>& profile, uint32_t options) const {
183         return zx_object_set_profile(get(), profile.get(), options);
184     }
185 
186 private:
187     template <typename A, typename B> struct is_same {
188         static const bool value = false;
189     };
190 
191     template <typename A> struct is_same<A, A> {
192         static const bool value = true;
193     };
194 };
195 
196 template <typename T> bool operator==(const object<T>& a, const object<T>& b) {
197     return a.get() == b.get();
198 }
199 
200 template <typename T> bool operator!=(const object<T>& a, const object<T>& b) {
201     return !(a == b);
202 }
203 
204 template <typename T> bool operator<(const object<T>& a, const object<T>& b) {
205     return a.get() < b.get();
206 }
207 
208 template <typename T> bool operator>(const object<T>& a, const object<T>& b) {
209     return a.get() > b.get();
210 }
211 
212 template <typename T> bool operator<=(const object<T>& a, const object<T>& b) {
213     return !(a.get() > b.get());
214 }
215 
216 template <typename T> bool operator>=(const object<T>& a, const object<T>& b) {
217     return !(a.get() < b.get());
218 }
219 
220 template <typename T> bool operator==(zx_handle_t a, const object<T>& b) {
221     return a == b.get();
222 }
223 
224 template <typename T> bool operator!=(zx_handle_t a, const object<T>& b) {
225     return !(a == b);
226 }
227 
228 template <typename T> bool operator<(zx_handle_t a, const object<T>& b) {
229     return a < b.get();
230 }
231 
232 template <typename T> bool operator>(zx_handle_t a, const object<T>& b) {
233     return a > b.get();
234 }
235 
236 template <typename T> bool operator<=(zx_handle_t a, const object<T>& b) {
237     return !(a > b.get());
238 }
239 
240 template <typename T> bool operator>=(zx_handle_t a, const object<T>& b) {
241     return !(a < b.get());
242 }
243 
244 template <typename T> bool operator==(const object<T>& a, zx_handle_t b) {
245     return a.get() == b;
246 }
247 
248 template <typename T> bool operator!=(const object<T>& a, zx_handle_t b) {
249     return !(a == b);
250 }
251 
252 template <typename T> bool operator<(const object<T>& a, zx_handle_t b) {
253     return a.get() < b;
254 }
255 
256 template <typename T> bool operator>(const object<T>& a, zx_handle_t b) {
257     return a.get() > b;
258 }
259 
260 template <typename T> bool operator<=(const object<T>& a, zx_handle_t b) {
261     return !(a.get() > b);
262 }
263 
264 template <typename T> bool operator>=(const object<T>& a, zx_handle_t b) {
265     return !(a.get() < b);
266 }
267 
268 // Wraps a handle to an object to provide type-safe access to its operations
269 // but does not take ownership of it.  The handle is not closed when the
270 // wrapper is destroyed.
271 //
272 // All use of unowned<object<T>> as an object<T> is via a dereference operator,
273 // as illustrated below:
274 //
275 // void do_something(const zx::event& event);
276 //
277 // void example(zx_handle_t event_handle) {
278 //     do_something(*zx::unowned<event>(event_handle));
279 // }
280 //
281 // Convenience aliases are provided for all object types, for example:
282 //
283 // zx::unowned_event(handle)->signal(..)
284 template <typename T>
285 class unowned final {
286 public:
287     explicit unowned(zx_handle_t h) : value_(h) {}
288     explicit unowned(const T& owner) : unowned(owner.get()) {}
289     explicit unowned(unowned& other) : unowned(*other) {}
290     constexpr unowned() = default;
291     unowned(unowned&& other) = default;
292 
293     ~unowned() { release_value(); }
294 
295     unowned& operator=(unowned& other) {
296         *this = unowned(other);
297         return *this;
298     }
299     unowned& operator=(unowned&& other) {
300         release_value();
301         value_ = static_cast<T&&>(other.value_);
302         return *this;
303     }
304 
305     const T& operator*() const { return value_; }
306     const T* operator->() const { return &value_; }
307 
308 private:
309     void release_value() {
310         zx_handle_t h = value_.release();
311         static_cast<void>(h);
312     }
313 
314     T value_;
315 };
316 
317 } // namespace zx
318 
319 #endif  // LIB_ZX_OBJECT_H_
320