SPU/LV2: Fix tiny race conditions

This commit is contained in:
Eladash 2022-09-18 21:19:34 +03:00 committed by Ivan
parent 3581c5b078
commit 194f7375da
18 changed files with 130 additions and 36 deletions

View file

@ -695,7 +695,6 @@ bool cpu_thread::check_state() noexcept
{
// Sticky flag, indicates check_state() is not allowed to return true
flags -= cpu_flag::temp;
flags -= cpu_flag::wait;
cpu_can_stop = false;
store = true;
}
@ -766,9 +765,9 @@ bool cpu_thread::check_state() noexcept
}
else
{
if (cpu_can_stop && !(flags & cpu_flag::wait))
if (flags & cpu_flag::wait)
{
flags += cpu_flag::wait;
flags -= cpu_flag::wait;
store = true;
}

View file

@ -99,6 +99,7 @@ error_code sys_cond_create(ppu_thread& ppu, vm::ptr<u32> cond_id, u32 mutex_id,
return error;
}
ppu.check_state();
*cond_id = idm::last_id();
return CELL_OK;
}

View file

@ -220,6 +220,7 @@ error_code sys_event_queue_create(cpu_thread& cpu, vm::ptr<u32> equeue_id, vm::p
return error;
}
cpu.check_state();
*equeue_id = idm::last_id();
return CELL_OK;
}
@ -381,7 +382,9 @@ error_code sys_event_queue_tryreceive(ppu_thread& ppu, u32 equeue_id, vm::ptr<sy
return CELL_EINVAL;
}
std::lock_guard lock(queue->mutex);
std::array<sys_event_t, 127> events;
std::unique_lock lock(queue->mutex);
if (!queue->exists)
{
@ -392,13 +395,17 @@ error_code sys_event_queue_tryreceive(ppu_thread& ppu, u32 equeue_id, vm::ptr<sy
while (count < size && !queue->events.empty())
{
auto& dest = event_array[count++];
auto& dest = events[count++];
const auto event = queue->events.front();
queue->events.pop_front();
std::tie(dest.source, dest.data1, dest.data2, dest.data3) = event;
}
lock.unlock();
ppu.check_state();
std::copy_n(event_array.get_ptr(), count, events.begin());
*number = count;
return CELL_OK;
@ -559,6 +566,7 @@ error_code sys_event_port_create(cpu_thread& cpu, vm::ptr<u32> eport_id, s32 por
if (const u32 id = idm::make<lv2_obj, lv2_event_port>(port_type, name))
{
cpu.check_state();
*eport_id = id;
return CELL_OK;
}

View file

@ -77,6 +77,7 @@ error_code sys_event_flag_create(ppu_thread& ppu, vm::ptr<u32> id, vm::ptr<sys_e
return error;
}
ppu.check_state();
*id = idm::last_id();
return CELL_OK;
}
@ -253,6 +254,7 @@ error_code sys_event_flag_wait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode, vm
}
}
ppu.check_state();
store.val = ppu.gpr[6];
return not_an_error(ppu.gpr[3]);
}
@ -291,6 +293,8 @@ error_code sys_event_flag_trywait(ppu_thread& ppu, u32 id, u64 bitptn, u32 mode,
return not_an_error(CELL_EBUSY);
}
ppu.check_state();
if (result) *result = pattern;
return CELL_OK;
}
@ -503,6 +507,8 @@ error_code sys_event_flag_get(ppu_thread& ppu, u32 id, vm::ptr<u64> flags)
return +flag.pattern;
});
ppu.check_state();
if (!flag)
{
if (flags) *flags = 0;

View file

@ -839,6 +839,7 @@ error_code sys_fs_open(ppu_thread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<
return result;
}))
{
ppu.check_state();
*fd = id;
return CELL_OK;
}
@ -962,7 +963,7 @@ error_code sys_fs_write(ppu_thread& ppu, u32 fd, vm::cptr<void> buf, u64 nbytes,
return CELL_EROFS;
}
std::lock_guard lock(file->mp->mutex);
std::unique_lock lock(file->mp->mutex);
if (!file->file)
{
@ -986,8 +987,11 @@ error_code sys_fs_write(ppu_thread& ppu, u32 fd, vm::cptr<void> buf, u64 nbytes,
file->file.seek(0, fs::seek_end);
}
*nwrite = file->op_write(buf, nbytes);
const u64 written = file->op_write(buf, nbytes);
lock.unlock();
ppu.check_state();
*nwrite = written;
return CELL_OK;
}
@ -1102,7 +1106,7 @@ error_code sys_fs_opendir(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u32> fd)
return {CELL_ENOTDIR, path};
}
std::lock_guard lock(mp->mutex);
std::unique_lock lock(mp->mutex);
const fs::dir dir(local_path);
@ -1177,6 +1181,9 @@ error_code sys_fs_opendir(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u32> fd)
if (const u32 id = idm::make<lv2_fs_object, lv2_dir>(processed_path, std::move(data)))
{
lock.unlock();
ppu.check_state();
*fd = id;
return CELL_OK;
}
@ -1199,6 +1206,8 @@ error_code sys_fs_readdir(ppu_thread& ppu, u32 fd, vm::ptr<CellFsDirent> dir, vm
return CELL_EBADF;
}
ppu.check_state();
if (auto* info = directory->dir_read())
{
dir->d_type = info->is_directory ? CELL_FS_TYPE_DIRECTORY : CELL_FS_TYPE_REGULAR;
@ -1265,7 +1274,7 @@ error_code sys_fs_stat(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<CellFsStat>
return {CELL_ENOTMOUNTED, path};
}
std::lock_guard lock(mp->mutex);
std::unique_lock lock(mp->mutex);
fs::stat_t info{};
@ -1308,6 +1317,9 @@ error_code sys_fs_stat(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<CellFsStat>
}
}
lock.unlock();
ppu.check_state();
sb->mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666;
sb->uid = mp->flags & lv2_mp_flag::no_uid_gid ? -1 : 0;
sb->gid = mp->flags & lv2_mp_flag::no_uid_gid ? -1 : 0;
@ -1340,7 +1352,7 @@ error_code sys_fs_fstat(ppu_thread& ppu, u32 fd, vm::ptr<CellFsStat> sb)
return CELL_EBADF;
}
std::lock_guard lock(file->mp->mutex);
std::unique_lock lock(file->mp->mutex);
if (!file->file)
{
@ -1352,7 +1364,9 @@ error_code sys_fs_fstat(ppu_thread& ppu, u32 fd, vm::ptr<CellFsStat> sb)
return CELL_EIO;
}
const fs::stat_t& info = file->file.stat();
const fs::stat_t info = file->file.stat();
lock.unlock();
ppu.check_state();
sb->mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666;
sb->uid = file->mp->flags & lv2_mp_flag::no_uid_gid ? -1 : 0;
@ -2342,7 +2356,7 @@ error_code sys_fs_lseek(ppu_thread& ppu, u32 fd, s64 offset, s32 whence, vm::ptr
return CELL_EBADF;
}
std::lock_guard lock(file->mp->mutex);
std::unique_lock lock(file->mp->mutex);
if (!file->file)
{
@ -2367,6 +2381,9 @@ error_code sys_fs_lseek(ppu_thread& ppu, u32 fd, s64 offset, s32 whence, vm::ptr
return CELL_EIO; // ???
}
lock.unlock();
ppu.check_state();
*pos = result;
return CELL_OK;
}
@ -2662,6 +2679,8 @@ error_code sys_fs_disk_free(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u64> t
return {CELL_ENOTSUP, path};
}
ppu.check_state();
if (mp->flags & lv2_mp_flag::read_only)
{
// TODO: check /dev_bdvd

View file

@ -190,6 +190,7 @@ error_code _sys_interrupt_thread_establish(ppu_thread& ppu, vm::ptr<u32> ih, u32
if (id)
{
ppu.check_state();
*ih = id;
return CELL_OK;
}

View file

@ -50,6 +50,7 @@ error_code _sys_lwcond_create(ppu_thread& ppu, vm::ptr<u32> lwcond_id, u32 lwmut
if (const u32 id = idm::make<lv2_obj, lv2_lwcond>(name, lwmutex_id, protocol, control))
{
ppu.check_state();
*lwcond_id = id;
return CELL_OK;
}

View file

@ -42,6 +42,7 @@ error_code _sys_lwmutex_create(ppu_thread& ppu, vm::ptr<u32> lwmutex_id, u32 pro
if (const u32 id = idm::make<lv2_obj, lv2_lwmutex>(protocol, control, name))
{
ppu.check_state();
*lwmutex_id = id;
return CELL_OK;
}

View file

@ -132,6 +132,7 @@ error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr<u32
if (alloc_addr)
{
vm::lock_sudo(addr, size);
cpu.check_state();
*alloc_addr = addr;
return CELL_OK;
}
@ -203,6 +204,7 @@ error_code sys_memory_allocate_from_container(cpu_thread& cpu, u32 size, u32 cid
if (alloc_addr)
{
vm::lock_sudo(addr, size);
cpu.check_state();
*alloc_addr = addr;
return CELL_OK;
}
@ -282,17 +284,22 @@ error_code sys_memory_get_user_memory_size(cpu_thread& cpu, vm::ptr<sys_memory_i
// Get "default" memory container
auto& dct = g_fxo->get<lv2_memory_container>();
::reader_lock lock(s_memstats_mtx);
mem_info->total_user_memory = dct.size;
mem_info->available_user_memory = dct.size - dct.used;
// Scan other memory containers
idm::select<lv2_memory_container>([&](u32, lv2_memory_container& ct)
sys_memory_info_t out{};
{
mem_info->total_user_memory -= ct.size;
});
::reader_lock lock(s_memstats_mtx);
out.total_user_memory = dct.size;
out.available_user_memory = dct.size - dct.used;
// Scan other memory containers
idm::select<lv2_memory_container>([&](u32, lv2_memory_container& ct)
{
out.total_user_memory -= ct.size;
});
}
cpu.check_state();
*mem_info = out;
return CELL_OK;
}
@ -332,6 +339,7 @@ error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr<u32> cid, u32 si
// Create the memory container
if (const u32 id = idm::make<lv2_memory_container>(size, true))
{
cpu.check_state();
*cid = id;
return CELL_OK;
}
@ -388,6 +396,7 @@ error_code sys_memory_container_get_size(cpu_thread& cpu, vm::ptr<sys_memory_inf
return CELL_ESRCH;
}
cpu.check_state();
mem_info->total_user_memory = ct->size; // Total container memory
mem_info->available_user_memory = ct->size - ct->used; // Available container memory

View file

@ -174,6 +174,7 @@ error_code sys_mmapper_allocate_address(ppu_thread& ppu, u64 size, u64 flags, u6
{
if (const auto area = vm::find_map(static_cast<u32>(size), static_cast<u32>(alignment), flags & SYS_MEMORY_PAGE_SIZE_MASK))
{
ppu.check_state();
*alloc_addr = area->addr;
return CELL_OK;
}
@ -246,6 +247,7 @@ error_code sys_mmapper_allocate_shared_memory(ppu_thread& ppu, u64 ipc_key, u64
return error;
}
ppu.check_state();
*mem_id = idm::last_id();
return CELL_OK;
}
@ -301,6 +303,7 @@ error_code sys_mmapper_allocate_shared_memory_from_container(ppu_thread& ppu, u6
return error;
}
ppu.check_state();
*mem_id = idm::last_id();
return CELL_OK;
}
@ -399,6 +402,7 @@ error_code sys_mmapper_allocate_shared_memory_ext(ppu_thread& ppu, u64 ipc_key,
return error;
}
ppu.check_state();
*mem_id = idm::last_id();
return CELL_OK;
}
@ -496,6 +500,7 @@ error_code sys_mmapper_allocate_shared_memory_from_container_ext(ppu_thread& ppu
return error;
}
ppu.check_state();
*mem_id = idm::last_id();
return CELL_OK;
}
@ -718,6 +723,8 @@ error_code sys_mmapper_search_and_map(ppu_thread& ppu, u32 start_addr, u32 mem_i
}
vm::lock_sudo(addr, mem->size);
ppu.check_state();
*alloc_addr = addr;
return CELL_OK;
}
@ -763,6 +770,7 @@ error_code sys_mmapper_unmap_shared_memory(ppu_thread& ppu, u32 addr, vm::ptr<u3
}
// Write out the ID
ppu.check_state();
*mem_id = mem.ret;
// Acknowledge

View file

@ -92,6 +92,7 @@ error_code sys_mutex_create(ppu_thread& ppu, vm::ptr<u32> mutex_id, vm::ptr<sys_
return error;
}
ppu.check_state();
*mutex_id = idm::last_id();
return CELL_OK;
}

