LV2: Improve IPC support (#10206)

* Remove custom event queue's IPC management of favour of universal LV2 approach.
* Move ipc_manager to FXO.
* Fix ipc_manager internal storage memory leak: deallocate entry when IPC object destroyed.
* Rewrite lv2_obj::create to be simpler (remove many duplicated code).
* Always execute lv2_obj::create under both IPC and IDM mutexes at once (not in non-atomic single-steps). Fixing potential case where concurrency can cause IDM to contain 2 or more different objects with the same IPC key with SYS_SYNC_NOT_CARE (instead of the same object).
* Do not rely on smart ptr reference count to tell if the object exists. Use similar approach as event queues as it makes error checkings accurate.
* Optimize lv2_event_port by using std::shared_ptr for queue which wasn't allowed before.
This commit is contained in:
Eladash 2021-05-07 09:58:30 +03:00 committed by GitHub
parent a043e95d24
commit 7b6482c01d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 146 additions and 240 deletions

View File

@ -9,8 +9,6 @@
LOG_CHANNEL(sys_cond); LOG_CHANNEL(sys_cond);
template<> DECLARE(ipc_manager<lv2_cond, u64>::g_ipc) {};
error_code sys_cond_create(ppu_thread& ppu, vm::ptr<u32> cond_id, u32 mutex_id, vm::ptr<sys_cond_attribute_t> attr) error_code sys_cond_create(ppu_thread& ppu, vm::ptr<u32> cond_id, u32 mutex_id, vm::ptr<sys_cond_attribute_t> attr)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
@ -58,7 +56,8 @@ error_code sys_cond_destroy(ppu_thread& ppu, u32 cond_id)
return CELL_EBUSY; return CELL_EBUSY;
} }
cond.mutex->obj_count.atomic_op([](lv2_mutex::count_info& info){ info.cond_count--; }); cond.mutex->cond_count--;
lv2_obj::on_id_destroy(cond, cond.shared, cond.key);
return {}; return {};
}); });

View File

@ -40,20 +40,17 @@ struct lv2_cond final : lv2_obj
{ {
} }
CellError on_id_create() const CellError on_id_create()
{ {
if (!mutex->obj_count.fetch_op([](lv2_mutex::count_info& info) if (mutex->exists)
{ {
if (info.mutex_count) mutex->cond_count++;
return info.cond_count++, true; exists++;
return false; return {};
}).second)
{
// Mutex has been destroyed, cannot create conditional variable
return CELL_ESRCH;
} }
return {}; // Mutex has been destroyed, cannot create conditional variable
return CELL_ESRCH;
} }
}; };

View File

