| // Copyright 2019 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 SRC_TESTING_LOADBENCH_OBJECT_H_ | |
| #define SRC_TESTING_LOADBENCH_OBJECT_H_ | |
| #include <lib/syslog/cpp/macros.h> | |
| #include <lib/zx/channel.h> | |
| #include <lib/zx/event.h> | |
| #include <lib/zx/port.h> | |
| #include <lib/zx/profile.h> | |
| #include <lib/zx/time.h> | |
| #include <lib/zx/timer.h> | |
| #include <string> | |
| #include <unordered_map> | |
| #include <utility> | |
| #include <vector> | |
| // Abstract base for objects. | |
| class Object { | |
| public: | |
| virtual ~Object() = default; | |
| virtual zx_obj_type_t type() const = 0; | |
| static void CloseHandles() { handles_.clear(); } | |
| protected: | |
| // Utility to create a zx::handle-based object. The actual handle is maintained in a static handle | |
| // table for the lifetime of the workload. The return value is an unowned handle so that | |
| // subclasses of Object that have handle members may be copiable. | |
| template <typename T, typename... Args> | |
| static zx::unowned<T> CreateHandle(Args&&... args) { | |
| T result; | |
| const auto status = T::create(std::forward<Args>(args)..., &result); | |
| FX_CHECK(status == ZX_OK); | |
| const auto handle = result.release(); | |
| handles_.emplace_back(handle); | |
| return zx::unowned<T>{handle}; | |
| } | |
| // Similar to above for creating peered objects. | |
| template <typename T, typename... Args> | |
| static std::pair<zx::unowned<T>, zx::unowned<T>> CreateHandlePair(Args&&... args) { | |
| std::pair<T, T> result; | |
| const auto status = T::create(std::forward<Args>(args)..., &result.first, &result.second); | |
| FX_CHECK(status == ZX_OK); | |
| const auto handle_first = result.first.release(); | |
| handles_.emplace_back(handle_first); | |
| const auto handle_second = result.second.release(); | |
| handles_.emplace_back(handle_second); | |
| return {zx::unowned<T>{handle_first}, zx::unowned<T>{handle_second}}; | |
| } | |
| private: | |
| inline static std::vector<zx::handle> handles_{}; | |
| }; | |
| // CRTP type that provides common functionality for handle-based objects. ZxType must be an owned | |
| // libzx object type (i.e. not an instantiation of zx::unowned<>). | |
| template <typename T, typename ZxType> | |
| class ObjectBase : public Object { | |
| public: | |
| using Base = ObjectBase; | |
| inline static constexpr auto Type = ZxType::TYPE; | |
| ~ObjectBase() override {} | |
| zx_obj_type_t type() const override { return Type; } | |
| zx::unowned<ZxType>& operator->() { return object_; } | |
| zx::unowned<ZxType>& object() { return object_; } | |
| zx::unowned<ZxType>& object() const { return object_; } | |
| template <typename... Args> | |
| static std::unique_ptr<T> Create(Args&&... args) { | |
| return std::make_unique<T>(std::forward<Args>(args)...); | |
| } | |
| protected: | |
| template <typename... Args> | |
| ObjectBase(Args&&... args) : object_{CreateHandle<ZxType>(std::forward<Args>(args)...)} {} | |
| private: | |
| zx::unowned<ZxType> object_; | |
| }; | |
| template <typename T, typename ZxType> | |
| class PairObjectBase : public Object { | |
| public: | |
| using Base = PairObjectBase; | |
| inline static constexpr auto Type = ZxType::TYPE; | |
| ~PairObjectBase() override {} | |
| zx_obj_type_t type() const override { return Type; } | |
| auto* operator->() { return &objects_; } | |
| auto bind() { return std::tie(objects_.first, objects_.second); } | |
| template <typename... Args> | |
| static std::unique_ptr<T> Create(Args&&... args) { | |
| return std::make_unique<T>(std::forward<Args>(args)...); | |
| } | |
| protected: | |
| template <typename... Args> | |
| PairObjectBase(Args&&... args) | |
| : objects_{CreateHandlePair<ZxType>(std::forward<Args>(args)...)} {} | |
| private: | |
| std::pair<zx::unowned<ZxType>, zx::unowned<ZxType>> objects_; | |
| }; | |
| // Define objects. | |
| struct EventObject : ObjectBase<EventObject, zx::event> { | |
| EventObject(uint32_t options = 0) : Base{options} {} | |
| }; | |
| struct TimerObject : ObjectBase<TimerObject, zx::timer> { | |
| TimerObject() : Base{ZX_TIMER_SLACK_CENTER, ZX_CLOCK_MONOTONIC} {} | |
| }; | |
| struct PortObject : ObjectBase<PortObject, zx::port> { | |
| PortObject(uint32_t options = 0) : Base{options} {} | |
| static constexpr zx_signals_t kTerminateSignal = ZX_USER_SIGNAL_0; | |
| static zx::unowned_event GetTerminateEvent() { | |
| static zx::unowned_event terminate_event{CreateHandle<zx::event>(0)}; | |
| return zx::unowned_event{terminate_event->get()}; | |
| } | |
| }; | |
| struct ChannelObject : PairObjectBase<ChannelObject, zx::channel> { | |
| ChannelObject(uint32_t options = 0) : Base{options} {} | |
| }; | |
| #endif // SRC_TESTING_LOADBENCH_OBJECT_H_ |