View file

@ -488,8 +488,10 @@ error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, vm::p
return CELL_EAGAIN;
}
*thread_id = tid;
sys_ppu_thread.warning(u8"_sys_ppu_thread_create(): Thread “%s” created (id=0x%x, func=*0x%x, rtoc=0x%x, user-tls=0x%x)", ppu_name, tid, entry.addr, entry.rtoc, tls);
ppu.check_state();
*thread_id = tid;
return CELL_OK;
}

View file

@ -542,6 +542,7 @@ error_code _sys_prx_start_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr<sys
return CELL_PRX_ERROR_ERROR;
}
ppu.check_state();
pOpt->entry.set(prx->start ? prx->start.addr() : ~0ull);
// This check is probably for older fw
@ -594,6 +595,7 @@ error_code _sys_prx_stop_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr<sys_
fmt::throw_exception("Invalid prx state (%d)", old);
}
ppu.check_state();
pOpt->entry.set(prx->stop ? prx->stop.addr() : ~0ull);
set_entry2(prx->epilogue ? prx->epilogue.addr() : ~0ull);
return CELL_OK;
@ -633,6 +635,7 @@ error_code _sys_prx_stop_module(ppu_thread& ppu, u32 id, u64 flags, vm::ptr<sys_
if (pOpt->cmd == 4u)
{
ppu.check_state();
pOpt->entry.set(prx->stop ? prx->stop.addr() : ~0ull);
set_entry2(prx->epilogue ? prx->epilogue.addr() : ~0ull);
}

View file

@ -62,6 +62,7 @@ error_code sys_rwlock_create(ppu_thread& ppu, vm::ptr<u32> rw_lock_id, vm::ptr<s
return error;
}
ppu.check_state();
*rw_lock_id = idm::last_id();
return CELL_OK;
}

