2021-06-12 19:06:59 +00:00
|
|
|
#include "ppsspp_config.h"
|
|
|
|
|
2021-06-19 12:54:36 +00:00
|
|
|
#if PPSSPP_PLATFORM(WINDOWS)
|
|
|
|
|
2012-03-27 21:39:13 +00:00
|
|
|
#include <windows.h>
|
2021-06-19 12:54:36 +00:00
|
|
|
|
2017-08-29 20:41:50 +00:00
|
|
|
#ifdef __MINGW32__
|
|
|
|
#include <excpt.h>
|
|
|
|
#endif
|
2021-06-19 12:54:36 +00:00
|
|
|
|
2014-06-29 10:44:07 +00:00
|
|
|
#define TLS_SUPPORTED
|
2021-06-19 12:54:36 +00:00
|
|
|
|
2016-10-12 09:13:16 +00:00
|
|
|
#elif defined(__ANDROID__)
|
2021-06-19 12:54:36 +00:00
|
|
|
|
2023-01-03 18:01:51 +00:00
|
|
|
#include "android/jni/app-android.h"
|
|
|
|
|
2014-06-29 10:44:07 +00:00
|
|
|
#define TLS_SUPPORTED
|
2021-06-19 12:54:36 +00:00
|
|
|
|
2012-03-27 21:39:13 +00:00
|
|
|
#endif
|
2014-06-29 10:44:07 +00:00
|
|
|
|
2023-01-03 18:01:51 +00:00
|
|
|
// TODO: Many other platforms also support TLS, in fact probably nearly all that we support
|
|
|
|
// these days.
|
|
|
|
|
2020-08-15 14:13:24 +00:00
|
|
|
#include <cstring>
|
2020-09-29 10:44:47 +00:00
|
|
|
#include <cstdint>
|
2020-08-15 14:13:24 +00:00
|
|
|
|
|
|
|
#include "Common/Log.h"
|
2020-10-01 07:27:25 +00:00
|
|
|
#include "Common/Thread/ThreadUtil.h"
|
2021-11-13 17:02:36 +00:00
|
|
|
#include "Common/Data/Encoding/Utf8.h"
|
2020-08-15 14:13:24 +00:00
|
|
|
|
2023-01-04 15:07:39 +00:00
|
|
|
AttachDetachFunc g_attach;
|
|
|
|
AttachDetachFunc g_detach;
|
|
|
|
|
|
|
|
void AttachThreadToJNI() {
|
|
|
|
if (g_attach) {
|
|
|
|
g_attach();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DetachThreadFromJNI() {
|
|
|
|
if (g_detach) {
|
|
|
|
g_detach();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void RegisterAttachDetach(AttachDetachFunc attach, AttachDetachFunc detach) {
|
|
|
|
g_attach = attach;
|
|
|
|
g_detach = detach;
|
|
|
|
}
|
|
|
|
|
2021-09-13 15:13:14 +00:00
|
|
|
#if (PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(LINUX)) && !defined(_GNU_SOURCE)
|
2021-06-19 12:54:36 +00:00
|
|
|
#define _GNU_SOURCE
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if !PPSSPP_PLATFORM(WINDOWS)
|
2015-07-19 14:21:24 +00:00
|
|
|
#include <pthread.h>
|
2021-06-12 19:06:59 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/syscall.h>
|
2015-07-19 14:21:24 +00:00
|
|
|
#endif
|
|
|
|
|
2021-08-10 16:37:14 +00:00
|
|
|
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
2021-08-10 16:29:52 +00:00
|
|
|
#include <pthread_np.h>
|
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
#include <lwp.h>
|
|
|
|
#endif
|
|
|
|
|
2014-06-29 10:44:07 +00:00
|
|
|
#ifdef TLS_SUPPORTED
|
2020-09-29 08:28:27 +00:00
|
|
|
static thread_local const char *curThreadName;
|
2014-06-29 10:44:07 +00:00
|
|
|
#endif
|
|
|
|
|
2017-08-31 20:15:05 +00:00
|
|
|
#ifdef __MINGW32__
|
|
|
|
#include <pshpack8.h>
|
|
|
|
typedef struct {
|
|
|
|
DWORD dwType;
|
|
|
|
LPCSTR szName;
|
|
|
|
DWORD dwThreadID;
|
|
|
|
DWORD dwFlags;
|
|
|
|
} THREADNAME_INFO;
|
|
|
|
#include <poppack.h>
|
|
|
|
|
|
|
|
static EXCEPTION_DISPOSITION NTAPI ignore_handler(EXCEPTION_RECORD *rec,
|
|
|
|
void *frame, CONTEXT *ctx,
|
|
|
|
void *disp)
|
|
|
|
{
|
|
|
|
return ExceptionContinueExecution;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2021-11-13 17:40:07 +00:00
|
|
|
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
|
2021-11-13 17:02:36 +00:00
|
|
|
typedef HRESULT (WINAPI *TSetThreadDescription)(HANDLE, PCWSTR);
|
|
|
|
|
|
|
|
static TSetThreadDescription g_pSetThreadDescription = nullptr;
|
|
|
|
static bool g_failedToFindSetThreadDescription = false;
|
|
|
|
|
|
|
|
static void InitializeSetThreadDescription() {
|
|
|
|
if (g_pSetThreadDescription != nullptr || g_failedToFindSetThreadDescription) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
HMODULE hKernel32 = GetModuleHandle(L"kernelbase.dll");
|
|
|
|
if (hKernel32 == nullptr) {
|
|
|
|
// Failed to find the function. Windows version too old, most likely.
|
|
|
|
g_failedToFindSetThreadDescription = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
g_pSetThreadDescription = reinterpret_cast<TSetThreadDescription>(GetProcAddress(hKernel32, "SetThreadDescription"));
|
|
|
|
if (g_pSetThreadDescription == nullptr) {
|
|
|
|
g_failedToFindSetThreadDescription = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetCurrentThreadNameThroughException(const char *threadName);
|
|
|
|
#endif
|
|
|
|
|
2023-01-03 18:01:51 +00:00
|
|
|
const char *GetCurrentThreadName() {
|
|
|
|
#ifdef TLS_SUPPORTED
|
|
|
|
return curThreadName;
|
|
|
|
#else
|
|
|
|
return "";
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetCurrentThreadName(const char *threadName) {
|
2021-11-13 17:40:07 +00:00
|
|
|
#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP)
|
2021-11-13 17:02:36 +00:00
|
|
|
InitializeSetThreadDescription();
|
|
|
|
if (g_pSetThreadDescription) {
|
|
|
|
// Use the modern API
|
|
|
|
wchar_t buffer[256];
|
|
|
|
ConvertUTF8ToWString(buffer, ARRAY_SIZE(buffer), threadName);
|
|
|
|
g_pSetThreadDescription(GetCurrentThread(), buffer);
|
|
|
|
} else {
|
|
|
|
// Use the old exception hack.
|
|
|
|
SetCurrentThreadNameThroughException(threadName);
|
|
|
|
}
|
2021-11-13 17:40:07 +00:00
|
|
|
#elif PPSSPP_PLATFORM(WINDOWS)
|
|
|
|
wchar_t buffer[256];
|
|
|
|
ConvertUTF8ToWString(buffer, ARRAY_SIZE(buffer), threadName);
|
|
|
|
SetThreadDescription(GetCurrentThread(), buffer);
|
2021-11-13 17:02:36 +00:00
|
|
|
#elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(LINUX)
|
|
|
|
pthread_setname_np(pthread_self(), threadName);
|
|
|
|
#elif defined(__APPLE__)
|
|
|
|
pthread_setname_np(threadName);
|
|
|
|
#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
|
|
|
|
pthread_set_name_np(pthread_self(), threadName);
|
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
pthread_setname_np(pthread_self(), "%s", (void*)threadName);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Set the locally known threadname using a thread local variable.
|
|
|
|
#ifdef TLS_SUPPORTED
|
|
|
|
curThreadName = threadName;
|
2017-08-31 20:15:05 +00:00
|
|
|
#endif
|
2021-11-13 17:02:36 +00:00
|
|
|
}
|
2017-08-31 20:15:05 +00:00
|
|
|
|
2021-11-13 17:02:36 +00:00
|
|
|
#if PPSSPP_PLATFORM(WINDOWS)
|
2021-06-12 19:06:59 +00:00
|
|
|
|
2021-11-13 17:02:36 +00:00
|
|
|
void SetCurrentThreadNameThroughException(const char *threadName) {
|
|
|
|
// Set the debugger-visible threadname through an unholy magic hack
|
|
|
|
static const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
|
|
|
|
|
|
|
#if defined(__MINGW32__)
|
2017-08-31 20:15:05 +00:00
|
|
|
// Thread information for VS compatible debugger. -1 sets current thread.
|
|
|
|
THREADNAME_INFO ti;
|
|
|
|
ti.dwType = 0x1000;
|
|
|
|
ti.szName = threadName;
|
|
|
|
ti.dwThreadID = -1;
|
|
|
|
|
|
|
|
// Push an exception handler to ignore all following exceptions
|
|
|
|
NT_TIB *tib = ((NT_TIB*)NtCurrentTeb());
|
|
|
|
EXCEPTION_REGISTRATION_RECORD rec;
|
|
|
|
rec.Next = tib->ExceptionList;
|
|
|
|
rec.Handler = ignore_handler;
|
|
|
|
tib->ExceptionList = &rec;
|
|
|
|
|
|
|
|
// Visual Studio and compatible debuggers receive thread names from the
|
|
|
|
// program through a specially crafted exception
|
|
|
|
RaiseException(MS_VC_EXCEPTION, 0, sizeof(ti) / sizeof(ULONG_PTR),
|
|
|
|
(ULONG_PTR*)&ti);
|
|
|
|
|
|
|
|
// Pop exception handler
|
|
|
|
tib->ExceptionList = tib->ExceptionList->Next;
|
2021-11-13 17:02:36 +00:00
|
|
|
#else
|
2012-03-27 21:39:13 +00:00
|
|
|
#pragma pack(push,8)
|
2014-06-29 10:44:07 +00:00
|
|
|
struct THREADNAME_INFO {
|
2012-03-27 21:39:13 +00:00
|
|
|
DWORD dwType; // must be 0x1000
|
|
|
|
LPCSTR szName; // pointer to name (in user addr space)
|
|
|
|
DWORD dwThreadID; // thread ID (-1=caller thread)
|
|
|
|
DWORD dwFlags; // reserved for future use, must be zero
|
|
|
|
} info;
|
|
|
|
#pragma pack(pop)
|
|
|
|
|
|
|
|
info.dwType = 0x1000;
|
2014-06-29 10:44:07 +00:00
|
|
|
info.szName = threadName;
|
2012-03-27 21:39:13 +00:00
|
|
|
info.dwThreadID = -1; //dwThreadID;
|
|
|
|
info.dwFlags = 0;
|
|
|
|
|
2017-08-29 20:41:50 +00:00
|
|
|
#ifdef __MINGW32__
|
|
|
|
__try1 (ehandler)
|
|
|
|
#else
|
2012-03-27 21:39:13 +00:00
|
|
|
__try
|
2017-08-29 20:41:50 +00:00
|
|
|
#endif
|
2012-03-27 21:39:13 +00:00
|
|
|
{
|
|
|
|
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
|
|
|
}
|
2017-08-29 20:41:50 +00:00
|
|
|
#ifdef __MINGW32__
|
|
|
|
__except1
|
|
|
|
#else
|
2012-03-27 21:39:13 +00:00
|
|
|
__except(EXCEPTION_CONTINUE_EXECUTION)
|
2017-08-29 20:41:50 +00:00
|
|
|
#endif
|
2012-03-27 21:39:13 +00:00
|
|
|
{}
|
2014-06-29 10:44:07 +00:00
|
|
|
#endif
|
|
|
|
}
|
2021-11-13 17:02:36 +00:00
|
|
|
#endif
|
2014-06-29 10:44:07 +00:00
|
|
|
|
|
|
|
void AssertCurrentThreadName(const char *threadName) {
|
|
|
|
#ifdef TLS_SUPPORTED
|
|
|
|
if (strcmp(curThreadName, threadName) != 0) {
|
2020-08-15 14:13:24 +00:00
|
|
|
ERROR_LOG(SYSTEM, "Thread name assert failed: Expected %s, was %s", threadName, curThreadName);
|
2014-06-29 10:44:07 +00:00
|
|
|
}
|
2012-03-27 21:39:13 +00:00
|
|
|
#endif
|
|
|
|
}
|
2021-06-12 19:06:59 +00:00
|
|
|
|
|
|
|
int GetCurrentThreadIdForDebug() {
|
2021-06-14 20:44:27 +00:00
|
|
|
#if __LIBRETRO__
|
|
|
|
// Not sure why gettid() would not be available, but it isn't.
|
|
|
|
// The return value of this function is only used in unit tests anyway...
|
|
|
|
return 1;
|
|
|
|
#elif PPSSPP_PLATFORM(WINDOWS)
|
2021-06-12 19:06:59 +00:00
|
|
|
return (int)GetCurrentThreadId();
|
2021-08-10 16:29:52 +00:00
|
|
|
#elif PPSSPP_PLATFORM(MAC) || PPSSPP_PLATFORM(IOS)
|
2021-06-12 20:42:10 +00:00
|
|
|
uint64_t tid = 0;
|
|
|
|
pthread_threadid_np(NULL, &tid);
|
|
|
|
return (int)tid;
|
2021-06-19 12:54:36 +00:00
|
|
|
#elif PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(LINUX)
|
2021-06-20 23:26:47 +00:00
|
|
|
// See issue 14545
|
|
|
|
return (int)syscall(__NR_gettid);
|
|
|
|
// return (int)gettid();
|
2021-08-10 16:29:52 +00:00
|
|
|
#elif defined(__DragonFly__) || defined(__FreeBSD__)
|
|
|
|
return pthread_getthreadid_np();
|
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
return _lwp_self();
|
|
|
|
#elif defined(__OpenBSD__)
|
|
|
|
return getthrid();
|
2021-06-19 12:54:36 +00:00
|
|
|
#else
|
|
|
|
return 1;
|
2021-06-12 19:06:59 +00:00
|
|
|
#endif
|
|
|
|
}
|