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

Make sys_spu_thread_group_join return once per termination #5643

Merged
merged 3 commits into from Feb 9, 2019
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
2 changes: 1 addition & 1 deletion rpcs3/Emu/Cell/Modules/cellSpurs.cpp
Expand Up @@ -574,7 +574,7 @@ void _spurs::handler_entry(ppu_thread& ppu, vm::ptr<CellSpurs> spurs)

CHECK_SUCCESS(sys_spu_thread_group_start(ppu, spurs->spuTG));

if (s32 rc = sys_spu_thread_group_join(ppu, spurs->spuTG, vm::null, vm::null))
if (s32 rc = sys_spu_thread_group_join(ppu, spurs->spuTG, vm::var<u32>{}, vm::var<u32>{}))
{
if (rc == CELL_ESTAT)
{
Expand Down
14 changes: 8 additions & 6 deletions rpcs3/Emu/Cell/PPUThread.cpp
Expand Up @@ -1092,17 +1092,18 @@ extern bool ppu_stwcx(ppu_thread& ppu, u32 addr, u32 reg_value)
vm::passive_unlock(ppu);

auto& res = vm::reservation_lock(addr, sizeof(u32));
const u64 old_time = res.load() & ~1ull;

const bool result = ppu.rtime == (res & ~1ull) && data.compare_and_swap_test(old_data, reg_value);
const bool result = ppu.rtime == old_time && data.compare_and_swap_test(old_data, reg_value);

if (result)
{
res++;
res.release(old_time + 2);
vm::reservation_notifier(addr, sizeof(u32)).notify_all();
}
else
{
res &= ~1ull;
res.release(old_time);
}

vm::passive_lock(ppu);
Expand Down Expand Up @@ -1185,17 +1186,18 @@ extern bool ppu_stdcx(ppu_thread& ppu, u32 addr, u64 reg_value)
vm::passive_unlock(ppu);

auto& res = vm::reservation_lock(addr, sizeof(u64));
const u64 old_time = res.load() & ~1ull;

const bool result = ppu.rtime == (res & ~1ull) && data.compare_and_swap_test(old_data, reg_value);
const bool result = ppu.rtime == old_time && data.compare_and_swap_test(old_data, reg_value);

if (result)
{
res++;
res.release(old_time + 2);
vm::reservation_notifier(addr, sizeof(u64)).notify_all();
}
else
{
res &= ~1ull;
res.release(old_time);
}

vm::passive_lock(ppu);
Expand Down
61 changes: 34 additions & 27 deletions rpcs3/Emu/Cell/SPUThread.cpp
Expand Up @@ -471,20 +471,20 @@ void spu_thread::cpu_init()
ch_tag_upd = 0;
ch_tag_mask = 0;
mfc_prxy_mask = 0;
ch_tag_stat.data.store({});
ch_tag_stat.data.release({});
ch_stall_mask = 0;
ch_stall_stat.data.store({});
ch_atomic_stat.data.store({});
ch_stall_stat.data.release({});
ch_atomic_stat.data.release({});

ch_in_mbox.clear();

ch_out_mbox.data.store({});
ch_out_intr_mbox.data.store({});
ch_out_mbox.data.release({});
ch_out_intr_mbox.data.release({});

snr_config = 0;

ch_snr1.data.store({});
ch_snr2.data.store({});
ch_snr1.data.release({});
ch_snr2.data.release({});

ch_event_mask = 0;
ch_event_stat = 0;
Expand All @@ -494,9 +494,9 @@ void spu_thread::cpu_init()
ch_dec_start_timestamp = get_timebased_time(); // ???
ch_dec_value = 0;

run_ctrl = 0;
status = 0;
npc = 0;
run_ctrl.release(0);
status.release(0);
npc.release(0);

int_ctrl[0].clear();
int_ctrl[1].clear();
Expand All @@ -521,6 +521,11 @@ void spu_thread::cpu_stop()
group->stop_count++;
group->run_state = SPU_THREAD_GROUP_STATUS_INITIALIZED;

if (!group->join_state)
{
group->join_state = SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT;
}

if (const auto ppu = std::exchange(group->waiter, nullptr))
{
// Send exit status directly to the joining thread
Expand Down Expand Up @@ -805,28 +810,28 @@ void spu_thread::do_dma_transfer(const spu_mfc_cmd& args)
{
auto& res = vm::reservation_lock(eal, 1);
*reinterpret_cast<u8*>(dst) = *reinterpret_cast<const u8*>(src);
res++;
res.release(res.load() + 1);
break;
}
case 2:
{
auto& res = vm::reservation_lock(eal, 2);
*reinterpret_cast<u16*>(dst) = *reinterpret_cast<const u16*>(src);
res++;
res.release(res.load() + 1);
break;
}
case 4:
{
auto& res = vm::reservation_lock(eal, 4);
*reinterpret_cast<u32*>(dst) = *reinterpret_cast<const u32*>(src);
res++;
res.release(res.load() + 1);
break;
}
case 8:
{
auto& res = vm::reservation_lock(eal, 8);
*reinterpret_cast<u64*>(dst) = *reinterpret_cast<const u64*>(src);
res++;
res.release(res.load() + 1);
break;
}
default:
Expand All @@ -845,7 +850,7 @@ void spu_thread::do_dma_transfer(const spu_mfc_cmd& args)
size -= 16;
}

res++;
res.release(res.load() + 1);
break;
}

Expand All @@ -869,7 +874,7 @@ void spu_thread::do_dma_transfer(const spu_mfc_cmd& args)
size -= 16;
}