View file

@ -457,6 +457,7 @@ error_code _sys_spu_image_get_information(ppu_thread& ppu, vm::ptr<sys_spu_image
return CELL_ESRCH;
}
ppu.check_state();
*entry_point = image->e_entry;
*nsegs = image->nsegs;
return CELL_OK;
@ -540,6 +541,7 @@ error_code _sys_spu_image_get_segments(ppu_thread& ppu, vm::ptr<sys_spu_image> i
}
// TODO: apply SPU patches
ppu.check_state();
std::memcpy(segments.get_ptr(), handle->segs.get_ptr(), sizeof(sys_spu_segment) * std::min<s32>(nseg, handle->nsegs));
return CELL_OK;
}
@ -674,7 +676,7 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
return CELL_EINVAL;
}
std::lock_guard lock(group->mutex);
std::unique_lock lock(group->mutex);
if (auto state = +group->run_state; state != SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED)
{
@ -713,8 +715,6 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
ensure(vm::get(vm::spu)->falloc(spu->vm_offset(), SPU_LS_SIZE, &spu->shm, static_cast<u64>(vm::page_size_64k) | static_cast<u64>(vm::alloc_hidden)));
spu->map_ls(*spu->shm, spu->ls);
*thread = tid;
group->args[inited] = {arg->arg1, arg->arg2, arg->arg3, arg->arg4};
group->imgs[inited].first = image.entry_point;
group->imgs[inited].second = std::move(spu_segs);
@ -740,7 +740,11 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
}
}
lock.unlock();
sys_spu.warning(u8"sys_spu_thread_initialize(): Thread “%s” created (id=0x%x)", thread_name, tid);
ppu.check_state();
*thread = tid;
return CELL_OK;
}
@ -781,6 +785,7 @@ error_code sys_spu_thread_get_exit_status(ppu_thread& ppu, u32 id, vm::ptr<s32>
if (thread->exit_status.try_read(data))
{
ppu.check_state();
*status = static_cast<s32>(data);
return CELL_OK;
}
@ -924,7 +929,7 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
auto& limits = g_fxo->get<spu_limits_t>();
std::lock_guard lock(limits.mutex);
std::unique_lock lock(limits.mutex);
if (!limits.check(use_scheduler ? limits_data{.controllable = num} : limits_data{.physical = num}))
{
@ -940,8 +945,11 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
return CELL_EAGAIN;
}
*id = idm::last_id();
lock.unlock();
sys_spu.warning(u8"sys_spu_thread_group_create(): Thread group “%s” created (id=0x%x)", group->name, idm::last_id());
ppu.check_state();
*id = idm::last_id();
return CELL_OK;
}
@ -1490,6 +1498,8 @@ error_code sys_spu_thread_group_join(ppu_thread& ppu, u32 id, vm::ptr<u32> cause
}
while (false);
ppu.check_state();
if (!cause)
{
if (status)
@ -1548,6 +1558,8 @@ error_code sys_spu_thread_group_get_priority(ppu_thread& ppu, u32 id, vm::ptr<s3
return CELL_ESRCH;
}
ppu.check_state();
if (!group->has_scheduler_context)
{
*priority = 0;
@ -1608,6 +1620,7 @@ error_code sys_spu_thread_group_syscall_253(ppu_thread& ppu, u32 id, vm::ptr<sys
// TODO
ppu.check_state();
info->deadlineMissCounter = 0;
info->deadlineMeetCounter = 0;
info->timestamp = get_timebased_time();
@ -1675,7 +1688,7 @@ error_code sys_spu_thread_read_ls(ppu_thread& ppu, u32 id, u32 lsa, vm::ptr<u64>
return CELL_ESRCH;
}
std::lock_guard lock(group->mutex);
std::unique_lock lock(group->mutex);
if (auto state = +group->run_state;
state < SPU_THREAD_GROUP_STATUS_WAITING || state > SPU_THREAD_GROUP_STATUS_RUNNING)
@ -1688,15 +1701,21 @@ error_code sys_spu_thread_read_ls(ppu_thread& ppu, u32 id, u32 lsa, vm::ptr<u64>
return CELL_ESTAT;
}
u64 _value{};
switch (type)
{
case 1: *value = thread->_ref<u8>(lsa); break;
case 2: *value = thread->_ref<u16>(lsa); break;
case 4: *value = thread->_ref<u32>(lsa); break;
case 8: *value = thread->_ref<u64>(lsa); break;
case 1: _value = thread->_ref<u8>(lsa); break;
case 2: _value = thread->_ref<u16>(lsa); break;
case 4: _value = thread->_ref<u32>(lsa); break;
case 8: _value = thread->_ref<u64>(lsa); break;
default: fmt::throw_exception("Unreachable");
}
lock.unlock();
ppu.check_state();
*value = _value;
return CELL_OK;
}
@ -1756,6 +1775,7 @@ error_code sys_spu_thread_get_spu_cfg(ppu_thread& ppu, u32 id, vm::ptr<u64> valu
return CELL_ESRCH;
}
ppu.check_state();
*value = thread->snr_config;
return CELL_OK;
@ -2041,7 +2061,7 @@ error_code sys_spu_thread_group_connect_event_all_threads(ppu_thread& ppu, u32 i
return CELL_EINVAL;
}
std::lock_guard lock(group->mutex);
std::unique_lock lock(group->mutex);
if (auto state = +group->run_state;
state < SPU_THREAD_GROUP_STATUS_INITIALIZED || state == SPU_THREAD_GROUP_STATUS_DESTROYED)
@ -2096,6 +2116,9 @@ error_code sys_spu_thread_group_connect_event_all_threads(ppu_thread& ppu, u32 i
}
}
lock.unlock();
ppu.check_state();
*spup = port;
return CELL_OK;
@ -2154,6 +2177,7 @@ error_code sys_spu_thread_group_log(ppu_thread& ppu, s32 command, vm::ptr<s32> s
return CELL_EFAULT;
}
ppu.check_state();
*stat = state.state;
break;
}
@ -2559,6 +2583,7 @@ error_code raw_spu_get_int_control(u32 id, u32 class_id, vm::ptr<u64> value, ato
return CELL_ESRCH;
}
cpu_thread::get_current()->check_state();
*value = thread->int_ctrl[class_id].*control;
return CELL_OK;