@ -11,8 +11,6 @@
LOG_CHANNEL(sys_event); LOG_CHANNEL(sys_event);
template<> DECLARE(ipc_manager<lv2_event_queue, u64>::g_ipc) {};
std::shared_ptr<lv2_event_queue> lv2_event_queue::find(u64 ipc_key) std::shared_ptr<lv2_event_queue> lv2_event_queue::find(u64 ipc_key)
{ {
if (ipc_key == SYS_EVENT_QUEUE_LOCAL) if (ipc_key == SYS_EVENT_QUEUE_LOCAL)
@ -21,14 +19,7 @@ std::shared_ptr<lv2_event_queue> lv2_event_queue::find(u64 ipc_key)
return {}; return {};
} }
auto queue = ipc_manager<lv2_event_queue, u64>::get(ipc_key); return g_fxo->get<ipc_manager<lv2_event_queue, u64>>().get(ipc_key);
if (queue && !queue->exists)
{
queue.reset();
}
return queue;
} }
bool lv2_event_queue::check(const std::weak_ptr<lv2_event_queue>& wkptr) bool lv2_event_queue::check(const std::weak_ptr<lv2_event_queue>& wkptr)
@ -93,11 +84,11 @@ CellError lv2_event_queue::send(lv2_event event)
return {}; return {};
} }
error_code sys_event_queue_create(cpu_thread& cpu, vm::ptr<u32> equeue_id, vm::ptr<sys_event_queue_attribute_t> attr, u64 event_queue_key, s32 size) error_code sys_event_queue_create(cpu_thread& cpu, vm::ptr<u32> equeue_id, vm::ptr<sys_event_queue_attribute_t> attr, u64 ipc_key, s32 size)
{ {
cpu.state += cpu_flag::wait; cpu.state += cpu_flag::wait;
sys_event.warning("sys_event_queue_create(equeue_id=*0x%x, attr=*0x%x, event_queue_key=0x%llx, size=%d)", equeue_id, attr, event_queue_key, size); sys_event.warning("sys_event_queue_create(equeue_id=*0x%x, attr=*0x%x, ipc_key=0x%llx, size=%d)", equeue_id, attr, ipc_key, size);
if (size <= 0 || size > 127) if (size <= 0 || size > 127)
{ {
@ -120,42 +111,19 @@ error_code sys_event_queue_create(cpu_thread& cpu, vm::ptr<u32> equeue_id, vm::p
return CELL_EINVAL; return CELL_EINVAL;
} }
auto queue = std::make_shared<lv2_event_queue>(protocol, type, attr->name_u64, event_queue_key, size); const u32 pshared = ipc_key == SYS_EVENT_QUEUE_LOCAL ? SYS_SYNC_NOT_PROCESS_SHARED : SYS_SYNC_NOT_PROCESS_SHARED;
constexpr u32 flags = SYS_SYNC_NEWLY_CREATED; // NOTE: This is inaccurate for multi-process
const u64 name = attr->name_u64;
CellError error = CELL_EAGAIN; if (const auto error = lv2_obj::create<lv2_event_queue>(pshared, ipc_key, flags, [&]()
if (event_queue_key == SYS_EVENT_QUEUE_LOCAL)
{ {
// Not an IPC queue return std::make_shared<lv2_event_queue>(protocol, type, name, ipc_key, size);
if (const u32 _id = idm::import<lv2_obj, lv2_event_queue>([&]() { if ((error = queue->on_id_create())) queue.reset(); return std::move(queue); } ))
{
*equeue_id = _id;
return CELL_OK;
}
return error;
}
// Create IPC queue
if (!ipc_manager<lv2_event_queue, u64>::add(event_queue_key, [&]() -> std::shared_ptr<lv2_event_queue>
{
if (const u32 _id = idm::import<lv2_obj, lv2_event_queue>([&]() { if ((error = queue->on_id_create())) return decltype(queue){}; return queue; } ))
{
*equeue_id = _id;
return std::move(queue);
}
return nullptr;
})) }))
{
return CELL_EEXIST;
}
if (queue)
{ {
return error; return error;
} }
*equeue_id = idm::last_id();
return CELL_OK; return CELL_OK;
} }
@ -179,7 +147,7 @@ error_code sys_event_queue_destroy(ppu_thread& ppu, u32 equeue_id, s32 mode)
return CELL_EBUSY; return CELL_EBUSY;
} }
queue.exists--; lv2_obj::on_id_destroy(queue, queue.key == SYS_EVENT_QUEUE_LOCAL ? SYS_SYNC_NOT_PROCESS_SHARED : SYS_SYNC_PROCESS_SHARED, queue.key);
return {}; return {};
}); });
@ -521,11 +489,11 @@ error_code sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3)
const auto port = idm::get<lv2_obj, lv2_event_port>(eport_id, [&](lv2_event_port& port) -> CellError const auto port = idm::get<lv2_obj, lv2_event_port>(eport_id, [&](lv2_event_port& port) -> CellError
{ {
if (const auto queue = port.queue.lock(); lv2_event_queue::check(queue)) if (lv2_event_queue::check(port.queue))
{ {
const u64 source = port.name ? port.name : (s64{process_getpid()} << 32) | u64{eport_id}; const u64 source = port.name ? port.name : (s64{process_getpid()} << 32) | u64{eport_id};
return queue->send(source, data1, data2, data3); return port.queue->send(source, data1, data2, data3);
} }
return CELL_ENOTCONN; return CELL_ENOTCONN;

View File

@ -86,7 +86,6 @@ struct lv2_event_queue final : public lv2_obj
const u64 key; const u64 key;
const s32 size; const s32 size;
atomic_t<u32> exists = 0; // Existence validation (workaround for shared-ptr ref-counting)
shared_mutex mutex; shared_mutex mutex;
std::deque<lv2_event> events; std::deque<lv2_event> events;
std::deque<cpu_thread*> sq; std::deque<cpu_thread*> sq;
@ -113,12 +112,6 @@ struct lv2_event_queue final : public lv2_obj
// Check queue ptr validity (use 'exists' member) // Check queue ptr validity (use 'exists' member)
static bool check(const std::weak_ptr<lv2_event_queue>&); static bool check(const std::weak_ptr<lv2_event_queue>&);
static bool check(const std::shared_ptr<lv2_event_queue>&); static bool check(const std::shared_ptr<lv2_event_queue>&);
CellError on_id_create()
{
exists++;
return {};
}
}; };
struct lv2_event_port final : lv2_obj struct lv2_event_port final : lv2_obj
@ -129,7 +122,7 @@ struct lv2_event_port final : lv2_obj
const u64 name; // Event source (generated from id and process id if not set) const u64 name; // Event source (generated from id and process id if not set)
u32 queue_id = 0; // Event queue ID (if IPC is used this value is meaningless) u32 queue_id = 0; // Event queue ID (if IPC is used this value is meaningless)
std::weak_ptr<lv2_event_queue> queue; // Event queue this port is connected to std::shared_ptr<lv2_event_queue> queue; // Event queue this port is connected to
lv2_event_port(s32 type, u64 name) lv2_event_port(s32 type, u64 name)
: type(type) : type(type)

View File

@ -11,8 +11,6 @@
LOG_CHANNEL(sys_event_flag); LOG_CHANNEL(sys_event_flag);
template<> DECLARE(ipc_manager<lv2_event_flag, u64>::g_ipc) {};
error_code sys_event_flag_create(ppu_thread& ppu, vm::ptr<u32> id, vm::ptr<sys_event_flag_attribute_t> attr, u64 init) error_code sys_event_flag_create(ppu_thread& ppu, vm::ptr<u32> id, vm::ptr<sys_event_flag_attribute_t> attr, u64 init)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
@ -73,6 +71,7 @@ error_code sys_event_flag_destroy(ppu_thread& ppu, u32 id)
return CELL_EBUSY; return CELL_EBUSY;
} }
lv2_obj::on_id_destroy(flag, flag.shared, flag.key);
return {}; return {};
}); });

