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

Remove SPU and PPU destructors #9630

Merged
merged 2 commits into from Jan 21, 2021
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
17 changes: 17 additions & 0 deletions Utilities/Thread.h
Expand Up @@ -234,6 +234,23 @@ class thread_ctrl final
_wait_for(-1, true);
}

// Wait for both thread sync var and provided atomic var
template <typename T, atomic_wait::op op = atomic_wait::op::eq, typename U>
static inline void wait_on(T& wait, U old, u64 usec = -1)
{
auto _this = g_tls_this_thread;

if (_this->m_sync.bit_test_reset(2))
{
return;
}

atomic_wait::list<2> list{};
list.set<0, op>(wait, old);
list.set<1>(_this->m_sync, 0, 4 + 1);
list.wait(atomic_wait_timeout{usec <= 0xffff'ffff'ffff'ffff / 1000 ? usec * 1000 : 0xffff'ffff'ffff'ffff});
}

// Exit.
[[noreturn]] static void emergency_exit(std::string_view reason);

Expand Down
9 changes: 0 additions & 9 deletions rpcs3/Emu/Cell/PPUThread.cpp
Expand Up @@ -914,15 +914,6 @@ void ppu_thread::exec_task()

ppu_thread::~ppu_thread()
{
// Deallocate Stack Area
ensure(vm::dealloc(stack_addr, vm::stack));

if (const auto dct = g_fxo->get<lv2_memory_container>())
{
dct->used -= stack_size;
}

perf_log.notice("Perf stats for STCX reload: successs %u, failure %u", last_succ, last_fail);
}

ppu_thread::ppu_thread(const ppu_thread_params& param, std::string_view name, u32 prio, int detached)
Expand Down
44 changes: 23 additions & 21 deletions rpcs3/Emu/Cell/SPUThread.cpp
Expand Up @@ -1675,26 +1675,12 @@ void spu_thread::cpu_task()
}
}

spu_thread::~spu_thread()
void spu_thread::cleanup()
{
{
vm::writer_lock(0);
elad335 marked this conversation as resolved.
Show resolved Hide resolved
const u32 addr = group ? SPU_FAKE_BASE_ADDR + SPU_LS_SIZE * (id & 0xffffff) : RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index;

for (s32 i = -1; i < 2; i++)
{
// Unmap LS mirrors
shm->unmap_critical(ls + (i * SPU_LS_SIZE));
}
}

if (!group)
{
// Deallocate local storage (thread groups are handled in sys_spu.cpp)
ensure(vm::dealloc(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, vm::spu));
}

// Release LS mirrors area
utils::memory_release(ls - (SPU_LS_SIZE * 2), SPU_LS_SIZE * 5);
// Deallocate local storage
ensure(vm::dealloc(addr, vm::spu, &shm));

// Deallocate RawSPU ID
if (get_type() >= spu_type::raw)
Expand All @@ -1710,14 +1696,28 @@ spu_thread::~spu_thread()
perf_log.notice("Perf stats for PUTLLC reload: successs %u, failure %u", last_succ, last_fail);
}

spu_thread::~spu_thread()
{
{
vm::writer_lock lock(0);

for (s32 i = -1; i < 2; i++)
{
// Unmap LS mirrors
shm->unmap_critical(ls + (i * SPU_LS_SIZE));
}
}

// Release LS mirrors area
utils::memory_release(ls - (SPU_LS_SIZE * 2), SPU_LS_SIZE * 5);
}

