The open source OpenXR runtime
at main 303 lines 7.7 kB view raw
1#ifdef _MSC_VER 2# pragma warning(disable:4996) 3#endif 4#if defined _WIN32 5# ifndef WIN32_LEAN_AND_MEAN 6# define WIN32_LEAN_AND_MEAN 7# endif 8# ifndef NOMINMAX 9# define NOMINMAX 10# endif 11# include <windows.h> 12# include <malloc.h> 13# include "TracyUwp.hpp" 14#else 15# include <pthread.h> 16# include <string.h> 17# include <unistd.h> 18#endif 19 20#ifdef __linux__ 21# ifdef __ANDROID__ 22# include <sys/types.h> 23# else 24# include <sys/syscall.h> 25# endif 26# include <fcntl.h> 27#elif defined __FreeBSD__ 28# include <sys/thr.h> 29#elif defined __NetBSD__ || defined __DragonFly__ 30# include <sys/lwp.h> 31#endif 32 33#ifdef __MINGW32__ 34# define __STDC_FORMAT_MACROS 35#endif 36#include <inttypes.h> 37#include <stdio.h> 38#include <stdlib.h> 39 40#include "TracySystem.hpp" 41 42#if defined _WIN32 43extern "C" typedef HRESULT (WINAPI *t_SetThreadDescription)( HANDLE, PCWSTR ); 44extern "C" typedef HRESULT (WINAPI *t_GetThreadDescription)( HANDLE, PWSTR* ); 45#endif 46 47#ifdef TRACY_ENABLE 48# include <atomic> 49# include "TracyAlloc.hpp" 50#endif 51 52namespace tracy 53{ 54 55namespace detail 56{ 57 58TRACY_API uint32_t GetThreadHandleImpl() 59{ 60#if defined _WIN32 61 static_assert( sizeof( decltype( GetCurrentThreadId() ) ) <= sizeof( uint32_t ), "Thread handle too big to fit in protocol" ); 62 return uint32_t( GetCurrentThreadId() ); 63#elif defined __APPLE__ 64 uint64_t id; 65 pthread_threadid_np( pthread_self(), &id ); 66 return uint32_t( id ); 67#elif defined __ANDROID__ 68 return (uint32_t)gettid(); 69#elif defined __linux__ 70 return (uint32_t)syscall( SYS_gettid ); 71#elif defined __FreeBSD__ 72 long id; 73 thr_self( &id ); 74 return id; 75#elif defined __NetBSD__ 76 return _lwp_self(); 77#elif defined __DragonFly__ 78 return lwp_gettid(); 79#elif defined __OpenBSD__ 80 return getthrid(); 81#elif defined __EMSCRIPTEN__ 82 // Not supported, but let it compile. 83 return 0; 84#else 85 // To add support for a platform, retrieve and return the kernel thread identifier here. 86 // 87 // Note that pthread_t (as for example returned by pthread_self()) is *not* a kernel 88 // thread identifier. It is a pointer to a library-allocated data structure instead. 89 // Such pointers will be reused heavily, making the pthread_t non-unique. Additionally 90 // a 64-bit pointer cannot be reliably truncated to 32 bits. 91 #error "Unsupported platform!" 92#endif 93 94} 95 96} 97 98#ifdef TRACY_ENABLE 99struct ThreadNameData 100{ 101 uint32_t id; 102 const char* name; 103 ThreadNameData* next; 104}; 105std::atomic<ThreadNameData*>& GetThreadNameData(); 106#endif 107 108#ifdef _MSC_VER 109# pragma pack( push, 8 ) 110struct THREADNAME_INFO 111{ 112 DWORD dwType; 113 LPCSTR szName; 114 DWORD dwThreadID; 115 DWORD dwFlags; 116}; 117# pragma pack( pop ) 118 119void ThreadNameMsvcMagic( const THREADNAME_INFO& info ) 120{ 121 __try 122 { 123 RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info ); 124 } 125 __except(EXCEPTION_EXECUTE_HANDLER) 126 { 127 } 128} 129#endif 130 131TRACY_API void SetThreadName( const char* name ) 132{ 133#if defined _WIN32 134# ifdef TRACY_UWP 135 static auto _SetThreadDescription = &::SetThreadDescription; 136# else 137 static auto _SetThreadDescription = (t_SetThreadDescription)GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "SetThreadDescription" ); 138# endif 139 if( _SetThreadDescription ) 140 { 141 wchar_t buf[256]; 142 mbstowcs( buf, name, 256 ); 143 _SetThreadDescription( GetCurrentThread(), buf ); 144 } 145 else 146 { 147# if defined _MSC_VER 148 THREADNAME_INFO info; 149 info.dwType = 0x1000; 150 info.szName = name; 151 info.dwThreadID = GetCurrentThreadId(); 152 info.dwFlags = 0; 153 ThreadNameMsvcMagic( info ); 154# endif 155 } 156#elif defined _GNU_SOURCE && !defined __EMSCRIPTEN__ 157 { 158 const auto sz = strlen( name ); 159 if( sz <= 15 ) 160 { 161#if defined __APPLE__ 162 pthread_setname_np( name ); 163#else 164 pthread_setname_np( pthread_self(), name ); 165#endif 166 } 167 else 168 { 169 char buf[16]; 170 memcpy( buf, name, 15 ); 171 buf[15] = '\0'; 172#if defined __APPLE__ 173 pthread_setname_np( buf ); 174#else 175 pthread_setname_np( pthread_self(), buf ); 176#endif 177 } 178 } 179#endif 180#ifdef TRACY_ENABLE 181 { 182 const auto sz = strlen( name ); 183 char* buf = (char*)tracy_malloc( sz+1 ); 184 memcpy( buf, name, sz ); 185 buf[sz] = '\0'; 186 auto data = (ThreadNameData*)tracy_malloc_fast( sizeof( ThreadNameData ) ); 187 data->id = detail::GetThreadHandleImpl(); 188 data->name = buf; 189 data->next = GetThreadNameData().load( std::memory_order_relaxed ); 190 while( !GetThreadNameData().compare_exchange_weak( data->next, data, std::memory_order_release, std::memory_order_relaxed ) ) {} 191 } 192#endif 193} 194 195TRACY_API const char* GetThreadName( uint32_t id ) 196{ 197 static char buf[256]; 198#ifdef TRACY_ENABLE 199 auto ptr = GetThreadNameData().load( std::memory_order_relaxed ); 200 while( ptr ) 201 { 202 if( ptr->id == id ) 203 { 204 return ptr->name; 205 } 206 ptr = ptr->next; 207 } 208#endif 209 210#if defined _WIN32 211# ifdef TRACY_UWP 212 static auto _GetThreadDescription = &::GetThreadDescription; 213# else 214 static auto _GetThreadDescription = (t_GetThreadDescription)GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "GetThreadDescription" ); 215# endif 216 if( _GetThreadDescription ) 217 { 218 auto hnd = OpenThread( THREAD_QUERY_LIMITED_INFORMATION, FALSE, (DWORD)id ); 219 if( hnd != 0 ) 220 { 221 PWSTR tmp; 222 _GetThreadDescription( hnd, &tmp ); 223 auto ret = wcstombs( buf, tmp, 256 ); 224 CloseHandle( hnd ); 225 if( ret != 0 ) 226 { 227 return buf; 228 } 229 } 230 } 231#elif defined __linux__ 232 int cs, fd; 233 char path[32]; 234 snprintf( path, sizeof( path ), "/proc/self/task/%d/comm", id ); 235 sprintf( buf, "%" PRIu32, id ); 236# ifndef __ANDROID__ 237 pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &cs ); 238# endif 239 if ( ( fd = open( path, O_RDONLY ) ) > 0) { 240 int len = read( fd, buf, 255 ); 241 if( len > 0 ) 242 { 243 buf[len] = 0; 244 if( len > 1 && buf[len-1] == '\n' ) 245 { 246 buf[len-1] = 0; 247 } 248 } 249 close( fd ); 250 } 251# ifndef __ANDROID__ 252 pthread_setcancelstate( cs, 0 ); 253# endif 254 return buf; 255#endif 256 257 sprintf( buf, "%" PRIu32, id ); 258 return buf; 259} 260 261TRACY_API const char* GetEnvVar( const char* name ) 262{ 263#if defined _WIN32 264 // unfortunately getenv() on Windows is just fundamentally broken. It caches the entire 265 // environment block once on startup, then never refreshes it again. If any environment 266 // strings are added or modified after startup of the CRT, those changes will not be 267 // seen by getenv(). This removes the possibility of an app using this SDK from 268 // programmatically setting any of the behaviour controlling envvars here. 269 // 270 // To work around this, we'll instead go directly to the Win32 environment strings APIs 271 // to get the current value. 272 static char buffer[1024]; 273 DWORD const kBufferSize = DWORD(sizeof(buffer) / sizeof(buffer[0])); 274 DWORD count = GetEnvironmentVariableA(name, buffer, kBufferSize); 275 276 if( count == 0 ) 277 return nullptr; 278 279 if( count >= kBufferSize ) 280 { 281 char* buf = reinterpret_cast<char*>(_alloca(count + 1)); 282 count = GetEnvironmentVariableA(name, buf, count + 1); 283 memcpy(buffer, buf, kBufferSize); 284 buffer[kBufferSize - 1] = 0; 285 } 286 287 return buffer; 288#else 289 return getenv(name); 290#endif 291} 292 293} 294 295#ifdef __cplusplus 296extern "C" { 297#endif 298 299TRACY_API void ___tracy_set_thread_name( const char* name ) { tracy::SetThreadName( name ); } 300 301#ifdef __cplusplus 302} 303#endif