View File

@ -12,10 +12,12 @@
LOG_CHANNEL(sys_mmapper); LOG_CHANNEL(sys_mmapper);
lv2_memory::lv2_memory(u32 size, u32 align, u64 flags, lv2_memory_container* ct) lv2_memory::lv2_memory(u32 size, u32 align, u64 flags, u64 key, u32 pshared, lv2_memory_container* ct)
: size(size) : size(size)
, align(align) , align(align)
, flags(flags) , flags(flags)
, key(key)
, pshared(pshared)
, ct(ct) , ct(ct)
, shm(std::make_shared<utils::shm>(size, 1 /* shareable flag */)) , shm(std::make_shared<utils::shm>(size, 1 /* shareable flag */))
{ {
@ -25,17 +27,18 @@ lv2_memory::lv2_memory(u32 size, u32 align, u64 flags, lv2_memory_container* ct)
#endif #endif
} }
template<> DECLARE(ipc_manager<lv2_memory, u64>::g_ipc) {};
template <bool exclusive = false> template <bool exclusive = false>
error_code create_lv2_shm(bool pshared, u64 ipc_key, u64 size, u32 align, u64 flags, lv2_memory_container* ct) error_code create_lv2_shm(bool pshared, u64 ipc_key, u64 size, u32 align, u64 flags, lv2_memory_container* ct)
{ {
if (auto error = lv2_obj::create<lv2_memory>(pshared ? SYS_SYNC_PROCESS_SHARED : SYS_SYNC_NOT_PROCESS_SHARED, ipc_key, exclusive ? SYS_SYNC_NEWLY_CREATED : SYS_SYNC_NOT_CARE, [&]() const u32 _pshared = pshared ? SYS_SYNC_PROCESS_SHARED : SYS_SYNC_NOT_PROCESS_SHARED;
if (auto error = lv2_obj::create<lv2_memory>(_pshared, ipc_key, exclusive ? SYS_SYNC_NEWLY_CREATED : SYS_SYNC_NOT_CARE, [&]()
{ {
return std::make_shared<lv2_memory>( return std::make_shared<lv2_memory>(
static_cast<u32>(size), static_cast<u32>(size),
align, align,
flags, flags,
ipc_key,
_pshared,
ct); ct);
}, false)) }, false))
{ {
@ -525,6 +528,7 @@ error_code sys_mmapper_free_shared_memory(ppu_thread& ppu, u32 mem_id)
return CELL_EBUSY; return CELL_EBUSY;
} }
lv2_obj::on_id_destroy(mem, mem.pshared, mem.key);
return {}; return {};
}); });

