sys_cond/mutex: Fix race between sys_cond_create and sys_mutex, Fix IPC support in sys_cond/mutex

This commit is contained in:
Eladash 2020-06-04 06:37:25 +03:00 committed by Ivan
parent 8d8fb4a2e4
commit 92b7c56f29
6 changed files with 85 additions and 14 deletions

View File

@ -59,7 +59,7 @@ error_code sys_cond_destroy(ppu_thread& ppu, u32 cond_id)
return CELL_EBUSY; return CELL_EBUSY;
} }
cond.mutex->cond_count--; cond.mutex->obj_count.atomic_op([](typename lv2_mutex::count_info& info){ info.cond_count--; });
return {}; return {};
}); });

View File

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

View File

@ -88,7 +88,17 @@ error_code sys_mutex_destroy(ppu_thread& ppu, u32 mutex_id)
return CELL_EBUSY; return CELL_EBUSY;
} }
if (mutex.cond_count) if (!mutex.obj_count.fetch_op([](typename lv2_mutex::count_info& info)
{
if (info.cond_count)
{
return false;
}
// Decrement mutex copies count
info.mutex_count--;
return true;
}).second)
{ {
return CELL_EPERM; return CELL_EPERM;
} }

View File

@ -33,10 +33,16 @@ struct lv2_mutex final : lv2_obj
const u64 name; const u64 name;
const s32 flags; const s32 flags;
struct alignas(8) count_info
{
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}; // Owner Thread ID atomic_t<u32> owner{0};
atomic_t<u32> lock_count{0}; // Recursive Locks atomic_t<u32> lock_count{0}; // Recursive Locks
atomic_t<u32> cond_count{0}; // Condition Variables 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, s32 flags, u64 name) lv2_mutex(u32 protocol, u32 recursive, u32 shared, u32 adaptive, u64 key, s32 flags, u64 name)
@ -50,6 +56,12 @@ 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

@ -75,6 +75,12 @@ private:
enqueue_cmd, enqueue_cmd,
}; };
// Function executed under IDM mutex, error will make the object creation fail and the error will be returned
CellError on_id_create()
{
return {};
}
public: public:
static std::string name64(u64 name_u64) static std::string name64(u64 name_u64)
@ -205,23 +211,45 @@ public:
{ {
std::shared_ptr<T> result = make(); std::shared_ptr<T> result = make();
if (!ipc_manager<T, u64>::add(ipc_key, [&] { if (!idm::import_existing<lv2_obj, T>(result)) result.reset(); return result; }, &result)) 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) if (flags == SYS_SYNC_NEWLY_CREATED)
{ {
return CELL_EEXIST; return CELL_EEXIST;
} }
if (!idm::import_existing<lv2_obj, T>(result)) error = CELL_EAGAIN;
if (!idm::import<lv2_obj, T>([&]() { if (result && (error = result->on_id_create())) result.reset(); return std::move(result); }))
{ {
return CELL_EAGAIN; return error;
} }
return CELL_OK; return CELL_OK;
} }
else if (!result) else if (!result)
{ {
return CELL_EAGAIN; return error ? CELL_EAGAIN : error;
} }
else else
{ {
@ -237,9 +265,11 @@ public:
return CELL_ESRCH; return CELL_ESRCH;
} }
if (!idm::import_existing<lv2_obj, T>(result)) CellError error = CELL_EAGAIN;
if (!idm::import<lv2_obj, T>([&]() { if (result && (error = result->on_id_create())) result.reset(); return std::move(result); }))
{ {
return CELL_EAGAIN; return error;
} }
return CELL_OK; return CELL_OK;
@ -252,9 +282,13 @@ public:
} }
case SYS_SYNC_NOT_PROCESS_SHARED: case SYS_SYNC_NOT_PROCESS_SHARED:
{ {
if (!idm::import<lv2_obj, T>(std::forward<F>(make))) std::shared_ptr<T> result = make();
CellError error = CELL_EAGAIN;
if (!idm::import<lv2_obj, T>([&]() { if (result && (error = result->on_id_create())) result.reset(); return std::move(result); }))
{ {
return CELL_EAGAIN; return error;
} }
return CELL_OK; return CELL_OK;

View File

@ -292,7 +292,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.cond_count, mutex.sq.size()))); mutex.recursive == SYS_SYNC_RECURSIVE ? " Recursive," : "", mutex.owner >> 1, +mutex.lock_count, mutex.key, mutex.obj_count.load().cond_count, mutex.sq.size())));
break; break;
} }
case SYS_COND_OBJECT: case SYS_COND_OBJECT: