2013-11-03 20:23:16 +01:00
|
|
|
#pragma once
|
2015-07-01 00:25:52 +02:00
|
|
|
|
2016-06-07 22:24:20 +02:00
|
|
|
#include "../Utilities/Thread.h"
|
2016-08-07 21:01:27 +02:00
|
|
|
#include "../Utilities/bit_set.h"
|
2014-08-25 16:56:13 +02:00
|
|
|
|
2016-08-13 16:58:19 +02:00
|
|
|
// Thread state flags
|
2016-08-09 16:14:41 +02:00
|
|
|
enum class cpu_flag : u32
|
2015-03-16 22:38:21 +01:00
|
|
|
{
|
2016-04-14 00:59:00 +02:00
|
|
|
stop, // Thread not running (HLE, initial state)
|
|
|
|
|
exit, // Irreversible exit
|
2019-06-06 20:32:35 +02:00
|
|
|
wait, // Indicates waiting state, set by the thread itself
|
|
|
|
|
pause, // Thread suspended by suspend_all technique
|
2017-02-06 19:36:46 +01:00
|
|
|
suspend, // Thread suspended
|
2016-04-14 00:59:00 +02:00
|
|
|
ret, // Callback return requested
|
|
|
|
|
signal, // Thread received a signal (HLE)
|
2017-03-11 00:14:48 +01:00
|
|
|
memory, // Thread must unlock memory mutex
|
2016-04-14 00:59:00 +02:00
|
|
|
|
|
|
|
|
dbg_global_pause, // Emulation paused
|
|
|
|
|
dbg_global_stop, // Emulation stopped
|
|
|
|
|
dbg_pause, // Thread paused
|
|
|
|
|
dbg_step, // Thread forced to pause after one step (one instruction, etc)
|
2016-08-07 21:01:27 +02:00
|
|
|
|
|
|
|
|
__bitset_enum_max
|
2015-03-16 22:38:21 +01:00
|
|
|
};
|
|
|
|
|
|
2018-10-11 00:17:19 +02:00
|
|
|
class cpu_thread
|
2013-11-03 20:23:16 +01:00
|
|
|
{
|
2018-10-11 00:17:19 +02:00
|
|
|
// PPU cache backward compatibility hack
|
2019-10-14 19:41:31 +02:00
|
|
|
char dummy[sizeof(std::shared_ptr<void>) - 8];
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
u64 block_hash = 0;
|
2018-10-11 00:17:19 +02:00
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
cpu_thread(u32 id);
|
2013-11-05 19:12:18 +01:00
|
|
|
|
2015-07-01 00:25:52 +02:00
|
|
|
public:
|
2018-10-11 00:17:19 +02:00
|
|
|
virtual ~cpu_thread();
|
|
|
|
|
void operator()();
|
2013-11-03 20:23:16 +01:00
|
|
|
|
2018-10-11 00:17:19 +02:00
|
|
|
// Self identifier
|
2017-01-25 18:50:30 +01:00
|
|
|
const u32 id;
|
2016-06-25 15:54:08 +02:00
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
// Public thread state
|
2019-06-06 20:32:35 +02:00
|
|
|
atomic_bs_t<cpu_flag> state{cpu_flag::stop + cpu_flag::wait};
|
2016-04-14 00:59:00 +02:00
|
|
|
|
2016-05-13 16:01:48 +02:00
|
|
|
// Process thread state, return true if the checker must return
|
2019-06-06 20:32:35 +02:00
|
|
|
bool check_state() noexcept;
|
2016-07-27 23:43:22 +02:00
|
|
|
|
2018-10-11 00:17:19 +02:00
|
|
|
// Process thread state (pause)
|
|
|
|
|
[[nodiscard]] bool test_stopped()
|
|
|
|
|
{
|
2019-06-06 20:32:35 +02:00
|
|
|
if (state)
|
2018-10-11 00:17:19 +02:00
|
|
|
{
|
|
|
|
|
if (check_state())
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2017-02-22 11:10:55 +01:00
|
|
|
|
2018-10-11 00:17:19 +02:00
|
|
|
// Test stopped state
|
2019-07-09 19:44:07 +02:00
|
|
|
bool is_stopped() const
|
2018-10-11 00:17:19 +02:00
|
|
|
{
|
2019-10-25 16:20:39 +02:00
|
|
|
return !!(state & (cpu_flag::stop + cpu_flag::exit + cpu_flag::dbg_global_stop));
|
2018-10-11 00:17:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Test paused state
|
2019-07-09 19:44:07 +02:00
|
|
|
bool is_paused() const
|
2018-10-11 00:17:19 +02:00
|
|
|
{
|
|
|
|
|
return !!(state & (cpu_flag::suspend + cpu_flag::dbg_global_pause + cpu_flag::dbg_pause));
|
|
|
|
|
}
|
2016-07-27 23:43:22 +02:00
|
|
|
|
2017-01-25 18:50:30 +01:00
|
|
|
// Check thread type
|
|
|
|
|
u32 id_type()
|
|
|
|
|
{
|
|
|
|
|
return id >> 24;
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-11 00:17:19 +02:00
|
|
|
void notify();
|
|
|
|
|
|
2019-09-08 22:59:08 +02:00
|
|
|
private:
|
|
|
|
|
void abort();
|
|
|
|
|
|
|
|
|
|
public:
|
2017-02-09 23:51:29 +01:00
|
|
|
// Thread stats for external observation
|
|
|
|
|
static atomic_t<u64> g_threads_created, g_threads_deleted;
|
|
|
|
|
|
2018-10-11 00:17:19 +02:00
|
|
|
// Get thread name
|
|
|
|
|
virtual std::string get_name() const = 0;
|
|
|
|
|
|
|
|
|
|
// Get CPU state dump
|
2016-08-13 16:58:19 +02:00
|
|
|
virtual std::string dump() const;
|
|
|
|
|
|
|
|
|
|
// Thread entry point function
|
2016-04-14 00:59:00 +02:00
|
|
|
virtual void cpu_task() = 0;
|
2017-02-06 19:36:46 +01:00
|
|
|
|
|
|
|
|
// Callback for cpu_flag::suspend
|
|
|
|
|
virtual void cpu_sleep() {}
|
2018-04-03 16:19:07 +02:00
|
|
|
|
|
|
|
|
// Callback for cpu_flag::memory
|
|
|
|
|
virtual void cpu_mem() {}
|
|
|
|
|
|
|
|
|
|
// Callback for vm::temporary_unlock
|
|
|
|
|
virtual void cpu_unmem() {}
|
2019-06-06 20:32:35 +02:00
|
|
|
|
|
|
|
|
// Thread locker
|
|
|
|
|
class suspend_all
|
|
|
|
|
{
|
|
|
|
|
cpu_thread* m_this;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
suspend_all(cpu_thread* _this) noexcept;
|
|
|
|
|
suspend_all(const suspend_all&) = delete;
|
|
|
|
|
suspend_all& operator=(const suspend_all&) = delete;
|
|
|
|
|
~suspend_all();
|
|
|
|
|
};
|
2019-08-20 18:07:03 +02:00
|
|
|
|
|
|
|
|
// Stop all threads with cpu_flag::dbg_global_stop
|
|
|
|
|
static void stop_all() noexcept;
|
2019-10-14 19:41:31 +02:00
|
|
|
|
|
|
|
|
// Send signal to the profiler(s) to flush results
|
|
|
|
|
static void flush_profilers() noexcept;
|
2013-11-03 20:23:16 +01:00
|
|
|
};
|
|
|
|
|
|
2016-04-14 00:59:00 +02:00
|
|
|
inline cpu_thread* get_current_cpu_thread() noexcept
|
2015-09-26 22:46:04 +02:00
|
|
|
{
|
2016-04-14 00:59:00 +02:00
|
|
|
extern thread_local cpu_thread* g_tls_current_cpu_thread;
|
2015-09-26 22:46:04 +02:00
|
|
|
|
|
|
|
|
return g_tls_current_cpu_thread;
|
|
|
|
|
}
|
2018-10-11 00:17:19 +02:00
|
|
|
|
|
|
|
|
class ppu_thread;
|
|
|
|
|
class spu_thread;
|