View File

@ -21,12 +21,14 @@ struct lv2_memory : lv2_obj
const u32 size; // Memory size const u32 size; // Memory size
const u32 align; // Alignment required const u32 align; // Alignment required
const u64 flags; const u64 flags;
const u64 key; // IPC key
const u32 pshared;
lv2_memory_container* const ct; // Associated memory container lv2_memory_container* const ct; // Associated memory container
const std::shared_ptr<utils::shm> shm; const std::shared_ptr<utils::shm> shm;
atomic_t<u32> counter{0}; atomic_t<u32> counter{0};
lv2_memory(u32 size, u32 align, u64 flags, lv2_memory_container* ct); lv2_memory(u32 size, u32 align, u64 flags, u64 key, u32 pshared, lv2_memory_container* ct);
}; };
enum : u64 enum : u64

View File

@ -9,8 +9,6 @@
LOG_CHANNEL(sys_mutex); LOG_CHANNEL(sys_mutex);
template<> DECLARE(ipc_manager<lv2_mutex, u64>::g_ipc) {};
error_code sys_mutex_create(ppu_thread& ppu, vm::ptr<u32> mutex_id, vm::ptr<sys_mutex_attribute_t> attr) error_code sys_mutex_create(ppu_thread& ppu, vm::ptr<u32> mutex_id, vm::ptr<sys_mutex_attribute_t> attr)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
@ -87,21 +85,12 @@ error_code sys_mutex_destroy(ppu_thread& ppu, u32 mutex_id)
return CELL_EBUSY; return CELL_EBUSY;
} }
if (!mutex.obj_count.fetch_op([](lv2_mutex::count_info& info) if (mutex.cond_count)
{
if (info.cond_count)
{
return false;
}
// Decrement mutex copies count
info.mutex_count--;
return true;
}).second)
{ {
return CELL_EPERM; return CELL_EPERM;
} }
lv2_obj::on_id_destroy(mutex, mutex.shared, mutex.key);
return {}; return {};
}); });

View File

@ -32,16 +32,10 @@ struct lv2_mutex final : lv2_obj
const u64 key; const u64 key;
const u64 name; const u64 name;
struct alignas(8) count_info u32 cond_count = 0; // Condition Variables
{
u32 mutex_count; // Mutex copies count (0 means doesn't exist anymore)
u32 cond_count; // Condition Variables
};
shared_mutex mutex; shared_mutex mutex;
atomic_t<u32> owner{0}; atomic_t<u32> owner{0};
atomic_t<u32> lock_count{0}; // Recursive Locks atomic_t<u32> lock_count{0}; // Recursive Locks
atomic_t<count_info> obj_count{};
std::deque<cpu_thread*> sq; std::deque<cpu_thread*> sq;
lv2_mutex(u32 protocol, u32 recursive, u32 shared, u32 adaptive, u64 key, u64 name) lv2_mutex(u32 protocol, u32 recursive, u32 shared, u32 adaptive, u64 key, u64 name)
@ -54,12 +48,6 @@ struct lv2_mutex final : lv2_obj
{ {
} }
CellError on_id_create()
{
obj_count.atomic_op([](count_info& info){ info.mutex_count++; });
return {};
}
CellError try_lock(u32 id) CellError try_lock(u32 id)
{ {
const u32 value = owner; const u32 value = owner;

View File

@ -9,8 +9,6 @@
LOG_CHANNEL(sys_rwlock); LOG_CHANNEL(sys_rwlock);
template<> DECLARE(ipc_manager<lv2_rwlock, u64>::g_ipc) {};
error_code sys_rwlock_create(ppu_thread& ppu, vm::ptr<u32> rw_lock_id, vm::ptr<sys_rwlock_attribute_t> attr) error_code sys_rwlock_create(ppu_thread& ppu, vm::ptr<u32> rw_lock_id, vm::ptr<sys_rwlock_attribute_t> attr)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
@ -57,6 +55,7 @@ error_code sys_rwlock_destroy(ppu_thread& ppu, u32 rw_lock_id)
return CELL_EBUSY; return CELL_EBUSY;
} }
lv2_obj::on_id_destroy(rw, rw.shared, rw.key);
return {}; return {};
}); });

