#if defined _MSC_VER || defined __CYGWIN__ || defined _WIN32 # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN # endif # ifndef NOMINMAX # define NOMINMAX # endif #endif #ifdef _MSC_VER # pragma warning(disable:4996) #endif #if defined _WIN32 || defined __CYGWIN__ # include # include #else # include # include # include #endif #ifdef __linux__ # ifdef __ANDROID__ # include # else # include # endif # include #elif defined __FreeBSD__ # include #elif defined __NetBSD__ || defined __DragonFly__ # include #endif #ifdef __MINGW32__ # define __STDC_FORMAT_MACROS #endif #include #include #include #include "TracySystem.hpp" #if defined _WIN32 || defined __CYGWIN__ extern "C" typedef HRESULT (WINAPI *t_SetThreadDescription)( HANDLE, PCWSTR ); extern "C" typedef HRESULT (WINAPI *t_GetThreadDescription)( HANDLE, PWSTR* ); #endif #ifdef TRACY_ENABLE # include # include "TracyAlloc.hpp" #endif namespace tracy { namespace detail { TRACY_API uint64_t GetThreadHandleImpl() { #if defined _WIN32 || defined __CYGWIN__ static_assert( sizeof( decltype( GetCurrentThreadId() ) ) <= sizeof( uint64_t ), "Thread handle too big to fit in protocol" ); return uint64_t( GetCurrentThreadId() ); #elif defined __APPLE__ uint64_t id; pthread_threadid_np( pthread_self(), &id ); return id; #elif defined __ANDROID__ return (uint64_t)gettid(); #elif defined __linux__ return (uint64_t)syscall( SYS_gettid ); #elif defined __FreeBSD__ long id; thr_self( &id ); return id; #elif defined __NetBSD__ return _lwp_self(); #elif defined __DragonFly__ return lwp_gettid(); #elif defined __OpenBSD__ return getthrid(); #else static_assert( sizeof( decltype( pthread_self() ) ) <= sizeof( uint64_t ), "Thread handle too big to fit in protocol" ); return uint64_t( pthread_self() ); #endif } } #ifdef TRACY_ENABLE struct ThreadNameData { uint64_t id; const char* name; ThreadNameData* next; }; std::atomic& GetThreadNameData(); TRACY_API void InitRPMallocThread(); #endif #ifdef _MSC_VER # pragma pack( push, 8 ) struct THREADNAME_INFO { DWORD dwType; LPCSTR szName; DWORD dwThreadID; DWORD dwFlags; }; # pragma pack(pop) void ThreadNameMsvcMagic( const THREADNAME_INFO& info ) { __try { RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info ); } __except(EXCEPTION_EXECUTE_HANDLER) { } } #endif TRACY_API void SetThreadName( const char* name ) { #if defined _WIN32 || defined __CYGWIN__ static auto _SetThreadDescription = (t_SetThreadDescription)GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "SetThreadDescription" ); if( _SetThreadDescription ) { wchar_t buf[256]; mbstowcs( buf, name, 256 ); _SetThreadDescription( GetCurrentThread(), buf ); } else { # if defined _MSC_VER THREADNAME_INFO info; info.dwType = 0x1000; info.szName = name; info.dwThreadID = GetCurrentThreadId(); info.dwFlags = 0; ThreadNameMsvcMagic( info ); # endif } #elif defined _GNU_SOURCE && !defined __EMSCRIPTEN__ && !defined __CYGWIN__ { const auto sz = strlen( name ); if( sz <= 15 ) { pthread_setname_np( pthread_self(), name ); } else { char buf[16]; memcpy( buf, name, 15 ); buf[15] = '\0'; pthread_setname_np( pthread_self(), buf ); } } #endif #ifdef TRACY_ENABLE { InitRPMallocThread(); const auto sz = strlen( name ); char* buf = (char*)tracy_malloc( sz+1 ); memcpy( buf, name, sz ); buf[sz] = '\0'; auto data = (ThreadNameData*)tracy_malloc( sizeof( ThreadNameData ) ); data->id = detail::GetThreadHandleImpl(); data->name = buf; data->next = GetThreadNameData().load( std::memory_order_relaxed ); while( !GetThreadNameData().compare_exchange_weak( data->next, data, std::memory_order_release, std::memory_order_relaxed ) ) {} } #endif } TRACY_API const char* GetThreadName( uint64_t id ) { static char buf[256]; #ifdef TRACY_ENABLE auto ptr = GetThreadNameData().load( std::memory_order_relaxed ); while( ptr ) { if( ptr->id == id ) { return ptr->name; } ptr = ptr->next; } #else # if defined _WIN32 || defined __CYGWIN__ static auto _GetThreadDescription = (t_GetThreadDescription)GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "GetThreadDescription" ); if( _GetThreadDescription ) { auto hnd = OpenThread( THREAD_QUERY_LIMITED_INFORMATION, FALSE, (DWORD)id ); if( hnd != 0 ) { PWSTR tmp; _GetThreadDescription( hnd, &tmp ); auto ret = wcstombs( buf, tmp, 256 ); CloseHandle( hnd ); if( ret != 0 ) { return buf; } } } # elif defined __linux__ int cs, fd; char path[32]; # ifdef __ANDROID__ int tid = gettid(); # else int tid = (int) syscall( SYS_gettid ); # endif snprintf( path, sizeof( path ), "/proc/self/task/%d/comm", tid ); sprintf( buf, "%" PRIu64, id ); # ifndef __ANDROID__ pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, &cs ); # endif if ( ( fd = open( path, O_RDONLY ) ) > 0) { int len = read( fd, buf, 255 ); if( len > 0 ) { buf[len] = 0; if( len > 1 && buf[len-1] == '\n' ) { buf[len-1] = 0; } } close( fd ); } # ifndef __ANDROID__ pthread_setcancelstate( cs, 0 ); # endif return buf; # endif #endif sprintf( buf, "%" PRIu64, id ); return buf; } TRACY_API const char* GetEnvVar( const char* name ) { #if defined _WIN32 || defined __CYGWIN__ // unfortunately getenv() on Windows is just fundamentally broken. It caches the entire // environment block once on startup, then never refreshes it again. If any environment // strings are added or modified after startup of the CRT, those changes will not be // seen by getenv(). This removes the possibility of an app using this SDK from // programmatically setting any of the behaviour controlling envvars here. // // To work around this, we'll instead go directly to the Win32 environment strings APIs // to get the current value. static char buffer[1024]; DWORD const kBufferSize = DWORD(sizeof(buffer) / sizeof(buffer[0])); DWORD count = GetEnvironmentVariableA(name, buffer, kBufferSize); if( count == 0 ) return nullptr; if( count >= kBufferSize ) { char* buf = reinterpret_cast(_alloca(count + 1)); count = GetEnvironmentVariableA(name, buf, count + 1); memcpy(buffer, buf, kBufferSize); buffer[kBufferSize - 1] = 0; } return buffer; #else return getenv(name); #endif } } #ifdef __cplusplus extern "C" { #endif TRACY_API void ___tracy_set_thread_name( const char* name ) { tracy::SetThreadName( name ); } #ifdef __cplusplus } #endif