*lock = 0;
lock->release(0);
break;
}
}
Expand Down Expand Up @@ -1081,12 +1086,12 @@ void spu_thread::do_putlluc(const spu_mfc_cmd& args)
// TODO: vm::check_addr
vm::writer_lock lock(addr);
mov_rdata(data.data(), to_write.data());
res++;
res.release(res.load() + 1);
}
else
{
mov_rdata(data.data(), to_write.data());
res++;
res.release(res.load() + 1);
}
}

Expand Down Expand Up @@ -1276,6 +1281,7 @@ bool spu_thread::process_mfc_cmd()
else
{
auto& res = vm::reservation_lock(addr, 128);
const u64 old_time = res.load() & ~1ull;

if (g_cfg.core.spu_accurate_getllar)
{
Expand All @@ -1285,15 +1291,15 @@ bool spu_thread::process_mfc_cmd()
// TODO: vm::check_addr
vm::writer_lock lock(addr);

ntime = res & ~1ull;
ntime = old_time;
mov_rdata(dst.data(), data.data());
res &= ~1ull;
res.release(old_time);
}
else
{
ntime = res & ~1ull;
ntime = old_time;
mov_rdata(dst.data(), data.data());
res &= ~1ull;
res.release(old_time);
}
}

Expand Down Expand Up @@ -1350,8 +1356,9 @@ bool spu_thread::process_mfc_cmd()
else if (auto& data = vm::_ref<decltype(rdata)>(addr); rdata == data)
{
auto& res = vm::reservation_lock(raddr, 128);
const u64 old_time = res.load() & ~1ull;

if (rtime == (res & ~1ull))
if (rtime == old_time)
{
*reinterpret_cast<atomic_t<u32>*>(&data) += 0;

Expand All @@ -1362,17 +1369,17 @@ bool spu_thread::process_mfc_cmd()
if (rdata == data)
{
mov_rdata(data.data(), to_write.data());
res++;
res.release(old_time + 2);
result = 1;
}
else
{
res &= ~1ull;
res.release(old_time);
}
}
else
{
res &= ~1ull;
res.release(old_time);
}
}
}
Expand Down Expand Up @@ -2436,7 +2443,7 @@ bool spu_thread::stop_and_signal(u32 code)
}

group->exit_status = value;
group->join_state |= SPU_TGJSF_GROUP_EXIT;
group->join_state = SYS_SPU_THREAD_GROUP_JOIN_GROUP_EXIT;

state += cpu_flag::stop;
return true;
Expand Down
8 changes: 4 additions & 4 deletions rpcs3/Emu/Cell/SPUThread.h
Expand Up @@ -276,8 +276,8 @@ struct spu_channel_4_t
public:
void clear()
{
values.store({});
value3 = 0;
values.release({});
value3.release(0);
}