View File

@ -9,8 +9,6 @@
LOG_CHANNEL(sys_semaphore); LOG_CHANNEL(sys_semaphore);
template<> DECLARE(ipc_manager<lv2_sema, u64>::g_ipc) {};
error_code sys_semaphore_create(ppu_thread& ppu, vm::ptr<u32> sem_id, vm::ptr<sys_semaphore_attribute_t> attr, s32 initial_val, s32 max_val) error_code sys_semaphore_create(ppu_thread& ppu, vm::ptr<u32> sem_id, vm::ptr<sys_semaphore_attribute_t> attr, s32 initial_val, s32 max_val)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
@ -68,6 +66,7 @@ error_code sys_semaphore_destroy(ppu_thread& ppu, u32 sem_id)
return CELL_EBUSY; return CELL_EBUSY;
} }
lv2_obj::on_id_destroy(sema, sema.shared, sema.key);
return {}; return {};
}); });

View File

@ -77,13 +77,17 @@ private:
}; };
// Function executed under IDM mutex, error will make the object creation fail and the error will be returned // Function executed under IDM mutex, error will make the object creation fail and the error will be returned
static CellError on_id_create() CellError on_id_create()
{ {
exists++;
return {}; return {};
} }
public: public:
// Existence validation (workaround for shared-ptr ref-counting)
atomic_t<u32> exists = 0;
static std::string name64(u64 name_u64) static std::string name64(u64 name_u64)
{ {
const auto ptr = reinterpret_cast<const char*>(&name_u64); const auto ptr = reinterpret_cast<const char*>(&name_u64);
@ -198,95 +202,95 @@ public:
{ {
case SYS_SYNC_NEWLY_CREATED: case SYS_SYNC_NEWLY_CREATED:
case SYS_SYNC_NOT_CARE: case SYS_SYNC_NOT_CARE:
{
std::shared_ptr<T> result = make();
CellError error{};
if (!ipc_manager<T, u64>::add(ipc_key, [&]()
{
if (!idm::import<lv2_obj, T>([&]()
{
if (result && (error = result->on_id_create()))
result.reset();
return result;
}))
{
result.reset();
}
return result;
}, &result))
{
if (error)
{
return error;
}
if (flags == SYS_SYNC_NEWLY_CREATED)
{
return CELL_EEXIST;
}
error = CELL_EAGAIN;
if (!idm::import<lv2_obj, T>([&]() { if (result && (error = result->on_id_create())) result.reset(); return std::move(result); }))
{
return error;
}
return CELL_OK;
}
else if (!result)
{
return error ? CELL_EAGAIN : error;
}
else
{
return CELL_OK;
}
}
case SYS_SYNC_NOT_CREATE: case SYS_SYNC_NOT_CREATE:
{ {
auto result = ipc_manager<T, u64>::get(ipc_key); break;
if (!result)
{
return CELL_ESRCH;
}
CellError error = CELL_EAGAIN;
if (!idm::import<lv2_obj, T>([&]() { if (result && (error = result->on_id_create())) result.reset(); return std::move(result); }))
{
return error;
}
return CELL_OK;
}
default:
{
return CELL_EINVAL;
} }
default: return CELL_EINVAL;
} }
break;
} }
case SYS_SYNC_NOT_PROCESS_SHARED: case SYS_SYNC_NOT_PROCESS_SHARED:
{ {
std::shared_ptr<T> result = make(); break;
}
default: return CELL_EINVAL;
}
CellError error = CELL_EAGAIN; std::shared_ptr<T> result = make();
if (!idm::import<lv2_obj, T>([&]() { if (result && (error = result->on_id_create())) result.reset(); return std::move(result); })) // EAGAIN for IDM IDs shortage
CellError error = CELL_EAGAIN;
if (!idm::import<lv2_obj, T>([&]() -> std::shared_ptr<T>
{
auto finalize_construct = [&]() -> std::shared_ptr<T>
{ {
return error; if ((error = result->on_id_create()))
{
result.reset();
}
return std::move(result);
};
if (flags != SYS_SYNC_PROCESS_SHARED)
{
// Creation of unique (non-shared) object handle
return finalize_construct();
} }
return CELL_OK; auto& ipc_container = g_fxo->get<ipc_manager<T, u64>>();
}
default: if (flags == SYS_SYNC_NOT_CREATE)
{
result = ipc_container.get(ipc_key);
if (!result)
{
error = CELL_ESRCH;
return result;
}
// Run on_id_create() on existing object
return finalize_construct();
}
bool added = false;
std::tie(added, result) = ipc_container.add(ipc_key, finalize_construct, flags != SYS_SYNC_NEWLY_CREATED);
if (!added)
{
if (flags == SYS_SYNC_NEWLY_CREATED)
{
// Object already exists but flags does not allow it
error = CELL_EEXIST;
// We specified we do not want to peek pointer's value, result must be empty
AUDIT(!result);
return result;
}
// Run on_id_create() on existing object
return finalize_construct();
}
return std::move(result);
}))
{ {
return CELL_EINVAL; return error;
} }
return CELL_OK;
}
template <typename T>
static void on_id_destroy(T& obj, u32 pshared, u64 ipc_key)
{
if (obj.exists-- == 1u && pshared == SYS_SYNC_PROCESS_SHARED)
{
g_fxo->get<ipc_manager<T, u64>>().remove(ipc_key);
} }
} }

