mirror of
https://github.com/decompals/wibo.git
synced 2025-12-13 07:06:18 +00:00
Move main source files into src/
This commit is contained in:
238
src/handles.cpp
Normal file
238
src/handles.cpp
Normal file
@@ -0,0 +1,238 @@
|
||||
#include "handles.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uint32_t kHandleAlignShift = 2;
|
||||
// Max index that still yields HANDLE < 0x10000 with (index + 1) << 2
|
||||
constexpr uint32_t kCompatMaxIndex = (0xFFFFu >> kHandleAlignShift) - 1;
|
||||
// Delay reuse of small handles to avoid accidental stale aliasing
|
||||
constexpr uint32_t kQuarantineLen = 64;
|
||||
|
||||
inline uint32_t indexOf(HANDLE h) {
|
||||
uint32_t v = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(h));
|
||||
if (v == 0 || (v & ((1U << kHandleAlignShift) - 1)) != 0) {
|
||||
return UINT32_MAX;
|
||||
}
|
||||
return (v >> kHandleAlignShift) - 1;
|
||||
}
|
||||
|
||||
inline HANDLE makeHandle(uint32_t index) {
|
||||
uint32_t v = (index + 1) << kHandleAlignShift;
|
||||
return reinterpret_cast<HANDLE>(static_cast<uintptr_t>(v));
|
||||
}
|
||||
|
||||
inline bool isPseudo(HANDLE h) { return reinterpret_cast<int32_t>(h) < 0; }
|
||||
|
||||
} // namespace
|
||||
|
||||
HANDLE Handles::alloc(Pin<> obj, uint32_t grantedAccess, uint32_t flags) {
|
||||
std::unique_lock lk(m);
|
||||
|
||||
// Attempt to, in order:
|
||||
// 1) use a fresh index in the compat range (0..kCompatMaxIndex)
|
||||
// 2) reuse a recently-freed index in the compat range
|
||||
// 3) reuse a recently-freed index above the compat range
|
||||
// 4) use a fresh index above the compat range
|
||||
uint32_t idx;
|
||||
if (nextIndex <= kCompatMaxIndex) {
|
||||
idx = nextIndex++;
|
||||
if (idx >= mSlots.size()) {
|
||||
mSlots.emplace_back();
|
||||
}
|
||||
} else if (!mFreeBelow.empty()) {
|
||||
idx = mFreeBelow.back();
|
||||
mFreeBelow.pop_back();
|
||||
} else if (!mFreeAbove.empty()) {
|
||||
idx = mFreeAbove.back();
|
||||
mFreeAbove.pop_back();
|
||||
} else {
|
||||
idx = static_cast<uint32_t>(mSlots.size());
|
||||
mSlots.emplace_back();
|
||||
}
|
||||
|
||||
// Initialize entry
|
||||
auto &e = mSlots[idx];
|
||||
e.obj = obj.release(); // Transfer ownership
|
||||
e.meta.grantedAccess = grantedAccess;
|
||||
e.meta.flags = flags;
|
||||
e.meta.typeCache = e.obj->type;
|
||||
if (e.meta.generation == 0) {
|
||||
e.meta.generation = 1;
|
||||
}
|
||||
|
||||
HANDLE h = makeHandle(idx);
|
||||
e.obj->handleCount.fetch_add(1, std::memory_order_acq_rel);
|
||||
return h;
|
||||
}
|
||||
|
||||
Pin<> Handles::get(HANDLE h, HandleMeta *metaOut) {
|
||||
if (isPseudo(h)) {
|
||||
return {}; // pseudo-handles have no entries
|
||||
}
|
||||
|
||||
std::shared_lock lk(m);
|
||||
const auto idx = indexOf(h);
|
||||
if (idx >= mSlots.size()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto &e = mSlots[idx];
|
||||
if (!e.obj) {
|
||||
return {};
|
||||
}
|
||||
if (metaOut) {
|
||||
*metaOut = e.meta;
|
||||
}
|
||||
return Pin<>::acquire(e.obj);
|
||||
}
|
||||
|
||||
bool Handles::release(HANDLE h) {
|
||||
if (isPseudo(h)) {
|
||||
return true; // no-op, success
|
||||
}
|
||||
|
||||
std::unique_lock lk(m);
|
||||
const auto idx = indexOf(h);
|
||||
if (idx >= mSlots.size()) {
|
||||
return false;
|
||||
}
|
||||
auto &e = mSlots[idx];
|
||||
if (!e.obj || e.meta.flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectBase *obj = e.obj;
|
||||
const auto generation = e.meta.generation + 1;
|
||||
e = {}; // Clear entry
|
||||
e.meta.generation = generation;
|
||||
uint32_t handleCount = obj->handleCount.fetch_sub(1, std::memory_order_acq_rel) - 1;
|
||||
|
||||
if (idx <= kCompatMaxIndex) {
|
||||
mQuarantine.push_back(idx);
|
||||
if (mQuarantine.size() > kQuarantineLen) {
|
||||
mFreeBelow.push_back(mQuarantine.front());
|
||||
mQuarantine.pop_front();
|
||||
}
|
||||
} else {
|
||||
mFreeAbove.push_back(idx);
|
||||
}
|
||||
lk.unlock();
|
||||
|
||||
if (handleCount == 0 && mOnHandleZero) {
|
||||
mOnHandleZero(obj);
|
||||
}
|
||||
detail::deref(obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Handles::setInformation(HANDLE h, uint32_t mask, uint32_t value) {
|
||||
if (isPseudo(h)) {
|
||||
return true; // no-op, success
|
||||
}
|
||||
|
||||
std::unique_lock lk(m);
|
||||
const auto idx = indexOf(h);
|
||||
if (idx >= mSlots.size()) {
|
||||
return false;
|
||||
}
|
||||
auto &e = mSlots[idx];
|
||||
if (!e.obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr uint32_t kAllowedFlags = HANDLE_FLAG_INHERIT | HANDLE_FLAG_PROTECT_FROM_CLOSE;
|
||||
mask &= kAllowedFlags;
|
||||
|
||||
e.meta.flags = (e.meta.flags & ~mask) | (value & mask);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Handles::getInformation(HANDLE h, uint32_t *outFlags) const {
|
||||
if (!outFlags) {
|
||||
return false;
|
||||
}
|
||||
if (isPseudo(h)) {
|
||||
*outFlags = 0;
|
||||
return true;
|
||||
}
|
||||
std::shared_lock lk(m);
|
||||
const auto idx = indexOf(h);
|
||||
if (idx >= mSlots.size()) {
|
||||
return false;
|
||||
}
|
||||
const auto &e = mSlots[idx];
|
||||
if (!e.obj) {
|
||||
return false;
|
||||
}
|
||||
*outFlags = e.meta.flags;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Handles::duplicateTo(HANDLE src, Handles &dst, HANDLE &out, uint32_t desiredAccess, bool inherit,
|
||||
uint32_t options) {
|
||||
HandleMeta meta{};
|
||||
Pin<> obj = get(src, &meta);
|
||||
if (!obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool closeSource = (options & DUPLICATE_CLOSE_SOURCE) != 0;
|
||||
if (closeSource && (meta.flags & HANDLE_FLAG_PROTECT_FROM_CLOSE) != 0) {
|
||||
// Cannot close source if it is protected
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t effAccess = (options & DUPLICATE_SAME_ACCESS) ? meta.grantedAccess : (desiredAccess & meta.grantedAccess);
|
||||
const uint32_t flags = (inherit ? HANDLE_FLAG_INHERIT : 0);
|
||||
out = dst.alloc(std::move(obj), effAccess, flags);
|
||||
|
||||
if (closeSource) {
|
||||
release(src);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Namespace::insert(const std::u16string &name, ObjectBase *obj, bool permanent) {
|
||||
if (name.empty() || !obj) {
|
||||
return false;
|
||||
}
|
||||
std::unique_lock lk(m);
|
||||
// Namespace holds a weak ref
|
||||
const auto [_, inserted] = mTable.try_emplace(name, obj, permanent);
|
||||
return inserted;
|
||||
}
|
||||
|
||||
void Namespace::remove(ObjectBase *obj) {
|
||||
std::unique_lock lk(m);
|
||||
for (auto it = mTable.begin(); it != mTable.end(); ++it) {
|
||||
if (it->second.obj == obj && !it->second.permanent) {
|
||||
mTable.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Pin<> Namespace::get(const std::u16string &name) {
|
||||
if (name.empty()) {
|
||||
return {};
|
||||
}
|
||||
std::shared_lock lk(m);
|
||||
auto it = mTable.find(name);
|
||||
if (it == mTable.end()) {
|
||||
return {};
|
||||
}
|
||||
assert(it->second.obj);
|
||||
return Pin<>::acquire(it->second.obj);
|
||||
}
|
||||
|
||||
namespace wibo {
|
||||
|
||||
Namespace g_namespace;
|
||||
Handles &handles() {
|
||||
static Handles table([](ObjectBase *obj) { g_namespace.remove(obj); });
|
||||
return table;
|
||||
}
|
||||
|
||||
} // namespace wibo
|
||||
Reference in New Issue
Block a user