// push unconditionally (overwriting latest value), returns true if needs signaling
Expand Down Expand Up @@ -364,8 +364,8 @@ struct spu_int_ctrl_t

void clear()
{
mask = 0;
stat = 0;
mask.release(0);
stat.release(0);
tag = nullptr;
}
};
Expand Down
2 changes: 1 addition & 1 deletion rpcs3/Emu/Cell/lv2/sys_lwcond.cpp
Expand Up @@ -266,7 +266,7 @@ error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
return cpu;
}

mutex->signaled = 1;
mutex->signaled.release(1);
return nullptr;
});

Expand Down
2 changes: 1 addition & 1 deletion rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp
Expand Up @@ -175,7 +175,7 @@ error_code _sys_lwmutex_unlock(ppu_thread& ppu, u32 lwmutex_id)
return cpu;
}

mutex.signaled = 1;
mutex.signaled.release(1);
return nullptr;
});

Expand Down
18 changes: 10 additions & 8 deletions rpcs3/Emu/Cell/lv2/sys_ppu_thread.cpp
Expand Up @@ -120,19 +120,21 @@ error_code sys_ppu_thread_join(ppu_thread& ppu, u32 thread_id, vm::ptr<u64> vptr
// Wait for cleanup
(*thread.ptr)();

// Get the exit status from the register
if (vptr)
if (ppu.test_stopped())
{
if (ppu.test_stopped())
{
return 0;
}

*vptr = thread->gpr[3];
return 0;
}

// Cleanup
idm::remove<named_thread<ppu_thread>>(thread->id);

if (!vptr)
{
return CELL_EFAULT;
}

// Get the exit status from the register
*vptr = thread->gpr[3];
return CELL_OK;
}

Expand Down
42 changes: 14 additions & 28 deletions rpcs3/Emu/Cell/lv2/sys_spu.cpp
Expand Up @@ -607,7 +607,7 @@ error_code sys_spu_thread_group_terminate(u32 id, s32 value)
}

group->exit_status = value;
group->join_state |= SPU_TGJSF_TERMINATED;
group->join_state = SYS_SPU_THREAD_GROUP_JOIN_TERMINATED;

// Wait until the threads are actually stopped
const u64 last_stop = group->stop_count - !group->running;
Expand Down Expand Up @@ -648,11 +648,12 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr<u32> cause
return CELL_EBUSY;
}

if (group->run_state == SPU_THREAD_GROUP_STATUS_INITIALIZED)
if (group->join_state)
{
// Already terminated
// Already signaled
ppu.gpr[4] = group->join_state;
ppu.gpr[5] = group->exit_status;
group->join_state.release(0);
break;
}
else
Expand All @@ -661,11 +662,9 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr<u32> cause
group->waiter = &ppu;
}

const u64 last_stop = group->stop_count - !group->running;

lv2_obj::sleep(ppu);

while (group->stop_count == last_stop)
while (!group->join_state)
{
if (ppu.is_stopped())
{
Expand All @@ -674,6 +673,8 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr<u32> cause

group->cond.wait(lock);
}

group->join_state.release(0);
}
while (0);

Expand All @@ -682,34 +683,19 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr<u32> cause
return 0;
}

switch (ppu.gpr[4] & (SPU_TGJSF_GROUP_EXIT | SPU_TGJSF_TERMINATED))
{
case 0:
{
if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_ALL_THREADS_EXIT;
break;
}
case SPU_TGJSF_GROUP_EXIT:
if (!cause)
{
if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_GROUP_EXIT;
break;
}
case SPU_TGJSF_TERMINATED:
{
if (cause) *cause = SYS_SPU_THREAD_GROUP_JOIN_TERMINATED;
break;
}
default:
{
fmt::throw_exception("Unexpected join_state" HERE);
}
return CELL_EFAULT;
}

if (status)
*cause = static_cast<u32>(ppu.gpr[4]);

if (!status)
{
*status = static_cast<s32>(ppu.gpr[5]);
return CELL_EFAULT;
}

*status = static_cast<s32>(ppu.gpr[5]);
return CELL_OK;
}

Expand Down