View File

@ -6,99 +6,65 @@
#include "Utilities/mutex.h" #include "Utilities/mutex.h"
// IPC manager for objects of type T and IPC keys of type K. // IPC manager for objects of type T and IPC keys of type K.
// External declaration of g_ipc is required.
template <typename T, typename K> template <typename T, typename K>
class ipc_manager final class ipc_manager final
{ {
std::unordered_map<K, std::weak_ptr<T>> m_map; std::unordered_map<K, std::shared_ptr<T>> m_map;
shared_mutex m_mutex; mutable shared_mutex m_mutex;
static ipc_manager g_ipc;
public: public:
// Add new object if specified ipc_key is not used // Add new object if specified ipc_key is not used
// .first: added new object?, .second: what's at m_map[key] after this function if (peek_ptr || added new object) is true
template <typename F> template <typename F>
static bool add(const K& ipc_key, F&& provider, std::shared_ptr<T>* out = nullptr) std::pair<bool, std::shared_ptr<T>> add(const K& ipc_key, F&& provider, bool peek_ptr = true)
{ {
std::lock_guard lock(g_ipc.m_mutex); std::lock_guard lock(m_mutex);
// Get object location // Get object location
std::weak_ptr<T>& wptr = g_ipc.m_map[ipc_key]; std::shared_ptr<T>& ptr = m_map[ipc_key];
const bool existed = ptr.operator bool();
std::shared_ptr<T> old; if (!existed)
if ((out && !(old = wptr.lock())) || wptr.expired())
{ {
// Call a function which must return the object // Call a function which must return the object
if (out) ptr = provider();
{
*out = provider();
wptr = *out;
}
else
{
wptr = provider();
}
return true;
} }
if (out) const bool added = !existed && ptr;
{ return {added, (peek_ptr || added) ? ptr : nullptr};
*out = std::move(old);
}
return false;
} }
// Unregister specified ipc_key, may return true even if the object doesn't exist anymore // Unregister specified ipc_key, may return true even if the object doesn't exist anymore
static bool remove(const K& ipc_key) bool remove(const K& ipc_key)
{ {
std::lock_guard lock(g_ipc.m_mutex); std::lock_guard lock(m_mutex);
return g_ipc.m_map.erase(ipc_key) != 0; return m_map.erase(ipc_key) != 0;
}
// Unregister specified ipc_key, return the object
static std::shared_ptr<T> withdraw(const K& ipc_key)
{
std::lock_guard lock(g_ipc.m_mutex);
const auto found = g_ipc.m_map.find(ipc_key);
if (found != g_ipc.m_map.end())
{
auto ptr = found->second.lock();
g_ipc.m_map.erase(found);
return ptr;
}
return nullptr;
} }
// Get object with specified ipc_key // Get object with specified ipc_key
static std::shared_ptr<T> get(const K& ipc_key) std::shared_ptr<T> get(const K& ipc_key) const
{ {
reader_lock lock(g_ipc.m_mutex); reader_lock lock(m_mutex);
const auto found = g_ipc.m_map.find(ipc_key); const auto found = m_map.find(ipc_key);
if (found != g_ipc.m_map.end()) if (found != m_map.end())
{ {
return found->second.lock(); return found->second;
} }
return nullptr; return nullptr;
} }
// Check whether the object actually exists // Check whether the object actually exists
static bool check(const K& ipc_key) bool check(const K& ipc_key) const
{ {
reader_lock lock(g_ipc.m_mutex); reader_lock lock(m_mutex);
const auto found = g_ipc.m_map.find(ipc_key); const auto found = m_map.find(ipc_key);
return found != g_ipc.m_map.end() && !found->second.expired(); return found != m_map.end();
} }
}; };

