mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-04-25 12:15:32 -06:00
Races and ThreadSafe issues (#4239)
* used atomics for thread safety * equeue: Save filter/ident before std:move since we access them out of the locked loop * fixed kqueues memory leak * clean storage objects effectively * fixed memory leak * fix some races * fixed race condition
This commit is contained in:
parent
36e11fcce5
commit
2c6d41cdd4
@ -77,7 +77,9 @@ private:
|
||||
}
|
||||
|
||||
void Release() {
|
||||
std::destroy_n(storage.get(), used_objects);
|
||||
for (size_t i = 0; i < used_objects; i++) {
|
||||
storage[i].object.~T();
|
||||
}
|
||||
used_objects = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include "common/assert.h"
|
||||
#include "common/spin_lock.h"
|
||||
|
||||
@ -152,6 +153,7 @@ public:
|
||||
}
|
||||
|
||||
void Free(T* obj) {
|
||||
std::destroy_at(obj);
|
||||
BaseHeap::Free(obj);
|
||||
}
|
||||
|
||||
|
||||
@ -303,6 +303,7 @@ File* HandleTable::GetResolver(int d) {
|
||||
}
|
||||
|
||||
File* HandleTable::GetFile(const std::filesystem::path& host_name) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
for (auto* file : m_files) {
|
||||
if (file != nullptr && file->m_host_name == host_name) {
|
||||
return file;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <thread>
|
||||
@ -49,6 +49,10 @@ static void TimerCallback(OrbisKernelEqueue eq, const OrbisKernelEvent& kevent)
|
||||
|
||||
// Events are uniquely identified by id and filter.
|
||||
bool EqueueInternal::AddEvent(EqueueEvent& event) {
|
||||
// Save id and filter before event is moved into m_events.
|
||||
const u64 id = event.event.ident;
|
||||
const auto filter = event.event.filter;
|
||||
|
||||
{
|
||||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
@ -71,8 +75,6 @@ bool EqueueInternal::AddEvent(EqueueEvent& event) {
|
||||
}
|
||||
|
||||
// First, check if there's already an event with the same id and filter.
|
||||
u64 id = event.event.ident;
|
||||
OrbisKernelEvent::Filter filter = event.event.filter;
|
||||
const auto& find_it = std::ranges::find_if(m_events, [id, filter](auto& ev) {
|
||||
return ev.event.ident == id && ev.event.filter == filter;
|
||||
});
|
||||
@ -106,12 +108,10 @@ bool EqueueInternal::AddEvent(EqueueEvent& event) {
|
||||
}
|
||||
|
||||
// Schedule callbacks for timer events
|
||||
if (event.event.filter == OrbisKernelEvent::Timer) {
|
||||
return this->ScheduleEvent(event.event.ident, OrbisKernelEvent::Filter::Timer,
|
||||
TimerCallback);
|
||||
} else if (event.event.filter == OrbisKernelEvent::HrTimer) {
|
||||
return this->ScheduleEvent(event.event.ident, OrbisKernelEvent::Filter::HrTimer,
|
||||
HrTimerCallback);
|
||||
if (filter == OrbisKernelEvent::Filter::Timer) {
|
||||
return this->ScheduleEvent(id, OrbisKernelEvent::Filter::Timer, TimerCallback);
|
||||
} else if (filter == OrbisKernelEvent::Filter::HrTimer) {
|
||||
return this->ScheduleEvent(id, OrbisKernelEvent::Filter::HrTimer, HrTimerCallback);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -454,6 +454,7 @@ int PS4_SYSV_ABI sceKernelDeleteEqueue(OrbisKernelEqueue eq) {
|
||||
|
||||
auto* handles = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||
handles->DeleteHandle(eq);
|
||||
delete kqueues[eq];
|
||||
kqueues.erase(eq);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
@ -30,8 +30,8 @@ static int CondInit(PthreadCondT* cond, const PthreadCondAttrT* cond_attr, const
|
||||
if (name) {
|
||||
cvp->name = name;
|
||||
} else {
|
||||
static int CondId = 0;
|
||||
cvp->name = fmt::format("Cond{}", CondId++);
|
||||
static std::atomic<int> CondId{0};
|
||||
cvp->name = fmt::format("Cond{}", CondId.fetch_add(1));
|
||||
}
|
||||
|
||||
if (cond_attr == nullptr || *cond_attr == nullptr) {
|
||||
|
||||
@ -60,8 +60,8 @@ static s32 MutexInit(PthreadMutexT* mutex, const PthreadMutexAttr* mutex_attr, c
|
||||
if (name) {
|
||||
pmutex->name = name;
|
||||
} else {
|
||||
static s32 MutexId = 0;
|
||||
pmutex->name = fmt::format("Mutex{}", MutexId++);
|
||||
static std::atomic<s32> MutexId{0};
|
||||
pmutex->name = fmt::format("Mutex{}", MutexId.fetch_add(1));
|
||||
}
|
||||
|
||||
pmutex->m_flags = PthreadMutexFlags(attr->m_type);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
@ -78,8 +78,10 @@ Pthread* ThreadState::Alloc(Pthread* curthread) {
|
||||
}
|
||||
if (!free_threads.empty()) {
|
||||
std::scoped_lock lk{free_thread_lock};
|
||||
thread = free_threads.back();
|
||||
free_threads.pop_back();
|
||||
if (!free_threads.empty()) {
|
||||
thread = free_threads.back();
|
||||
free_threads.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (thread == nullptr) {
|
||||
@ -123,9 +125,10 @@ void ThreadState::Free(Pthread* curthread, Pthread* thread) {
|
||||
TcbDtor(thread->tcb);
|
||||
}
|
||||
thread->tcb = nullptr;
|
||||
auto* sleepqueue = thread->sleepqueue;
|
||||
std::destroy_at(thread);
|
||||
if (free_threads.size() >= MaxCachedThreads) {
|
||||
delete thread->sleepqueue;
|
||||
delete sleepqueue;
|
||||
thread_heap.Free(thread);
|
||||
total_threads.fetch_sub(1);
|
||||
} else {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user