View file

@ -163,6 +163,7 @@ error_code sys_timer_create(ppu_thread& ppu, vm::ptr<u32> timer_id)
}
}
ppu.check_state();
*timer_id = idm::last_id();
return CELL_OK;
}
@ -226,6 +227,7 @@ error_code sys_timer_get_information(ppu_thread& ppu, u32 timer_id, vm::ptr<sys_
return CELL_ESRCH;
}
ppu.check_state();
std::memcpy(info.get_ptr(), &_info, info.size());
return CELL_OK;
}

View file

@ -622,11 +622,14 @@ error_code sys_usbd_initialize(ppu_thread& ppu, vm::ptr<u32> handle)
auto& usbh = g_fxo->get<named_thread<usb_handler_thread>>();
std::lock_guard lock(usbh.mutex);
{
std::lock_guard lock(usbh.mutex);
// Must not occur (lv2 allows multiple handles, cellUsbd does not)
ensure(!usbh.is_init.exchange(true));
// Must not occur (lv2 allows multiple handles, cellUsbd does not)
ensure(!usbh.is_init.exchange(true));
}
ppu.check_state();
*handle = 0x115B;
// TODO
@ -891,6 +894,7 @@ error_code sys_usbd_receive_event(ppu_thread& ppu, u32 handle, vm::ptr<u64> arg1
thread_ctrl::wait_on(ppu.state, state);
}
ppu.check_state();
*arg1 = ppu.gpr[4];
*arg2 = ppu.gpr[5];
*arg3 = ppu.gpr[6];

View file

@ -98,6 +98,7 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64
idm::make<sys_vm_t>(area->addr, vsize, ct, psize);
// Write a pointer for the allocated memory
ppu.check_state();
*addr = area->addr;
return CELL_OK;
}
@ -399,6 +400,7 @@ error_code sys_vm_test(ppu_thread& ppu, u32 addr, u32 size, vm::ptr<u64> result)
return CELL_EINVAL;
}
ppu.check_state();
*result = SYS_VM_STATE_ON_MEMORY;
return CELL_OK;
@ -417,6 +419,7 @@ error_code sys_vm_get_statistics(ppu_thread& ppu, u32 addr, vm::ptr<sys_vm_stati
return CELL_EINVAL;
}
ppu.check_state();
stat->page_fault_ppu = 0;
stat->page_fault_spu = 0;
stat->page_in = 0;