#include "handles.h" #include "common.h" #include namespace { constexpr uint32_t kIndexBits = 17; constexpr uint32_t kIndexMask = (1u << kIndexBits) - 1; // 0x1FFFF constexpr uint32_t kGenerationMask = (1u << 15) - 1; // 0x7FFF constexpr unsigned kGenerationShift = kIndexBits; // 17 inline uint32_t indexOf(Handle h) { return h & kIndexMask; } inline uint32_t generationOf(Handle h) { return (h >> kGenerationShift) & kGenerationMask; } inline Handle makeHandle(uint32_t index, uint32_t gen) { return (gen << kGenerationShift) | index; } inline bool isPseudo(Handle h) { return static_cast(h) < 0; } } // namespace Handle HandleTable::create(ObjectHeader *obj, uint32_t grantedAccess, uint32_t flags) { std::unique_lock lk(mu_); uint32_t idx; if (!freeList_.empty()) { idx = freeList_.back(); freeList_.pop_back(); } else { idx = static_cast(slots_.size()); slots_.push_back(HandleEntry{}); } auto &e = slots_[idx]; // Initialize generation if needed if (e.generation == 0) { e.generation = 1; } const uint16_t gen = e.generation; // Table owns one pointer ref for this entry detail::ref(obj); // Initialize entry e.obj = obj; e.grantedAccess = grantedAccess; e.flags = flags; e.typeCache = obj->type; const Handle h = makeHandle(idx, gen); obj->handleCount.fetch_add(1, std::memory_order_acq_rel); return h; } bool HandleTable::get(Handle h, HandleEntry &out, Pin &pinOut) { if (isPseudo(h)) { return false; // pseudo-handles have no entries } std::shared_lock lk(mu_); const auto idx = indexOf(h); if (idx >= slots_.size()) { return false; } const auto &e = slots_[idx]; if (e.generation != generationOf(h) || !e.obj) { return false; } detail::ref(e.obj); // pin under the lock pinOut = Pin::adopt(e.obj); // dtor will deref out = e; return true; } bool HandleTable::close(Handle h) { if (isPseudo(h)) { return true; // no-op, success } std::unique_lock lk(mu_); const auto idx = indexOf(h); if (idx >= slots_.size()) { return false; } auto &e = slots_[idx]; if (e.generation != generationOf(h) || !e.obj || e.flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) { return false; } ObjectHeader *obj = e.obj; e.obj = nullptr; // tombstone auto newHandleCnt = obj->handleCount.fetch_sub(1, std::memory_order_acq_rel) - 1; // bump generation & recycle while still holding the lock e.generation = static_cast((e.generation + 1) & kGenerationMask); freeList_.push_back(idx); lk.unlock(); // if (newHandleCnt == 0) { // namespaceOnHandleCountZero(obj); // } detail::deref(obj); return true; } bool HandleTable::setInformation(Handle h, uint32_t mask, uint32_t value) { if (isPseudo(h)) { return true; // no-op, success } std::unique_lock lk(mu_); const auto idx = indexOf(h); if (idx >= slots_.size()) { return false; } auto &e = slots_[idx]; if (e.generation != generationOf(h) || !e.obj) { return false; } constexpr uint32_t kAllowedFlags = HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE; mask &= kAllowedFlags; e.flags = (e.flags & ~mask) | (value & mask); return true; } bool HandleTable::getInformation(Handle h, uint32_t *outFlags) const { if (!outFlags) { return false; } if (isPseudo(h)) { *outFlags = 0; return true; } std::shared_lock lk(mu_); const auto idx = indexOf(h); if (idx >= slots_.size()) { return false; } const auto &e = slots_[idx]; if (e.generation != generationOf(h) || !e.obj) { return false; } *outFlags = e.flags; return true; } bool HandleTable::duplicateTo(Handle src, HandleTable &dst, Handle *out, uint32_t desiredAccess, bool inherit, uint32_t options) { if (!out) return false; // Pseudo-handles: resolve to a Borrow of the live object // if (isPseudo(src)) { // Pin pin = resolvePseudoBorrow(src); // if (!pin) // return false; // const uint32_t granted = desiredAccess; // or compute from type; pseudo has full rights to self // *out = dst.create(pin.obj, granted, inherit ? HANDLE_FLAG_INHERIT : 0); // return true; // } HandleEntry e{}; Pin pin; if (!get(src, e, pin)) return false; bool closeSource = (options & DUPLICATE_CLOSE_SOURCE) != 0; if (closeSource && (e.flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) != 0) { // Cannot close source if it is protected return false; } uint32_t effAccess = (options & DUPLICATE_SAME_ACCESS) ? e.grantedAccess : (desiredAccess & e.grantedAccess); const uint32_t flags = (inherit ? HANDLE_FLAG_INHERIT : 0); *out = dst.create(pin.obj, effAccess, flags); if (closeSource) { close(src); } return true; } namespace handles { static Data datas[MAX_HANDLES]; Data dataFromHandle(void *handle, bool pop) { uintptr_t index = (uintptr_t)handle; if (index > 0 && index < MAX_HANDLES) { Data ret = datas[index]; if (pop) datas[index] = Data{}; return ret; } return Data{}; } void *allocDataHandle(Data data) { for (size_t i = 1; i < MAX_HANDLES; i++) { if (datas[i].type == TYPE_UNUSED) { datas[i] = data; return (void *)i; } } printf("Out of handles\n"); assert(0); } } // namespace handles