#pragma once #include "common.h" #include #include #include #include #include #include enum class ObjectType : uint16_t { File, Mapped, Process, Token, Mutex, Event, Semaphore, Thread, Heap, RegistryKey, }; struct ObjectHeader { const ObjectType type; std::atomic pointerCount{1}; std::atomic handleCount{0}; explicit ObjectHeader(ObjectType t) : type(t) {} virtual ~ObjectHeader() = default; [[nodiscard]] virtual bool isWaitable() const { return false; } virtual void onDestroy() {} }; namespace detail { inline void ref(ObjectHeader *o) { o->pointerCount.fetch_add(1, std::memory_order_acq_rel); } inline void deref(ObjectHeader *o) { if (o->pointerCount.fetch_sub(1, std::memory_order_acq_rel) == 1) { o->onDestroy(); delete o; } } } // namespace detail struct WaitableObject : ObjectHeader { std::atomic signaled{false}; std::mutex m; std::condition_variable_any cv; using ObjectHeader::ObjectHeader; [[nodiscard]] bool isWaitable() const override { return true; } }; template struct Pin { enum class Tag { Acquire, Adopt }; T *obj = nullptr; Pin() = default; Pin(T *o, Tag t) : obj(o) { if (obj && t == Tag::Acquire) { detail::ref(obj); } } static Pin acquire(ObjectHeader *o) { return {o, Tag::Acquire}; } static Pin adopt(ObjectHeader *o) { return {o, Tag::Adopt}; } Pin(const Pin &) = delete; Pin &operator=(const Pin &) = delete; Pin(Pin &&other) noexcept : obj(std::exchange(other.obj, nullptr)) {} Pin &operator=(Pin &&other) noexcept { if (this != &other) { reset(); obj = std::exchange(other.obj, nullptr); } return *this; } ~Pin() { reset(); } ObjectHeader *release() { return std::exchange(obj, nullptr); } void reset() { if (obj) { detail::deref(obj); obj = nullptr; } } T *operator->() const { return obj; } T &operator*() const { return *obj; } [[nodiscard]] T *get() const { return obj; } explicit operator bool() const { return obj != nullptr; } template Pin downcast() && { if (obj && obj->type == U::kType) { auto *u = static_cast(obj); obj = nullptr; return Pin::adopt(u); } return Pin{}; } }; constexpr DWORD HANDLE_FLAG_INHERIT = 0x1; constexpr DWORD HANDLE_FLAG_PROTECT_FROM_CLOSE = 0x2; constexpr DWORD DUPLICATE_CLOSE_SOURCE = 0x1; constexpr DWORD DUPLICATE_SAME_ACCESS = 0x2; struct HandleMeta { uint32_t grantedAccess; // effective access mask for this handle uint32_t flags; // inherit/protect/etc ObjectType typeCache; // cached ObjectType for fast getAs uint16_t generation; // must match handle’s generation }; // template // struct HandleRef { // Pin obj; // HandleMeta meta; // HandleRef() = default; // HandleRef(Pin o, HandleMeta m) : obj(std::move(o)), meta(m) {} // explicit operator bool() const { return obj.operator bool(); } // }; class HandleTable { public: HANDLE create(ObjectHeader *obj, uint32_t grantedAccess, uint32_t flags); bool close(HANDLE h); bool get(HANDLE h, Pin &pinOut, HandleMeta *metaOut = nullptr); template Pin getAs(HANDLE h, HandleMeta *metaOut = nullptr) { static_assert(std::is_base_of_v, "T must derive from ObjectHeader"); Pin pin; HandleMeta metaOutLocal{}; if (!metaOut) { metaOut = &metaOutLocal; } if (!get(h, pin, metaOut)) { return {}; } if constexpr (std::is_same_v) { return std::move(pin); } else if (metaOut->typeCache != T::kType || pin->type != T::kType) { return {}; } else { // Cast directly to T* and transfer ownership to Pin return Pin::adopt(static_cast(pin.release())); } } bool setInformation(HANDLE h, uint32_t mask, uint32_t value); bool getInformation(HANDLE h, uint32_t *outFlags) const; bool duplicateTo(HANDLE src, HandleTable &dst, HANDLE *out, uint32_t desiredAccess, bool inherit, uint32_t options); private: struct HandleEntry { struct ObjectHeader *obj; HandleMeta meta; }; std::vector slots_; std::vector freeList_; mutable std::shared_mutex mu_; }; namespace wibo { extern HandleTable &handles(); }