idm: Fix minor race in cellVdecClose, sys_raw_spu_destroy...

Because of racing removal of IDs vs the shared pointer owned object
This commit is contained in:
Eladash 2020-03-14 13:27:18 +02:00
parent efe6e1eb0a
commit c16124f0d9
6 changed files with 33 additions and 20 deletions

View file

@ -833,7 +833,12 @@ error_code cellAdecClose(u32 handle)
thread_ctrl::wait_for(1000); // hack thread_ctrl::wait_for(1000); // hack
} }
idm::remove<ppu_thread>(handle); if (!idm::remove_verify<ppu_thread>(handle, std::move(adec)))
{
// Removed by other thread beforehead
return CELL_ADEC_ERROR_ARG;
}
return CELL_OK; return CELL_OK;
} }

View file

@ -693,7 +693,13 @@ error_code cellVdecClose(ppu_thread& ppu, u32 handle)
} }
ppu_execute<&sys_interrupt_thread_disestablish>(ppu, vdec->ppu_tid); ppu_execute<&sys_interrupt_thread_disestablish>(ppu, vdec->ppu_tid);
idm::remove<vdec_context>(handle);
if (!idm::remove_verify<vdec_context>(handle, std::move(vdec)))
{
// Other thread removed it beforehead
return CELL_VDEC_ERROR_ARG;
}
return CELL_OK; return CELL_OK;
} }

View file

@ -117,15 +117,11 @@ error_code sceNpSnsFbDestroyHandle(u32 handle)
return SCE_NP_SNS_ERROR_INVALID_ARGUMENT; return SCE_NP_SNS_ERROR_INVALID_ARGUMENT;
} }
const auto sfh = idm::get<sns_fb_handle_t>(handle); if (!idm::remove<sns_fb_handle_t>(handle))
if (!sfh)
{ {
return SCE_NP_SNS_FB_ERROR_UNKNOWN_HANDLE; return SCE_NP_SNS_FB_ERROR_UNKNOWN_HANDLE;
} }
idm::remove<sns_fb_handle_t>(handle);
return CELL_OK; return CELL_OK;
} }

View file

@ -120,7 +120,7 @@ void sys_mempool_destroy(ppu_thread& ppu, sys_mempool_t mempool)
u32 mutexid = memory_pool->mutexid; u32 mutexid = memory_pool->mutexid;
sys_mutex_lock(ppu, memory_pool->mutexid, 0); sys_mutex_lock(ppu, memory_pool->mutexid, 0);
idm::remove<memory_pool_t>(mempool); idm::remove_verify<memory_pool_t>(mempool, std::move(memory_pool));
sys_mutex_unlock(ppu, mutexid); sys_mutex_unlock(ppu, mutexid);
sys_mutex_destroy(ppu, mutexid); sys_mutex_destroy(ppu, mutexid);
sys_cond_destroy(ppu, condid); sys_cond_destroy(ppu, condid);

View file

@ -39,7 +39,7 @@ void lv2_int_serv::join()
thread_ctrl::notify(*thread); thread_ctrl::notify(*thread);
(*thread)(); (*thread)();
idm::remove<named_thread<ppu_thread>>(thread->id); idm::remove_verify<named_thread<ppu_thread>>(thread->id, thread);
} }
error_code sys_interrupt_tag_destroy(ppu_thread& ppu, u32 intrtag) error_code sys_interrupt_tag_destroy(ppu_thread& ppu, u32 intrtag)

View file

@ -1703,32 +1703,33 @@ error_code sys_raw_spu_destroy(ppu_thread& ppu, u32 id)
thread->state += cpu_flag::stop; thread->state += cpu_flag::stop;
// Kernel objects which must be removed // Kernel objects which must be removed
std::unordered_map<lv2_obj*, u32, pointer_hash<lv2_obj, alignof(void*)>> to_remove; std::vector<std::pair<std::shared_ptr<lv2_obj>, u32>> to_remove;
// Clear interrupt handlers // Clear interrupt handlers
for (auto& intr : thread->int_ctrl) for (auto& intr : thread->int_ctrl)
{ {
if (const auto tag = intr.tag.lock()) if (auto tag = intr.tag.lock())
{ {
if (auto handler = tag->handler.lock()) if (auto handler = tag->handler.lock())
{ {
// SLEEP // SLEEP
handler->join(); handler->join();
to_remove.emplace(handler.get(), 0); to_remove.emplace_back(std::move(handler), 0);
} }
to_remove.emplace(tag.get(), 0); to_remove.emplace_back(std::move(tag), 0);
} }
} }
// Scan all kernel objects to determine IDs // Scan all kernel objects to determine IDs
idm::select<lv2_obj>([&](u32 id, lv2_obj& obj) idm::select<lv2_obj>([&](u32 id, lv2_obj& obj)
{ {
const auto found = to_remove.find(&obj); for (auto& pair : to_remove)
if (found != to_remove.end())
{ {
found->second = id; if (pair.first.get() == std::addressof(obj))
{
pair.second = id;
}
} }
}); });
@ -1736,12 +1737,17 @@ error_code sys_raw_spu_destroy(ppu_thread& ppu, u32 id)
for (auto&& pair : to_remove) for (auto&& pair : to_remove)
{ {
if (pair.second >> 24 == 0xa) if (pair.second >> 24 == 0xa)
idm::remove<lv2_obj, lv2_int_tag>(pair.second); idm::remove_verify<lv2_obj, lv2_int_tag>(pair.second, std::move(pair.first));
if (pair.second >> 24 == 0xb) if (pair.second >> 24 == 0xb)
idm::remove<lv2_obj, lv2_int_serv>(pair.second); idm::remove_verify<lv2_obj, lv2_int_serv>(pair.second, std::move(pair.first));
}
if (!idm::remove_verify<named_thread<spu_thread>>(thread->id, std::move(thread)))
{
// Other thread destroyed beforehead
return CELL_ESRCH;
} }
idm::remove<named_thread<spu_thread>>(thread->id);
return CELL_OK; return CELL_OK;
} }