View File

@ -321,7 +321,7 @@ void kernel_explorer::Update()
{ {
auto& mutex = static_cast<lv2_mutex&>(obj); auto& mutex = static_cast<lv2_mutex&>(obj);
add_leaf(node, qstr(fmt::format(u8"Mutex 0x%08x: “%s”, %s,%s Owner: %#x, Locks: %u, Key: %#llx, Conds: %u, Wq: %zu", id, lv2_obj::name64(mutex.name), mutex.protocol, add_leaf(node, qstr(fmt::format(u8"Mutex 0x%08x: “%s”, %s,%s Owner: %#x, Locks: %u, Key: %#llx, Conds: %u, Wq: %zu", id, lv2_obj::name64(mutex.name), mutex.protocol,
mutex.recursive == SYS_SYNC_RECURSIVE ? " Recursive," : "", mutex.owner >> 1, +mutex.lock_count, mutex.key, mutex.obj_count.load().cond_count, mutex.sq.size()))); mutex.recursive == SYS_SYNC_RECURSIVE ? " Recursive," : "", mutex.owner >> 1, +mutex.lock_count, mutex.key, mutex.cond_count, mutex.sq.size())));
break; break;
} }
case SYS_COND_OBJECT: case SYS_COND_OBJECT:
@ -360,19 +360,18 @@ void kernel_explorer::Update()
case SYS_EVENT_PORT_OBJECT: case SYS_EVENT_PORT_OBJECT:
{ {
auto& ep = static_cast<lv2_event_port&>(obj); auto& ep = static_cast<lv2_event_port&>(obj);
const auto queue = ep.queue.lock();
const auto type = ep.type == SYS_EVENT_PORT_LOCAL ? "LOCAL"sv : "IPC"sv; const auto type = ep.type == SYS_EVENT_PORT_LOCAL ? "LOCAL"sv : "IPC"sv;
if (lv2_event_queue::check(queue)) if (const auto queue = ep.queue.get(); queue && queue->exists)
{ {
if (queue.get() == idm::check_unlocked<lv2_obj, lv2_event_queue>(ep.queue_id)) if (queue == idm::check_unlocked<lv2_obj, lv2_event_queue>(ep.queue_id))
{ {
// Type must be LOCAL here, but refer to the note below for why it is showed // Type must be LOCAL here, but refer to the note below for why it is showed
add_leaf(node, qstr(fmt::format("Event Port 0x%08x: %s, Name: %#llx, Event Queue (ID): 0x%08x", id, type, ep.name, ep.queue_id))); add_leaf(node, qstr(fmt::format("Event Port 0x%08x: %s, Name: %#llx, Event Queue (ID): 0x%08x", id, type, ep.name, ep.queue_id)));
break; break;
} }
if (queue == lv2_event_queue::find(queue->key)) if (queue == lv2_event_queue::find(queue->key).get())
{ {
// There are cases in which the attached queue by ID also has an IPC // There are cases in which the attached queue by ID also has an IPC
// And the ID was destroyed but another was created for that same IPC // And the ID was destroyed but another was created for that same IPC