| // Copyright 2018 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_INSPECT_CPP_VMO_STATE_H_ |
| #define LIB_INSPECT_CPP_VMO_STATE_H_ |
| |
| #include <lib/async/dispatcher.h> |
| #include <lib/fit/function.h> |
| #include <lib/fit/promise.h> |
| #include <lib/fit/sequencer.h> |
| #include <lib/fit/thread_safety.h> |
| #include <lib/inspect/cpp/inspector.h> |
| #include <lib/inspect/cpp/vmo/block.h> |
| #include <lib/inspect/cpp/vmo/heap.h> |
| #include <lib/inspect/cpp/vmo/types.h> |
| |
| #include <iterator> |
| #include <map> |
| #include <mutex> |
| |
| namespace inspect { |
| |
| namespace internal { |
| |
| // |State| wraps a |Heap| and implements the Inspect VMO API on top of |
| // that heap. This class contains the low-level operations necessary to |
| // deal with the various Inspect types and wrappers to denote ownership of |
| // those values. |
| // |
| // This class should not be used directly, prefer to use |Inspector|. |
| class State final { |
| public: |
| // Create a new State wrapping the given Heap. |
| // On failure, returns nullptr. |
| static std::shared_ptr<State> Create(std::unique_ptr<Heap> heap); |
| |
| // Create a new State wrapping a new heap of the given size. |
| // On failure, returns an empty shared_ptr. |
| static std::shared_ptr<State> CreateWithSize(size_t size); |
| |
| // Destructor for State, which performs necessary cleanup. |
| ~State(); |
| |
| // Disallow copy and assign. |
| State(const State&) = delete; |
| State(State&&) = delete; |
| State& operator=(const State&) = delete; |
| State& operator=(State&&) = delete; |
| |
| // Obtain a reference to the wrapped VMO. |
| // This may be duplicated read-only to pass to a reader process. |
| const zx::vmo& GetVmo() const; |
| |
| // Obtain a read-only duplicate of the VMO backing this State. |
| bool DuplicateVmo(zx::vmo* vmo) const; |
| |
| // Obtain a copy of the VMO backing this state. |
| // |
| // Returns true on success, false otherwise. |
| bool Copy(zx::vmo* vmo) const; |
| |
| // Obtain a copy of the bytes in the VMO backing this state. |
| // |
| // Returns true on success, false otherwise. |
| bool CopyBytes(std::vector<uint8_t>* out) const; |
| |
| // Create a new |IntProperty| in the Inspect VMO. The returned value releases |
| // the property when destroyed. |
| IntProperty CreateIntProperty(const std::string& name, BlockIndex parent, int64_t value); |
| |
| // Create a new |UintProperty| in the Inspect VMO. The returned value releases |
| // the property when destroyed. |
| UintProperty CreateUintProperty(const std::string& name, BlockIndex parent, uint64_t value); |
| |
| // Create a new |DoubleProperty| in the Inspect VMO. The returned value releases |
| // the property when destroyed. |
| DoubleProperty CreateDoubleProperty(const std::string& name, BlockIndex parent, double value); |
| |
| // Create a new |BoolProperty| in the Inspect VMO. The returned value releases |
| // the property when destroyed. |
| BoolProperty CreateBoolProperty(const std::string& name, BlockIndex parent, bool value); |
| |
| // Create a new |IntArray| in the Inspect VMO. The returned value releases |
| // the array when destroyed. |
| IntArray CreateIntArray(const std::string& name, BlockIndex parent, size_t slots, |
| ArrayBlockFormat format); |
| |
| // Create a new |UintArray| in the Inspect VMO. The returned value releases |
| // the array when destroyed. |
| UintArray CreateUintArray(const std::string& name, BlockIndex parent, size_t slots, |
| ArrayBlockFormat format); |
| |
| // Create a new |DoubleArray| in the Inspect VMO. The returned value releases |
| // the array when destroyed. |
| DoubleArray CreateDoubleArray(const std::string& name, BlockIndex parent, size_t slots, |
| ArrayBlockFormat format); |
| |
| // Create a new |StringProperty| in the Inspect VMO. The returned value releases |
| // the property when destroyed. |
| StringProperty CreateStringProperty(const std::string& name, BlockIndex parent, |
| const std::string& value); |
| |
| // Create a new |ByteVectorProperty| in the Inspect VMO. The returned value releases |
| // the property when destroyed. |
| ByteVectorProperty CreateByteVectorProperty(const std::string& name, BlockIndex parent, |
| const std::vector<uint8_t>& value); |
| |
| // Create a new [Link] in the Inspect VMO. The returned node releases the link when destroyed. |
| // |
| // A Link is a low-level reference to a new Inspector linked off of the one managed by this |
| // state. A Link alone is not sufficient to populate the linked tree, see CreateLazyNode and |
| // CreateLazyValues. |
| Link CreateLink(const std::string& name, BlockIndex parent, const std::string& content, |
| LinkBlockDisposition disposition); |
| |
| // Create a new |Node| in the Inspect VMO. Nodes are refcounted such that values nested under the |
| // node remain valid until all such values values are destroyed. |
| Node CreateNode(const std::string& name, BlockIndex parent); |
| |
| // Create a special root |Node| in the Inspect VMO. This node is not backed by any storage, rather |
| // it allows clients to use the |Node| iterface to add properties and children directly to the |
| // root of the VMO. |
| Node CreateRootNode(); |
| |
| // Create a new |LazyNode| with a new named |Link| that calls the given callback with child |
| // disposition. |
| LazyNode CreateLazyNode(const std::string& name, BlockIndex parent, LazyNodeCallbackFn callback); |
| |
| // Create a new |LazyNode| with a new named |Link| that calls the given callback with inline |
| // disposition. |
| LazyNode CreateLazyValues(const std::string& name, BlockIndex parent, |
| LazyNodeCallbackFn callback); |
| |
| // Setters for various property types |
| void SetIntProperty(IntProperty* property, int64_t value); |
| void SetUintProperty(UintProperty* property, uint64_t value); |
| void SetDoubleProperty(DoubleProperty* property, double value); |
| void SetBoolProperty(BoolProperty* property, bool value); |
| void SetIntArray(IntArray* array, size_t index, int64_t value); |
| void SetUintArray(UintArray* array, size_t index, uint64_t value); |
| void SetDoubleArray(DoubleArray* array, size_t index, double value); |
| void SetStringProperty(StringProperty* property, const std::string& value); |
| void SetByteVectorProperty(ByteVectorProperty* property, const std::vector<uint8_t>& value); |
| |
| // Adders for various property types |
| void AddIntProperty(IntProperty* property, int64_t value); |
| void AddUintProperty(UintProperty* property, uint64_t value); |
| void AddDoubleProperty(DoubleProperty* property, double value); |
| void AddIntArray(IntArray* array, size_t index, int64_t value); |
| void AddUintArray(UintArray* array, size_t index, uint64_t value); |
| void AddDoubleArray(DoubleArray* array, size_t index, double value); |
| |
| // Subtractors for various property types |
| void SubtractIntProperty(IntProperty* property, int64_t value); |
| void SubtractUintProperty(UintProperty* property, uint64_t value); |
| void SubtractDoubleProperty(DoubleProperty* property, double value); |
| void SubtractIntArray(IntArray* array, size_t index, int64_t value); |
| void SubtractUintArray(UintArray* array, size_t index, uint64_t value); |
| void SubtractDoubleArray(DoubleArray* array, size_t index, double value); |
| |
| // Free various entities |
| void FreeIntProperty(IntProperty* property); |
| void FreeUintProperty(UintProperty* property); |
| void FreeDoubleProperty(DoubleProperty* property); |
| void FreeBoolProperty(BoolProperty* property); |
| void FreeIntArray(IntArray* array); |
| void FreeUintArray(UintArray* array); |
| void FreeDoubleArray(DoubleArray* array); |
| void FreeStringProperty(StringProperty* property); |
| void FreeByteVectorProperty(ByteVectorProperty* property); |
| void FreeLink(Link* link); |
| void FreeNode(Node* node); |
| void FreeLazyNode(LazyNode* lazy_node); |
| |
| // Get the names of all links in this state. |
| std::vector<std::string> GetLinkNames() const; |
| |
| // Call a specific link by name, return a promise for the Inspector it produces. |
| fit::promise<Inspector> CallLinkCallback(const std::string& name); |
| |
| // Create a unique name for children in this State. |
| // |
| // Returned strings are guaranteed to be unique and will start with the given prefix. |
| std::string UniqueName(const std::string& prefix); |
| |
| private: |
| // Holder for a LazyNodeCallbackFn. |
| // |
| // This class ensures that the callback function is only called once at a time, and it allows |
| // future calls to the callback to be cancelled to prevent calling it when the corresponding |
| // LazyNode has been deleted. |
| // |
| // This class is copyable and thread-safe. Each copy refers to the same underlying callback, and |
| // cancelling one copy cancels all copies. |
| class LazyNodeCallbackHolder { |
| public: |
| LazyNodeCallbackHolder() = default; |
| explicit LazyNodeCallbackHolder(LazyNodeCallbackFn callback) |
| : inner_(new Inner(std::move(callback))) {} |
| |
| // This class is copyable but not movable. This ensures LazyNodeCallbackHolder objects are |
| // always in a valid state. |
| LazyNodeCallbackHolder(const LazyNodeCallbackHolder&) = default; |
| LazyNodeCallbackHolder(LazyNodeCallbackHolder&&) = delete; |
| LazyNodeCallbackHolder& operator=(const LazyNodeCallbackHolder&) = default; |
| LazyNodeCallbackHolder& operator=(LazyNodeCallbackHolder&&) = delete; |
| |
| // Cancel and release the callback. Future attempts to call the callback will do nothing. |
| void cancel() { |
| std::lock_guard<std::mutex> lock(inner_->mutex); |
| inner_->callback = {}; |
| } |
| |
| // Call the callback if it is not cancelled. |
| fit::promise<Inspector> call() { |
| std::lock_guard<std::mutex> lock(inner_->mutex); |
| if (inner_->callback) { |
| return inner_->callback(); |
| } else { |
| return fit::make_result_promise<Inspector>(fit::error()); |
| } |
| } |
| |
| private: |
| // Inner structure to share a mutex and a callback. |
| struct Inner { |
| explicit Inner(LazyNodeCallbackFn fn) : callback(std::move(fn)) {} |
| |
| std::mutex mutex; |
| LazyNodeCallbackFn callback FIT_GUARDED(mutex); |
| }; |
| std::shared_ptr<Inner> inner_; |
| }; |
| |
| State(std::unique_ptr<Heap> heap, BlockIndex header) |
| : heap_(std::move(heap)), header_(header), next_unique_id_(0), next_unique_link_number_(0) {} |
| |
| void DecrementParentRefcount(BlockIndex value_index) __TA_REQUIRES(mutex_); |
| |
| // Helper method for creating a new VALUE block type. |
| zx_status_t InnerCreateValue(const std::string& name, BlockType type, BlockIndex parent_index, |
| BlockIndex* out_name, BlockIndex* out_value, |
| size_t min_size_required = kMinOrderSize) __TA_REQUIRES(mutex_); |
| |
| // Helper method to create a new LINK block that calls a callback when followed. |
| LazyNode InnerCreateLazyLink(const std::string& name, BlockIndex parent, |
| LazyNodeCallbackFn callback, LinkBlockDisposition disposition); |
| |
| // Returns true if the block is an extent, false otherwise. |
| constexpr bool IsExtent(const Block* block) { |
| return block && GetType(block) == BlockType::kExtent; |
| } |
| |
| // Helper to set the value of a string across its extents. |
| zx_status_t InnerSetStringExtents(BlockIndex string_index, const char* value, size_t length) |
| __TA_REQUIRES(mutex_); |
| |
| // Helper to free all extents for a given string. |
| // This leaves the string value allocated and empty. |
| void InnerFreeStringExtents(BlockIndex string_index) __TA_REQUIRES(mutex_); |
| |
| // Helper to create a new name block with the given name. |
| zx_status_t CreateName(const std::string& name, BlockIndex* out) __TA_REQUIRES(mutex_); |
| |
| // Helper function to create an array with the given name, number of slots, and format. |
| template <typename NumericType, typename WrapperType, BlockType BlockTypeValue> |
| WrapperType InnerCreateArray(const std::string& name, BlockIndex parent, size_t slots, |
| ArrayBlockFormat format); |
| |
| // Helper function to create a property with a byte format. |
| template <typename WrapperType, typename ValueType> |
| WrapperType InnerCreateProperty(const std::string& name, BlockIndex parent, const char* value, |
| size_t length, PropertyBlockFormat format); |
| |
| template <typename WrapperType> |
| void InnerSetProperty(WrapperType* property, const char* value, size_t length); |
| |
| // Helper function to delete String or ByteVector properties. |
| template <typename WrapperType> |
| void InnerFreePropertyWithExtents(WrapperType* property); |
| |
| // Helper function to set the value of a specific index in an array. |
| template <typename NumericType, typename WrapperType, BlockType BlockTypeValue> |
| void InnerSetArray(WrapperType* property, size_t index, NumericType value); |
| |
| // Helper function to perform an operation on a specific index in an array. |
| // Common operations are std::plus and std::minus. |
| template <typename NumericType, typename WrapperType, BlockType BlockTypeValue, |
| typename Operation> |
| void InnerOperationArray(WrapperType* property, size_t index, NumericType value); |
| |
| // Helper function to free an array type. |
| template <typename WrapperType> |
| void InnerFreeArray(WrapperType* value); |
| |
| // Helper function to generate a unique name for a link. |
| std::string UniqueLinkName(const std::string& prefix); |
| |
| // Mutex wrapping all fields in the state. |
| // The mutex is mutable to support locking when reading fields of a |
| // const reference to state. |
| mutable std::mutex mutex_; |
| |
| // Weak pointer reference to this object, used to pass shared pointers to children. |
| std::weak_ptr<State> weak_self_ptr_; |
| |
| // The wrapped |Heap|, protected by the mutex. |
| std::unique_ptr<Heap> heap_ FIT_GUARDED(mutex_); |
| |
| // Map from the key of a linked inspect tree to the callback that populates that tree. |
| // |
| // An ordered map is used to ensure consistent iteration ordering for clients reading this data. |
| std::map<std::string, LazyNodeCallbackHolder> link_callbacks_ FIT_GUARDED(mutex_); |
| |
| // The index for the header block containing the generation count |
| // to increment |
| BlockIndex header_ FIT_GUARDED(mutex_); |
| |
| // The next unique ID to give out from UniqueName. |
| // |
| // Uses the fastest available atomic uint64 type for fetch_and_add. |
| std::atomic_uint_fast64_t next_unique_id_; |
| |
| // Next value to be used as a suffix for links. |
| // |
| // Uses the fastest available atomic uint64 type for fetch_and_add. |
| std::atomic_uint_fast64_t next_unique_link_number_; |
| }; |
| |
| } // namespace internal |
| } // namespace inspect |
| |
| #endif // LIB_INSPECT_CPP_VMO_STATE_H_ |