mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-11-21 18:22:33 +01:00
Implement simple thread pool
This commit is contained in:
parent
50d80c64fa
commit
67785a918c
@ -1842,8 +1842,68 @@ thread_local DECLARE(thread_ctrl::g_tls_error_callback) = nullptr;
|
||||
|
||||
DECLARE(thread_ctrl::g_native_core_layout) { native_core_arrangement::undefined };
|
||||
|
||||
static lf_fifo<atomic_t<thread_base**>, 240> s_thread_pool;
|
||||
|
||||
static shared_mutex s_pool_lock;
|
||||
|
||||
void thread_base::start(native_entry entry)
|
||||
{
|
||||
while (u32 size = s_thread_pool.size())
|
||||
{
|
||||
u32 pos = s_thread_pool.peek();
|
||||
thread_base** tls = nullptr;
|
||||
|
||||
for (u32 i = pos; i < pos + size; i++)
|
||||
{
|
||||
auto val = s_thread_pool[i].load();
|
||||
|
||||
if (val && s_thread_pool[i].compare_and_swap_test(val, 0))
|
||||
{
|
||||
tls = val;
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tls)
|
||||
{
|
||||
// Send "this" and entry point
|
||||
m_thread = reinterpret_cast<u64>(entry);
|
||||
atomic_storage<thread_base*>::store(*tls, this);
|
||||
s_thread_pool[pos].notify_one();
|
||||
|
||||
{
|
||||
// Using it in MPMC manner is a bit tricky, since it's originally MPSC
|
||||
std::lock_guard lock(s_pool_lock);
|
||||
|
||||
u32 count = 0;
|
||||
|
||||
while (!s_thread_pool[s_thread_pool.peek() + count])
|
||||
{
|
||||
count++;
|
||||
|
||||
if (count >= s_thread_pool.size())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (count)
|
||||
{
|
||||
s_thread_pool.pop_end(count);
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for actual "m_thread" in return
|
||||
while (m_thread == reinterpret_cast<u64>(entry))
|
||||
{
|
||||
busy_wait(300);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
m_thread = ::_beginthreadex(nullptr, 0, entry, this, CREATE_SUSPENDED, nullptr);
|
||||
verify("thread_ctrl::start" HERE), m_thread, ::ResumeThread(reinterpret_cast<HANDLE>(+m_thread)) != -1;
|
||||
@ -1867,8 +1927,11 @@ void thread_base::initialize(void (*error_cb)(), bool(*wait_cb)(const void*))
|
||||
return thread_ctrl::get_name_cached();
|
||||
};
|
||||
|
||||
std::string name = thread_ctrl::get_name_cached();
|
||||
set_name(thread_ctrl::get_name_cached());
|
||||
}
|
||||
|
||||
void thread_base::set_name(std::string name)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
struct THREADNAME_INFO
|
||||
{
|
||||
@ -1983,11 +2046,34 @@ bool thread_base::finalize(thread_state result_state) noexcept
|
||||
return !ok;
|
||||
}
|
||||
|
||||
void thread_base::finalize() noexcept
|
||||
void thread_base::finalize(u64 _self) noexcept
|
||||
{
|
||||
if (!_self)
|
||||
{
|
||||
// Don't even need to clean these values for detached threads
|
||||
return;
|
||||
}
|
||||
|
||||
atomic_wait_engine::set_wait_callback(nullptr);
|
||||
g_tls_log_prefix = []() -> std::string { return {}; };
|
||||
set_name("..pool");
|
||||
thread_ctrl::g_tls_this_thread = nullptr;
|
||||
|
||||
// Try to add self to thread pool
|
||||
const u32 pos = s_thread_pool.push_begin();
|
||||
const auto tls = &thread_ctrl::g_tls_this_thread;
|
||||
s_thread_pool[pos] = tls;
|
||||
|
||||
while (s_thread_pool[pos] == tls || !atomic_storage<thread_base*>::load(thread_ctrl::g_tls_this_thread))
|
||||
{
|
||||
s_thread_pool[pos].wait(tls);
|
||||
}
|
||||
|
||||
// Restore thread id
|
||||
const auto _this = thread_ctrl::g_tls_this_thread;
|
||||
const auto entry = _this->m_thread.exchange(_self);
|
||||
_this->m_thread.notify_one();
|
||||
reinterpret_cast<native_entry>(entry)(_this);
|
||||
}
|
||||
|
||||
void thread_ctrl::_wait_for(u64 usec, bool alert /* true */)
|
||||
@ -2073,14 +2159,6 @@ thread_base::thread_base(std::string_view name)
|
||||
|
||||
thread_base::~thread_base()
|
||||
{
|
||||
if (m_thread)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
CloseHandle(reinterpret_cast<HANDLE>(m_thread.raw()));
|
||||
#else
|
||||
pthread_detach(reinterpret_cast<pthread_t>(m_thread.raw()));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool thread_base::join() const
|
||||
@ -2169,7 +2247,7 @@ void thread_ctrl::emergency_exit(std::string_view reason)
|
||||
delete _this;
|
||||
}
|
||||
|
||||
thread_base::finalize();
|
||||
thread_base::finalize(0);
|
||||
|
||||
#ifdef _WIN32
|
||||
_endthreadex(0);
|
||||
|
@ -91,6 +91,7 @@ struct thread_thread_name<T, std::void_t<decltype(named_thread<T>::thread_name)>
|
||||
// Thread base class
|
||||
class thread_base
|
||||
{
|
||||
public:
|
||||
// Native thread entry point function type
|
||||
#ifdef _WIN32
|
||||
using native_entry = uint(__stdcall*)(void* arg);
|
||||
@ -98,6 +99,7 @@ class thread_base
|
||||
using native_entry = void*(*)(void* arg);
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Thread handle (platform-specific)
|
||||
atomic_t<std::uintptr_t> m_thread{0};
|
||||
|
||||
@ -129,7 +131,10 @@ class thread_base
|
||||
bool finalize(thread_state result) noexcept;
|
||||
|
||||
// Cleanup after possibly deleting the thread instance
|
||||
static void finalize() noexcept;
|
||||
static void finalize(u64 _self) noexcept;
|
||||
|
||||
// Set name for debugger
|
||||
static void set_name(std::string);
|
||||
|
||||
friend class thread_ctrl;
|
||||
|
||||
@ -287,9 +292,11 @@ class named_thread final : public Context, result_storage_t<Context>, thread_bas
|
||||
if (_this->entry_point())
|
||||
{
|
||||
delete _this;
|
||||
thread::finalize(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
thread::finalize();
|
||||
thread::finalize(_this->thread::m_thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -324,6 +324,12 @@ struct cpu_counter
|
||||
// Unregister and wait if necessary
|
||||
_this->state += cpu_flag::wait;
|
||||
|
||||
if (slot >= std::size(cpu_array))
|
||||
{
|
||||
sys_log.fatal("Index out of bounds (%u)." HERE, slot);
|
||||
return;
|
||||
}
|
||||
|
||||
std::lock_guard lock(cpu_suspend_lock);
|
||||
|
||||
if (!cpu_array[slot].compare_and_swap_test(_this, nullptr))
|
||||
@ -344,7 +350,7 @@ struct cpu_counter
|
||||
|
||||
if (index >= std::size(cpu_array))
|
||||
{
|
||||
sys_log.fatal("Index out of bounds (%u).", index);
|
||||
sys_log.fatal("Index out of bounds (%u)." HERE, index);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -493,15 +499,9 @@ void cpu_thread::operator()()
|
||||
|
||||
static thread_local struct thread_cleanup_t
|
||||
{
|
||||
cpu_thread* _this;
|
||||
cpu_thread* _this = nullptr;
|
||||
std::string name;
|
||||
|
||||
thread_cleanup_t(cpu_thread* _this)
|
||||
: _this(_this)
|
||||
, name(thread_ctrl::get_name())
|
||||
{
|
||||
}
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
if (_this == nullptr)
|
||||
@ -520,6 +520,8 @@ void cpu_thread::operator()()
|
||||
|
||||
g_fxo->get<cpu_counter>()->remove(_this, s_tls_thread_slot);
|
||||
|
||||
s_tls_thread_slot = -1;
|
||||
|
||||
_this = nullptr;
|
||||
}
|
||||
|
||||
@ -531,7 +533,10 @@ void cpu_thread::operator()()
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
} cleanup{this};
|
||||
} cleanup;
|
||||
|
||||
cleanup._this = this;
|
||||
cleanup.name = thread_ctrl::get_name();
|
||||
|
||||
// Check thread status
|
||||
while (!(state & (cpu_flag::exit + cpu_flag::dbg_global_stop)) && thread_ctrl::state() != thread_state::aborting)
|
||||
|
Loading…
Reference in New Issue
Block a user