Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix sys_raw_spu_destroy #7782

Merged
merged 3 commits into from Mar 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 9 additions & 4 deletions rpcs3/Emu/Cell/Modules/cellVdec.cpp
Expand Up @@ -116,7 +116,7 @@ struct vdec_context final
u32 frc_set{}; // Frame Rate Override
u64 next_pts{};
u64 next_dts{};
u32 ppu_tid{};
atomic_t<u32> ppu_tid{};

std::deque<vdec_frame> out;
atomic_t<u32> out_max = 60;
Expand Down Expand Up @@ -202,7 +202,7 @@ struct vdec_context final

void exec(ppu_thread& ppu, u32 vid)
{
ppu_tid = ppu.id;
ppu_tid.release(ppu.id);

// pcmd can be nullptr
for (auto* pcmd : in_cmd)
Expand Down Expand Up @@ -687,12 +687,17 @@ error_code cellVdecClose(ppu_thread& ppu, u32 handle)
vdec->out_max = 0;
vdec->in_cmd.push(vdec_close);

while (!atomic_storage<u32>::load(vdec->ppu_tid))
while (!vdec->ppu_tid)
{
thread_ctrl::wait_for(1000);
}

ppu_execute<&sys_interrupt_thread_disestablish>(ppu, vdec->ppu_tid);
const u32 tid = vdec->ppu_tid.exchange(-1);

if (tid != umax)
{
ppu_execute<&sys_interrupt_thread_disestablish>(ppu, tid);
}

if (!idm::remove_verify<vdec_context>(handle, std::move(vdec)))
{
Expand Down
5 changes: 3 additions & 2 deletions rpcs3/Emu/Cell/SPUThread.cpp
Expand Up @@ -955,14 +955,15 @@ void spu_int_ctrl_t::set(u64 ints)
ints &= mask;

// notify if at least 1 bit was set
if (ints && ~stat.fetch_or(ints) & ints && !tag.expired())
if (ints && ~stat.fetch_or(ints) & ints)
{
reader_lock rlock(id_manager::g_mutex);
std::shared_lock rlock(id_manager::g_mutex);

if (const auto tag_ptr = tag.lock())
{
if (auto handler = tag_ptr->handler.lock())
{
rlock.unlock();
handler->exec();
}
}
Expand Down
2 changes: 2 additions & 0 deletions rpcs3/Emu/Cell/lv2/sys_interrupt.cpp
Expand Up @@ -150,6 +150,8 @@ error_code _sys_interrupt_thread_disestablish(ppu_thread& ppu, u32 ih, vm::ptr<u
return CELL_ESRCH;
}

lv2_obj::sleep(ppu);

// Wait for sys_interrupt_thread_eoi() and destroy interrupt thread
handler->join();

Expand Down
15 changes: 9 additions & 6 deletions rpcs3/Emu/Cell/lv2/sys_spu.cpp
Expand Up @@ -1690,7 +1690,12 @@ error_code sys_raw_spu_destroy(ppu_thread& ppu, u32 id)

sys_spu.warning("sys_raw_spu_destroy(id=%d)", id);

const auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu(id));
auto thread = idm::get<named_thread<spu_thread>>(spu_thread::find_raw_spu(id), [](named_thread<spu_thread>& thread)
{
// Stop thread
thread.state += cpu_flag::exit;
thread = thread_state::aborting;
});

if (!thread) [[unlikely]]
{
Expand All @@ -1699,9 +1704,6 @@ error_code sys_raw_spu_destroy(ppu_thread& ppu, u32 id)

// TODO: CELL_EBUSY is not returned

// Stop thread
thread->state += cpu_flag::stop;

// Kernel objects which must be removed
std::vector<std::pair<std::shared_ptr<lv2_obj>, u32>> to_remove;

Expand All @@ -1713,6 +1715,7 @@ error_code sys_raw_spu_destroy(ppu_thread& ppu, u32 id)
if (auto handler = tag->handler.lock())
{
// SLEEP
lv2_obj::sleep(ppu);
handler->join();
to_remove.emplace_back(std::move(handler), 0);
}
Expand Down Expand Up @@ -1742,7 +1745,7 @@ error_code sys_raw_spu_destroy(ppu_thread& ppu, u32 id)
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)))
if (!idm::remove_verify<named_thread<spu_thread>>(id, std::move(thread)))
{
// Other thread destroyed beforehead
return CELL_ESRCH;
Expand Down Expand Up @@ -1770,7 +1773,7 @@ error_code sys_raw_spu_create_interrupt_tag(ppu_thread& ppu, u32 id, u32 class_i

auto thread = idm::check_unlocked<named_thread<spu_thread>>(spu_thread::find_raw_spu(id));

if (!thread)
if (!thread || *thread == thread_state::aborting)
{
error = CELL_ESRCH;
return result;
Expand Down