blob: 710b4741f14bb2b3605090f37a6a9bd48668170a [file] [log] [blame]
// Copyright 2016 The Fuchsia 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 LIB_ZX_OBJECT_H_
#define LIB_ZX_OBJECT_H_
#include <lib/zx/object_traits.h>
#include <lib/zx/time.h>
#include <zircon/syscalls.h>
#include <zircon/types.h>
namespace zx {
class port;
class profile;
// Wraps and takes ownership of a handle to an object.
//
// Used for code that wants to operate generically on the zx_handle_t value
// inside a |zx::object| and doesn't otherwise need a template parameter.
//
// The handle is automatically closed when the wrapper is destroyed.
class object_base {
public:
void reset(zx_handle_t value = ZX_HANDLE_INVALID) {
close();
value_ = value;
}
bool is_valid() const { return value_ != ZX_HANDLE_INVALID; }
explicit operator bool() const { return is_valid(); }
zx_handle_t get() const { return value_; }
// Reset the underlying handle, and then get the address of the
// underlying internal handle storage.
//
// Note: The intended purpose is to facilitate interactions with C
// APIs which expect to be provided a pointer to a handle used as
// an out parameter.
zx_handle_t* reset_and_get_address() {
reset();
return &value_;
}
__attribute__((warn_unused_result)) zx_handle_t release() {
zx_handle_t result = value_;
value_ = ZX_HANDLE_INVALID;
return result;
}
zx_status_t get_info(uint32_t topic, void* buffer, size_t buffer_size, size_t* actual_count,
size_t* avail_count) const {
return zx_object_get_info(get(), topic, buffer, buffer_size, actual_count, avail_count);
}
zx_status_t get_property(uint32_t property, void* value, size_t size) const {
return zx_object_get_property(get(), property, value, size);
}
zx_status_t set_property(uint32_t property, const void* value, size_t size) const {
return zx_object_set_property(get(), property, value, size);
}
protected:
constexpr object_base() : value_(ZX_HANDLE_INVALID) {}
explicit object_base(zx_handle_t value) : value_(value) {}
~object_base() { close(); }
object_base(const object_base&) = delete;
void operator=(const object_base&) = delete;
void close() {
if (value_ != ZX_HANDLE_INVALID) {
zx_handle_close(value_);
value_ = ZX_HANDLE_INVALID;
}
}
zx_handle_t value_;
};
// Forward declaration for borrow method.
template <typename T>
class unowned;
// Provides type-safe access to operations on a handle.
template <typename T>
class object : public object_base {
public:
constexpr object() = default;
explicit object(zx_handle_t value) : object_base(value) {}
template <typename U>
object(object<U>&& other) : object_base(other.release()) {
static_assert(is_same<T, void>::value, "Receiver must be compatible.");
}
template <typename U>
object<T>& operator=(object<U>&& other) {
static_assert(is_same<T, void>::value, "Receiver must be compatible.");
reset(other.release());
return *this;
}
void swap(object<T>& other) {
zx_handle_t tmp = value_;
value_ = other.value_;
other.value_ = tmp;
}
zx_status_t duplicate(zx_rights_t rights, object<T>* result) const {
static_assert(object_traits<T>::supports_duplication, "Object must support duplication.");
zx_handle_t h = ZX_HANDLE_INVALID;
zx_status_t status = zx_handle_duplicate(value_, rights, &h);
result->reset(h);
return status;
}
zx_status_t replace(zx_rights_t rights, object<T>* result) {
zx_handle_t h = ZX_HANDLE_INVALID;
zx_status_t status = zx_handle_replace(value_, rights, &h);
// We store ZX_HANDLE_INVALID to value_ before calling reset on result
// in case result == this.
value_ = ZX_HANDLE_INVALID;
result->reset(h);
return status;
}
zx_status_t wait_one(zx_signals_t signals, zx::time deadline, zx_signals_t* pending) const {
static_assert(object_traits<T>::supports_wait, "Object is not waitable.");
return zx_object_wait_one(value_, signals, deadline.get(), pending);
}
zx_status_t wait_async(const object<port>& port, uint64_t key, zx_signals_t signals,
uint32_t options) const {
static_assert(object_traits<T>::supports_wait, "Object is not waitable.");
return zx_object_wait_async(value_, port.get(), key, signals, options);
}
static zx_status_t wait_many(zx_wait_item_t* wait_items, uint32_t count, zx::time deadline) {
static_assert(object_traits<T>::supports_wait, "Object is not waitable.");
return zx_object_wait_many(wait_items, count, deadline.get());
}
zx_status_t signal(uint32_t clear_mask, uint32_t set_mask) const {
static_assert(object_traits<T>::supports_user_signal, "Object must support user signals.");
return zx_object_signal(get(), clear_mask, set_mask);
}
zx_status_t signal_peer(uint32_t clear_mask, uint32_t set_mask) const {
static_assert(object_traits<T>::supports_user_signal, "Object must support user signals.");
static_assert(object_traits<T>::has_peer_handle, "Object must have peer object.");
return zx_object_signal_peer(get(), clear_mask, set_mask);
}
zx_status_t get_child(uint64_t koid, zx_rights_t rights, object<void>* result) const {
static_assert(object_traits<T>::supports_get_child, "Object must support getting children.");
// Allow for |result| and |this| being the same container, though that
// can only happen for |T=void|, due to strict aliasing.
object<void> h;
zx_status_t status = zx_object_get_child(value_, koid, rights, h.reset_and_get_address());
result->reset(h.release());
return status;
}
zx_status_t set_profile(const object<profile>& profile, uint32_t options) const {
static_assert(object_traits<T>::supports_set_profile,
"Object must support scheduling profiles.");
return zx_object_set_profile(get(), profile.get(), options);
}
// Returns a type-safe wrapper of the underlying handle that does not claim ownership.
unowned<T> borrow() const { return unowned<T>(get()); }
private:
template <typename A, typename B>
struct is_same {
static const bool value = false;
};
template <typename A>
struct is_same<A, A> {
static const bool value = true;
};
};
template <typename T>
bool operator==(const object<T>& a, const object<T>& b) {
return a.get() == b.get();
}
template <typename T>
bool operator!=(const object<T>& a, const object<T>& b) {
return !(a == b);
}
template <typename T>
bool operator<(const object<T>& a, const object<T>& b) {
return a.get() < b.get();
}
template <typename T>
bool operator>(const object<T>& a, const object<T>& b) {
return a.get() > b.get();
}
template <typename T>
bool operator<=(const object<T>& a, const object<T>& b) {
return !(a.get() > b.get());
}
template <typename T>
bool operator>=(const object<T>& a, const object<T>& b) {
return !(a.get() < b.get());
}
template <typename T>
bool operator==(zx_handle_t a, const object<T>& b) {
return a == b.get();
}
template <typename T>
bool operator!=(zx_handle_t a, const object<T>& b) {
return !(a == b);
}
template <typename T>
bool operator<(zx_handle_t a, const object<T>& b) {
return a < b.get();
}
template <typename T>
bool operator>(zx_handle_t a, const object<T>& b) {
return a > b.get();
}
template <typename T>
bool operator<=(zx_handle_t a, const object<T>& b) {
return !(a > b.get());
}
template <typename T>
bool operator>=(zx_handle_t a, const object<T>& b) {
return !(a < b.get());
}
template <typename T>
bool operator==(const object<T>& a, zx_handle_t b) {
return a.get() == b;
}
template <typename T>
bool operator!=(const object<T>& a, zx_handle_t b) {
return !(a == b);
}
template <typename T>
bool operator<(const object<T>& a, zx_handle_t b) {
return a.get() < b;
}
template <typename T>
bool operator>(const object<T>& a, zx_handle_t b) {
return a.get() > b;
}
template <typename T>
bool operator<=(const object<T>& a, zx_handle_t b) {
return !(a.get() > b);
}
template <typename T>
bool operator>=(const object<T>& a, zx_handle_t b) {
return !(a.get() < b);
}
// Wraps a handle to an object to provide type-safe access to its operations
// but does not take ownership of it. The handle is not closed when the
// wrapper is destroyed.
//
// All use of unowned<object<T>> as an object<T> is via a dereference operator,
// as illustrated below:
//
// void do_something(const zx::event& event);
//
// void example(zx_handle_t event_handle) {
// do_something(*zx::unowned<event>(event_handle));
// }
//
// Convenience aliases are provided for all object types, for example:
//
// zx::unowned_event(handle)->signal(..)
template <typename T>
class unowned final {
public:
explicit unowned(zx_handle_t h) : value_(h) {}
explicit unowned(const T& owner) : unowned(owner.get()) {}
explicit unowned(const unowned& other) : unowned(*other) {}
constexpr unowned() = default;
unowned(unowned&& other) = default;
~unowned() { release_value(); }
unowned& operator=(const unowned& other) {
if (&other == this) {
return *this;
}
*this = unowned(other);
return *this;
}
unowned& operator=(unowned&& other) {
release_value();
value_ = static_cast<T&&>(other.value_);
return *this;
}
const T& operator*() const { return value_; }
const T* operator->() const { return &value_; }
private:
void release_value() {
zx_handle_t h = value_.release();
static_cast<void>(h);
}
T value_;
};
template <typename T>
bool operator==(const unowned<T>& a, const unowned<T>& b) {
return a->get() == b->get();
}
template <typename T>
bool operator!=(const unowned<T>& a, const unowned<T>& b) {
return !(a == b);
}
template <typename T>
bool operator<(const unowned<T>& a, const unowned<T>& b) {
return a->get() < b->get();
}
template <typename T>
bool operator>(const unowned<T>& a, const unowned<T>& b) {
return a->get() > b->get();
}
template <typename T>
bool operator<=(const unowned<T>& a, const unowned<T>& b) {
return !(a > b);
}
template <typename T>
bool operator>=(const unowned<T>& a, const unowned<T>& b) {
return !(a < b);
}
template <typename T>
bool operator==(zx_handle_t a, const unowned<T>& b) {
return a == b->get();
}
template <typename T>
bool operator!=(zx_handle_t a, const unowned<T>& b) {
return !(a == b);
}
template <typename T>
bool operator<(zx_handle_t a, const unowned<T>& b) {
return a < b->get();
}
template <typename T>
bool operator>(zx_handle_t a, const unowned<T>& b) {
return a > b->get();
}
template <typename T>
bool operator<=(zx_handle_t a, const unowned<T>& b) {
return !(a > b);
}
template <typename T>
bool operator>=(zx_handle_t a, const unowned<T>& b) {
return !(a < b);
}
template <typename T>
bool operator==(const unowned<T>& a, zx_handle_t b) {
return a->get() == b;
}
template <typename T>
bool operator!=(const unowned<T>& a, zx_handle_t b) {
return !(a == b);
}
template <typename T>
bool operator<(const unowned<T>& a, zx_handle_t b) {
return a->get() < b;
}
template <typename T>
bool operator>(const unowned<T>& a, zx_handle_t b) {
return a->get() > b;
}
template <typename T>
bool operator<=(const unowned<T>& a, zx_handle_t b) {
return !(a > b);
}
template <typename T>
bool operator>=(const unowned<T>& a, zx_handle_t b) {
return !(a < b);
}
} // namespace zx
#endif // LIB_ZX_OBJECT_H_