spu_thread::spu_thread(lv2_spu_group* group, u32 index, std::string_view name, u32 lv2_id, bool is_isolated, u32 option)
: cpu_thread(idm::last_id())
, index(index)
, shm(std::make_shared<utils::shm>(SPU_LS_SIZE))
, ls([&]()
{
const auto addr = static_cast<u8*>(utils::memory_reserve(SPU_LS_SIZE * 5));

if (!group)
{
ensure(vm::get(vm::spu)->falloc(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * index, SPU_LS_SIZE, &shm));
Expand All @@ -1728,7 +1728,9 @@ spu_thread::spu_thread(lv2_spu_group* group, u32 index, std::string_view name, u
ensure(vm::get(vm::spu)->falloc(SPU_FAKE_BASE_ADDR + SPU_LS_SIZE * (cpu_thread::id & 0xffffff), SPU_LS_SIZE, &shm, 0x1000));
}

vm::writer_lock(0);
vm::writer_lock lock(0);

const auto addr = static_cast<u8*>(utils::memory_reserve(SPU_LS_SIZE * 5));

for (u32 i = 1; i < 4; i++)
{
Expand Down
1 change: 1 addition & 0 deletions rpcs3/Emu/Cell/SPUThread.h
Expand Up @@ -634,6 +634,7 @@ class spu_thread : public cpu_thread
virtual void cpu_task() override final;
virtual void cpu_return() override;
virtual ~spu_thread() override;
void cleanup();
void cpu_init();

static const u32 id_base = 0x02000000; // TODO (used to determine thread type)
Expand Down
8 changes: 2 additions & 6 deletions rpcs3/Emu/Cell/lv2/sys_interrupt.cpp
Expand Up @@ -22,18 +22,14 @@ void lv2_int_serv::exec()
thread_ctrl::notify(*thread);
}

bool interrupt_thread_exit(ppu_thread& ppu)
{
ppu.state += cpu_flag::exit;
return false;
}
bool ppu_thread_exit(ppu_thread& ppu);

void lv2_int_serv::join()
{
thread->cmd_list
({
{ ppu_cmd::ptr_call, 0 },
std::bit_cast<u64>(&interrupt_thread_exit)
std::bit_cast<u64>(&ppu_thread_exit)
});

thread_ctrl::notify(*thread);
Expand Down
46 changes: 40 additions & 6 deletions rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp
Expand Up @@ -2,6 +2,7 @@
#include "sys_ppu_thread.h"

#include "Emu/IdManager.h"
#include "Emu/perf_meter.hpp"

#include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/PPUThread.h"
Expand Down Expand Up @@ -36,6 +37,22 @@ struct ppu_thread_cleaner
}
};

bool ppu_thread_exit(ppu_thread& ppu)
{
ppu.state += cpu_flag::exit + cpu_flag::wait;

// Deallocate Stack Area
ensure(vm::dealloc(ppu.stack_addr, vm::stack) == ppu.stack_size);

if (const auto dct = g_fxo->get<lv2_memory_container>())
{
dct->used -= ppu.stack_size;
}

perf_log.notice("Perf stats for STCX reload: successs %u, failure %u", ppu.last_succ, ppu.last_fail);
return false;
}

void _sys_ppu_thread_exit(ppu_thread& ppu, u64 errorcode)
{
ppu.state += cpu_flag::wait;
Expand Down Expand Up @@ -77,10 +94,15 @@ void _sys_ppu_thread_exit(ppu_thread& ppu, u64 errorcode)
ppu.state -= cpu_flag::suspend;
}

if (old_status == ppu_join_status::detached)
g_fxo->get<ppu_thread_cleaner>()->clean(old_status == ppu_join_status::detached ? ppu.id : 0);

if (old_status == ppu_join_status::joinable)
{
g_fxo->get<ppu_thread_cleaner>()->clean(ppu.id);
// Wait for termination
thread_ctrl::wait_on(ppu.joiner, ppu_join_status::zombie);
}

ppu_thread_exit(ppu);
}

s32 sys_ppu_thread_yield(ppu_thread& ppu)
Expand Down Expand Up @@ -114,7 +136,7 @@ error_code sys_ppu_thread_join(ppu_thread& ppu, u32 thread_id, vm::ptr<u64> vptr
if (value == ppu_join_status::zombie)
{
value = ppu_join_status::exited;
return CELL_EBUSY;
return CELL_EAGAIN;
}

if (value == ppu_join_status::exited)
Expand All @@ -135,6 +157,10 @@ error_code sys_ppu_thread_join(ppu_thread& ppu, u32 thread_id, vm::ptr<u64> vptr
{
lv2_obj::sleep(ppu);
}
else if (result == CELL_EAGAIN)
{
thread.joiner.notify_one();
}

return result;
});
Expand All @@ -144,7 +170,7 @@ error_code sys_ppu_thread_join(ppu_thread& ppu, u32 thread_id, vm::ptr<u64> vptr
return CELL_ESRCH;
}

if (thread.ret && thread.ret != CELL_EBUSY)
if (thread.ret && thread.ret != CELL_EAGAIN)
{
return thread.ret;
}
Expand Down Expand Up @@ -183,7 +209,7 @@ error_code sys_ppu_thread_detach(ppu_thread& ppu, u32 thread_id)

const auto thread = idm::check<named_thread<ppu_thread>>(thread_id, [&](ppu_thread& thread) -> CellError
{
return thread.joiner.atomic_op([](ppu_join_status& value) -> CellError
CellError result = thread.joiner.atomic_op([](ppu_join_status& value) -> CellError
{
if (value == ppu_join_status::zombie)
{
Expand All @@ -209,6 +235,13 @@ error_code sys_ppu_thread_detach(ppu_thread& ppu, u32 thread_id)
value = ppu_join_status::detached;
return {};
});

if (result == CELL_EAGAIN)
{
thread.joiner.notify_one();
}

return result;
});

if (!thread)
Expand All @@ -223,7 +256,8 @@ error_code sys_ppu_thread_detach(ppu_thread& ppu, u32 thread_id)

if (thread.ret == CELL_EAGAIN)
{
ensure(idm::remove<named_thread<ppu_thread>>(thread_id));
g_fxo->get<ppu_thread_cleaner>()->clean(thread_id);
g_fxo->get<ppu_thread_cleaner>()->clean(0);
}

return CELL_OK;
Expand Down
13 changes: 11 additions & 2 deletions rpcs3/Emu/Cell/lv2/sys_spu.cpp
Expand Up @@ -687,7 +687,7 @@ error_code sys_spu_thread_group_destroy(ppu_thread& ppu, u32 id)
if (auto thread = t.get())
{
// Deallocate LS
ensure(vm::get(vm::spu)->dealloc(SPU_FAKE_BASE_ADDR + SPU_LS_SIZE * (thread->id & 0xffffff), &thread->shm));
thread->cleanup();

// Remove ID from IDM (destruction will occur in group destructor)
idm::remove<named_thread<spu_thread>>(thread->id);
Expand Down Expand Up @@ -1989,7 +1989,16 @@ error_code raw_spu_destroy(ppu_thread& ppu, u32 id)

(*thread)();

if (!idm::remove_verify<named_thread<spu_thread>>(idm_id, std::move(thread.ptr)))
if (idm::withdraw<named_thread<spu_thread>>(idm_id, [&](spu_thread& spu) -> CellError
{
if (std::addressof(spu) != std::addressof(*thread))
{
return CELL_ESRCH;
}

spu.cleanup();
return {};
}).ret)
{
// Other thread destroyed beforehead
return CELL_ESRCH;
Expand Down