Threading: Add ThreadHandle class

This commit is contained in:
Connor McLaughlin 2022-05-02 16:01:44 +10:00 committed by refractionpcsx2
parent 5eae7a6328
commit 6ebb8c2e91
4 changed files with 267 additions and 0 deletions

View File

@ -94,6 +94,52 @@ u64 Threading::GetThreadCpuTime()
return us;
}
Threading::ThreadHandle::ThreadHandle() = default;
Threading::ThreadHandle::ThreadHandle(const ThreadHandle& handle)
: m_native_handle(handle.m_native_handle)
{
}
Threading::ThreadHandle::ThreadHandle(ThreadHandle&& handle)
: m_native_handle(handle.m_native_handle)
{
handle.m_native_handle = nullptr;
}
Threading::ThreadHandle::~ThreadHandle() = default;
Threading::ThreadHandle Threading::ThreadHandle::GetForCallingThread()
{
ThreadHandle ret;
ret.m_native_handle = pthread_self();
return ret;
}
Threading::ThreadHandle& Threading::ThreadHandle::operator=(ThreadHandle&& handle)
{
m_native_handle = handle.m_native_handle;
handle.m_native_handle = nullptr;
return *this;
}
Threading::ThreadHandle& Threading::ThreadHandle::operator=(const ThreadHandle& handle)
{
m_native_handle = handle.m_native_handle;
return *this;
}
u64 Threading::ThreadHandle::GetCPUTime() const
{
return getthreadtime(pthread_mach_thread_np((pthread_t)m_native_handle));
}
bool Threading::ThreadHandle::SetAffinity(u64 processor_mask) const
{
// Doesn't appear to be possible to set affinity.
return false;
}
u64 Threading::pxThread::GetCpuTime() const
{
// Get the cpu time for the thread belonging to this object. Use m_native_id and/or

View File

@ -14,9 +14,22 @@
*/
#if !defined(_WIN32) && !defined(__APPLE__)
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <unistd.h>
#if defined(__linux__)
#include <sys/prctl.h>
#include <sys/types.h>
#include <sched.h>
// glibc < v2.30 doesn't define gettid...
#if __GLIBC__ == 2 && __GLIBC_MINOR__ < 30
#include <sys/syscall.h>
#define gettid() syscall(SYS_gettid)
#endif
#elif defined(__unix__)
#include <pthread_np.h>
#endif
@ -96,6 +109,96 @@ u64 Threading::GetThreadCpuTime()
return get_thread_time();
}
Threading::ThreadHandle::ThreadHandle() = default;
Threading::ThreadHandle::ThreadHandle(const ThreadHandle& handle)
: m_native_handle(handle.m_native_handle)
#ifdef __linux__
, m_native_id(handle.m_native_id)
#endif
{
}
Threading::ThreadHandle::ThreadHandle(ThreadHandle&& handle)
: m_native_handle(handle.m_native_handle)
#ifdef __linux__
, m_native_id(handle.m_native_id)
#endif
{
handle.m_native_handle = nullptr;
#ifdef __linux__
handle.m_native_id = 0;
#endif
}
Threading::ThreadHandle::~ThreadHandle() = default;
Threading::ThreadHandle Threading::ThreadHandle::GetForCallingThread()
{
ThreadHandle ret;
ret.m_native_handle = (void*)pthread_self();
#ifdef __linux__
ret.m_native_id = gettid();
#endif
return ret;
}
Threading::ThreadHandle& Threading::ThreadHandle::operator=(ThreadHandle&& handle)
{
m_native_handle = handle.m_native_handle;
handle.m_native_handle = nullptr;
#ifdef __linux__
m_native_id = handle.m_native_id;
handle.m_native_id = 0;
#endif
return *this;
}
Threading::ThreadHandle& Threading::ThreadHandle::operator=(const ThreadHandle& handle)
{
m_native_handle = handle.m_native_handle;
#ifdef __linux__
m_native_id = handle.m_native_id;
#endif
return *this;
}
u64 Threading::ThreadHandle::GetCPUTime() const
{
return m_native_handle ? get_thread_time((uptr)m_native_handle) : 0;
}
bool Threading::ThreadHandle::SetAffinity(u64 processor_mask) const
{
#if defined(__linux__)
cpu_set_t set;
CPU_ZERO(&set);
if (processor_mask != 0)
{
for (u32 i = 0; i < 64; i++)
{
if (processor_mask & (static_cast<u64>(1) << i))
{
CPU_SET(i, &set);
}
}
}
else
{
long num_processors = sysconf(_SC_NPROCESSORS_CONF);
for (long i = 0; i < num_processors; i++)
{
CPU_SET(i, &set);
}
}
return sched_setaffinity((pid_t)m_native_id, sizeof(set), &set) >= 0;
#else
return false;
#endif
}
u64 Threading::pxThread::GetCpuTime() const
{
// Get the cpu time for the thread belonging to this object. Use m_native_id and/or

View File

@ -90,6 +90,7 @@ class wxTimeSpan;
namespace Threading
{
class ThreadHandle;
class pxThread;
class RwMutex;
@ -198,6 +199,45 @@ namespace Threading
};
#endif
// --------------------------------------------------------------------------------------
// ThreadHandle
// --------------------------------------------------------------------------------------
// Abstracts an OS's handle to a thread, closing the handle when necessary. Currently,
// only used for getting the CPU time for a thread.
//
class ThreadHandle
{
public:
ThreadHandle();
ThreadHandle(ThreadHandle&& handle);
ThreadHandle(const ThreadHandle& handle);
~ThreadHandle();
/// Returns a new handle for the calling thread.
static ThreadHandle GetForCallingThread();
ThreadHandle& operator=(ThreadHandle&& handle);
ThreadHandle& operator=(const ThreadHandle& handle);
operator void*() const { return m_native_handle; }
operator bool() const { return (m_native_handle != nullptr); }
/// Returns the amount of CPU time consumed by the thread, at the GetThreadTicksPerSecond() frequency.
u64 GetCPUTime() const;
/// Sets the affinity for a thread to the specified processors.
/// Obviously, only works up to 64 processors.
bool SetAffinity(u64 processor_mask) const;
private:
void* m_native_handle = nullptr;
// We need the thread ID for affinity adjustments on Linux.
#if defined(__linux__)
unsigned int m_native_id = 0;
#endif
};
// --------------------------------------------------------------------------------------
// NonblockingMutex
// --------------------------------------------------------------------------------------

View File

@ -47,6 +47,84 @@ __fi void Threading::DisableHiresScheduler()
timeEndPeriod(1);
}
Threading::ThreadHandle::ThreadHandle() = default;
Threading::ThreadHandle::ThreadHandle(const ThreadHandle& handle)
{
if (handle.m_native_handle)
{
HANDLE new_handle;
if (DuplicateHandle(GetCurrentProcess(), (HANDLE)handle.m_native_handle,
GetCurrentProcess(), &new_handle, THREAD_QUERY_INFORMATION | THREAD_SET_LIMITED_INFORMATION, FALSE, 0))
{
m_native_handle = (void*)new_handle;
}
}
}
Threading::ThreadHandle::ThreadHandle(ThreadHandle&& handle)
: m_native_handle(handle.m_native_handle)
{
handle.m_native_handle = nullptr;
}
Threading::ThreadHandle::~ThreadHandle()
{
if (m_native_handle)
CloseHandle(m_native_handle);
}
Threading::ThreadHandle Threading::ThreadHandle::GetForCallingThread()
{
ThreadHandle ret;
ret.m_native_handle = (void*)OpenThread(THREAD_QUERY_INFORMATION | THREAD_SET_LIMITED_INFORMATION, FALSE, GetCurrentThreadId());
return ret;
}
Threading::ThreadHandle& Threading::ThreadHandle::operator=(ThreadHandle&& handle)
{
if (m_native_handle)
CloseHandle((HANDLE)m_native_handle);
m_native_handle = handle.m_native_handle;
handle.m_native_handle = nullptr;
return *this;
}
Threading::ThreadHandle& Threading::ThreadHandle::operator=(const ThreadHandle& handle)
{
if (m_native_handle)
{
CloseHandle((HANDLE)m_native_handle);
m_native_handle = nullptr;
}
HANDLE new_handle;
if (DuplicateHandle(GetCurrentProcess(), (HANDLE)handle.m_native_handle,
GetCurrentProcess(), &new_handle, THREAD_QUERY_INFORMATION | THREAD_SET_LIMITED_INFORMATION, FALSE, 0))
{
m_native_handle = (void*)new_handle;
}
return *this;
}
u64 Threading::ThreadHandle::GetCPUTime() const
{
u64 ret = 0;
if (m_native_handle)
QueryThreadCycleTime((HANDLE)m_native_handle, &ret);
return ret;
}
bool Threading::ThreadHandle::SetAffinity(u64 processor_mask) const
{
if (processor_mask == 0)
processor_mask = ~processor_mask;
return (SetThreadAffinityMask(GetCurrentThread(), (DWORD_PTR)processor_mask) != 0 || GetLastError() != ERROR_SUCCESS);
}
u64 Threading::GetThreadCpuTime()
{
u64 ret = 0;