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