From 112ef3d680c50ae3c64d7c129b658d9cd00a5a3d Mon Sep 17 00:00:00 2001 From: Adeel Mujahid <3840695+am11@users.noreply.github.com> Date: Sun, 6 Oct 2024 08:37:48 +0300 Subject: [PATCH] Share pthread_setname via minipal (#108370) --- src/coreclr/gc/unix/gcenv.unix.cpp | 14 +- .../nativeaot/Runtime/eventpipe/ep-rt-aot.cpp | 5 +- .../nativeaot/Runtime/unix/PalCreateDump.cpp | 28 +--- .../nativeaot/Runtime/unix/PalRedhawkUnix.cpp | 34 ++-- src/coreclr/pal/src/include/pal/thread.hpp | 63 +------ src/coreclr/pal/src/misc/perfjitdump.cpp | 2 +- src/coreclr/pal/src/synchmgr/synchmanager.cpp | 4 +- src/coreclr/pal/src/thread/thread.cpp | 157 ++++-------------- src/mono/mono/utils/mono-threads-mach.c | 3 +- src/mono/mono/utils/mono-threads-posix.c | 62 +------ src/native/libs/System.Native/pal_signal.c | 16 +- src/native/libs/System.Native/pal_threading.c | 41 +---- src/native/minipal/getexepath.h | 9 +- src/native/minipal/thread.h | 118 +++++++++++++ 14 files changed, 201 insertions(+), 355 deletions(-) create mode 100644 src/native/minipal/thread.h diff --git a/src/coreclr/gc/unix/gcenv.unix.cpp b/src/coreclr/gc/unix/gcenv.unix.cpp index 879397c4493c4..06e6e9ae5a86d 100644 --- a/src/coreclr/gc/unix/gcenv.unix.cpp +++ b/src/coreclr/gc/unix/gcenv.unix.cpp @@ -21,6 +21,7 @@ #include "gcenv.unix.inl" #include "volatile.h" #include "numasupport.h" +#include #if HAVE_SWAPCTL #include @@ -389,18 +390,7 @@ void GCToOSInterface::Shutdown() // Numeric id of the current thread, as best we can retrieve it. uint64_t GCToOSInterface::GetCurrentThreadIdForLogging() { -#if defined(__linux__) - return (uint64_t)syscall(SYS_gettid); -#elif HAVE_PTHREAD_GETTHREADID_NP - return (uint64_t)pthread_getthreadid_np(); -#elif HAVE_PTHREAD_THREADID_NP - unsigned long long tid; - pthread_threadid_np(pthread_self(), &tid); - return (uint64_t)tid; -#else - // Fallback in case we don't know how to get integer thread id on the current platform - return (uint64_t)pthread_self(); -#endif + return (uint64_t)minipal_get_current_thread_id(); } // Get the process ID of the process. diff --git a/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp index 1af3e334d2b63..f7ca6d565b4ed 100644 --- a/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp +++ b/src/coreclr/nativeaot/Runtime/eventpipe/ep-rt-aot.cpp @@ -405,10 +405,7 @@ ep_rt_aot_current_thread_get_id (void) { STATIC_CONTRACT_NOTHROW; #ifdef TARGET_UNIX - static __thread uint64_t tid; - if (!tid) - tid = PalGetCurrentOSThreadId(); - return static_cast(tid); + return static_cast(PalGetCurrentOSThreadId()); #else return static_cast(::GetCurrentThreadId ()); #endif diff --git a/src/coreclr/nativeaot/Runtime/unix/PalCreateDump.cpp b/src/coreclr/nativeaot/Runtime/unix/PalCreateDump.cpp index 408defa691e87..c320b64cc1ecf 100644 --- a/src/coreclr/nativeaot/Runtime/unix/PalCreateDump.cpp +++ b/src/coreclr/nativeaot/Runtime/unix/PalCreateDump.cpp @@ -48,6 +48,7 @@ #include "RhConfig.h" #include +#include #include #if !defined(HOST_MACCATALYST) && !defined(HOST_IOS) && !defined(HOST_TVOS) @@ -59,31 +60,6 @@ const char* g_argvCreateDump[MAX_ARGV_ENTRIES] = { nullptr }; char* g_szCreateDumpPath = nullptr; char* g_ppidarg = nullptr; -/*++ -Function: - PlatformGetCurrentThreadId - - Returns the current thread id -*/ - -#if defined(__linux__) -#define PlatformGetCurrentThreadId() (uint32_t)syscall(SYS_gettid) -#elif defined(__APPLE__) -inline uint32_t PlatformGetCurrentThreadId() { - uint64_t tid; - pthread_threadid_np(pthread_self(), &tid); - return (uint32_t)tid; -} -#elif defined(__FreeBSD__) -#include -#define PlatformGetCurrentThreadId() (uint32_t)pthread_getthreadid_np() -#elif defined(__NetBSD__) -#include -#define PlatformGetCurrentThreadId() (uint32_t)_lwp_self() -#else -#define PlatformGetCurrentThreadId() (uint32_t)pthread_self() -#endif - const size_t MaxUnsigned32BitDecString = STRING_LENGTH("4294967295"); const size_t MaxUnsigned64BitDecString = STRING_LENGTH("18446744073709551615"); @@ -386,7 +362,7 @@ PalCreateCrashDumpIfEnabled(int signal, siginfo_t* siginfo, void* exceptionRecor } // Add the current thread id to the command line. This function is always called on the crashing thread. - crashThreadArg = FormatInt(PlatformGetCurrentThreadId()); + crashThreadArg = FormatInt(minipal_get_current_thread_id()); if (crashThreadArg != nullptr) { argv[argc++] = "--crashthread"; diff --git a/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp b/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp index aac2e811bc807..56b453adc6ba3 100644 --- a/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp +++ b/src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #if HAVE_PTHREAD_GETTHREADID_NP #include @@ -718,15 +719,14 @@ REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalStartBackgroundWork(_In_ BackgroundCall REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalSetCurrentThreadName(const char* name) { - const int MAX_THREAD_NAME_SIZE = 15; - char name_copy[MAX_THREAD_NAME_SIZE + 1]; - strncpy(name_copy, name, MAX_THREAD_NAME_SIZE); - name_copy[MAX_THREAD_NAME_SIZE] = '\0'; -#ifdef __APPLE__ - pthread_setname_np(name_copy); -#else - pthread_setname_np(pthread_self(), name_copy); -#endif //__APPLE__ + // Ignore requests to set the main thread name because + // it causes the value returned by Process.ProcessName to change. + if ((pid_t)PalGetCurrentOSThreadId() != getpid()) + { + int setNameResult = minipal_set_thread_name(pthread_self(), name); + (void)setNameResult; // used + assert(setNameResult == 0); + } return true; } @@ -1292,19 +1292,5 @@ extern "C" uint64_t PalQueryPerformanceFrequency() extern "C" uint64_t PalGetCurrentOSThreadId() { -#if defined(__linux__) - return (uint64_t)syscall(SYS_gettid); -#elif defined(__APPLE__) - uint64_t tid; - pthread_threadid_np(pthread_self(), &tid); - return (uint64_t)tid; -#elif HAVE_PTHREAD_GETTHREADID_NP - return (uint64_t)pthread_getthreadid_np(); -#elif HAVE_LWP_SELF - return (uint64_t)_lwp_self(); -#else - // Fallback in case we don't know how to get integer thread id on the current platform - return (uint64_t)pthread_self(); -#endif + return (uint64_t)minipal_get_current_thread_id(); } - diff --git a/src/coreclr/pal/src/include/pal/thread.hpp b/src/coreclr/pal/src/include/pal/thread.hpp index 411040f39b21a..13875bcf14346 100644 --- a/src/coreclr/pal/src/include/pal/thread.hpp +++ b/src/coreclr/pal/src/include/pal/thread.hpp @@ -33,6 +33,7 @@ Module Name: #include "threadinfo.hpp" #include "synchobjects.hpp" #include +#include namespace CorUnix { @@ -91,13 +92,6 @@ namespace CorUnix HANDLE *phThread ); - PAL_ERROR - InternalSetThreadDescription( - CPalThread *, - HANDLE, - PCWSTR - ); - PAL_ERROR CreateThreadData( CPalThread **ppThread @@ -192,14 +186,6 @@ namespace CorUnix int ); - friend - PAL_ERROR - InternalSetThreadDescription( - CPalThread *, - HANDLE, - PCWSTR - ); - friend PAL_ERROR CreateThreadData( @@ -723,50 +709,9 @@ TLSCleanup( extern PAL_ActivationFunction g_activationFunction; extern PAL_SafeActivationCheckFunction g_safeActivationCheckFunction; -/*++ -Macro: - THREADSilentGetCurrentThreadId - -Abstract: - Same as GetCurrentThreadId, but it doesn't output any traces. - It is useful for tracing functions to display the thread ID - without generating any new traces. - - TODO: how does the perf of pthread_self compare to - InternalGetCurrentThread when we find the thread in the - cache? - - If the perf of pthread_self is comparable to that of the stack - bounds based lookaside system, why aren't we using it in the - cache? - - In order to match the thread ids that debuggers use at least for - linux we need to use gettid(). - ---*/ -#if defined(__linux__) -#define PlatformGetCurrentThreadId() (SIZE_T)syscall(SYS_gettid) -#elif defined(__APPLE__) -inline SIZE_T PlatformGetCurrentThreadId() { - uint64_t tid; - pthread_threadid_np(pthread_self(), &tid); - return (SIZE_T)tid; -} -#elif defined(__FreeBSD__) -#include -#define PlatformGetCurrentThreadId() (SIZE_T)pthread_getthreadid_np() -#elif defined(__NetBSD__) -#include -#define PlatformGetCurrentThreadId() (SIZE_T)_lwp_self() -#else -#define PlatformGetCurrentThreadId() (SIZE_T)pthread_self() -#endif - -inline SIZE_T THREADSilentGetCurrentThreadId() { - static __thread SIZE_T tid; - if (!tid) - tid = PlatformGetCurrentThreadId(); - return tid; +inline SIZE_T THREADSilentGetCurrentThreadId() +{ + return minipal_get_current_thread_id(); } #endif // _PAL_THREAD_HPP_ diff --git a/src/coreclr/pal/src/misc/perfjitdump.cpp b/src/coreclr/pal/src/misc/perfjitdump.cpp index 6223d533ac7f7..93262462c1962 100644 --- a/src/coreclr/pal/src/misc/perfjitdump.cpp +++ b/src/coreclr/pal/src/misc/perfjitdump.cpp @@ -102,7 +102,7 @@ namespace { JitCodeLoadRecord() : pid(getpid()), - tid((uint32_t)PlatformGetCurrentThreadId()) + tid((uint32_t)THREADSilentGetCurrentThreadId()) { header.id = JIT_CODE_LOAD; header.timestamp = GetTimeStampNS(); diff --git a/src/coreclr/pal/src/synchmgr/synchmanager.cpp b/src/coreclr/pal/src/synchmgr/synchmanager.cpp index f7d505dabaf01..07cbfa302d420 100644 --- a/src/coreclr/pal/src/synchmgr/synchmanager.cpp +++ b/src/coreclr/pal/src/synchmgr/synchmanager.cpp @@ -1708,9 +1708,7 @@ namespace CorUnix reinterpret_cast(pArg); CPalThread * pthrWorker = InternalGetCurrentThread(); - InternalSetThreadDescription(pthrWorker, - PAL_GetCurrentThread(), - W(".NET SynchManager")); + SetThreadDescription(PAL_GetCurrentThread(), W(".NET SynchManager")); while (!fWorkerIsDone) { diff --git a/src/coreclr/pal/src/thread/thread.cpp b/src/coreclr/pal/src/thread/thread.cpp index abfde0de726f3..60fa11872148c 100644 --- a/src/coreclr/pal/src/thread/thread.cpp +++ b/src/coreclr/pal/src/thread/thread.cpp @@ -29,6 +29,8 @@ SET_DEFAULT_DEBUG_CHANNEL(THREAD); // some headers have code with asserts, so do #include "pal/utils.h" #include "pal/virtual.h" +#include + #if defined(__NetBSD__) && !HAVE_PTHREAD_GETCPUCLOCKID #include #include @@ -75,14 +77,6 @@ typedef cpuset_t cpu_set_t; using namespace CorUnix; -#ifdef __APPLE__ -#define MAX_THREAD_NAME_SIZE 63 -#elif defined(__FreeBSD__) -#define MAX_THREAD_NAME_SIZE MAXCOMLEN -#else -#define MAX_THREAD_NAME_SIZE 15 -#endif - /* ------------------- Definitions ------------------------------*/ // Activation function that gets called when an activation is injected into a thread. @@ -1474,138 +1468,51 @@ SetThreadDescription( IN HANDLE hThread, IN PCWSTR lpThreadDescription) { - CPalThread *pThread; - PAL_ERROR palError; - PERF_ENTRY(SetThreadDescription); ENTRY("SetThreadDescription(hThread=%p,lpThreadDescription=%p)\n", hThread, lpThreadDescription); - pThread = InternalGetCurrentThread(); - - palError = InternalSetThreadDescription( - pThread, - hThread, - lpThreadDescription - ); - - if (NO_ERROR != palError) - { - pThread->SetLastError(palError); - } - - LOGEXIT("SetThreadDescription"); - PERF_EXIT(SetThreadDescription); - - return HRESULT_FROM_WIN32(palError); -} + CPalThread *pThread = InternalGetCurrentThread(); -PAL_ERROR -CorUnix::InternalSetThreadDescription( - CPalThread *pThread, - HANDLE hTargetThread, - PCWSTR lpThreadDescription -) -{ - PAL_ERROR palError = NO_ERROR; CPalThread *pTargetThread = NULL; IPalObject *pobjThread = NULL; - int error = 0; - int maxNameSize = 0; int nameSize; char *nameBuf = NULL; -// The exact API of pthread_setname_np varies very wildly depending on OS. -// For now, only Linux, macOS and FreeBSD are implemented. -#if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) - - palError = InternalGetThreadDataFromHandle( - pThread, - hTargetThread, - &pTargetThread, - &pobjThread - ); - - if (NO_ERROR != palError) - { - goto InternalSetThreadDescriptionExit; - } - - pTargetThread->Lock(pThread); - - // Ignore requests to set the main thread name because - // it causes the value returned by Process.ProcessName to change. - if ((pid_t)pTargetThread->GetThreadId() == getpid()) - { - goto InternalSetThreadDescriptionExit; - } - - /* translate the wide char lpThreadDescription string to multibyte string */ - nameSize = WideCharToMultiByte(CP_ACP, 0, lpThreadDescription, -1, NULL, 0, NULL, NULL); - - if (0 == nameSize) - { - palError = ERROR_INTERNAL_ERROR; - goto InternalSetThreadDescriptionExit; - } - - nameBuf = (char *)malloc(nameSize); - if (nameBuf == NULL) - { - palError = ERROR_OUTOFMEMORY; - goto InternalSetThreadDescriptionExit; - } - - if (WideCharToMultiByte(CP_ACP, 0, lpThreadDescription, -1, nameBuf, nameSize, NULL, - NULL) != nameSize) - { - palError = ERROR_INTERNAL_ERROR; - goto InternalSetThreadDescriptionExit; - } - - // Null terminate early. - // pthread_setname_np only accepts up to 16 chars on Linux, - // 64 chars on macOS and 20 chars on FreeBSD. - if (nameSize > MAX_THREAD_NAME_SIZE) - { - nameBuf[MAX_THREAD_NAME_SIZE] = '\0'; - } - - #if defined(__linux__) || defined(__FreeBSD__) - error = pthread_setname_np(pTargetThread->GetPThreadSelf(), nameBuf); - #endif - - #if defined(__APPLE__) - // on macOS, pthread_setname_np only works for the calling thread. - if (PlatformGetCurrentThreadId() == pTargetThread->GetThreadId()) - { - error = pthread_setname_np(nameBuf); - } - #endif - - if (error != 0) + PAL_ERROR palError = InternalGetThreadDataFromHandle(pThread, hThread, &pTargetThread, &pobjThread); + if (palError != NO_ERROR) { - palError = ERROR_INTERNAL_ERROR; - } + // Ignore requests to set the main thread name because + // it causes the value returned by Process.ProcessName to change. + if ((pid_t)pTargetThread->GetThreadId() != getpid()) + { + nameSize = WideCharToMultiByte(CP_ACP, 0, lpThreadDescription, -1, NULL, 0, NULL, NULL); + if (nameSize > 0) + { + nameBuf = (char *)malloc(nameSize); + if (nameBuf == NULL || WideCharToMultiByte(CP_ACP, 0, lpThreadDescription, -1, nameBuf, nameSize, NULL, NULL) != nameSize) + { + pThread->SetLastError(ERROR_INSUFFICIENT_BUFFER); + } -InternalSetThreadDescriptionExit: + int setNameResult = minipal_set_thread_name(pTargetThread->GetPThreadSelf(), nameBuf); + (void)setNameResult; // used + _ASSERTE(setNameResult == 0); - if (NULL != pTargetThread) - { - pTargetThread->Unlock(pThread); - } + free(nameBuf); + } + else + { + pThread->SetLastError(ERROR_INVALID_PARAMETER); + } + } - if (NULL != pobjThread) - { pobjThread->ReleaseReference(pThread); } - if (NULL != nameBuf) { - free(nameBuf); - } - -#endif //defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) + LOGEXIT("SetThreadDescription"); + PERF_EXIT(SetThreadDescription); - return palError; + return HRESULT_FROM_WIN32(palError); } void * @@ -2568,7 +2475,7 @@ void * CPalThread::GetStackBase() { void* stackBase; -#ifdef TARGET_OSX +#ifdef TARGET_APPLE // This is a Mac specific method stackBase = pthread_get_stackaddr_np(pthread_self()); #else @@ -2608,7 +2515,7 @@ void * CPalThread::GetStackLimit() { void* stackLimit; -#ifdef TARGET_OSX +#ifdef TARGET_APPLE // This is a Mac specific method stackLimit = ((BYTE *)pthread_get_stackaddr_np(pthread_self()) - pthread_get_stacksize_np(pthread_self())); diff --git a/src/mono/mono/utils/mono-threads-mach.c b/src/mono/mono/utils/mono-threads-mach.c index a9240dd36de14..79fa501d5e045 100644 --- a/src/mono/mono/utils/mono-threads-mach.c +++ b/src/mono/mono/utils/mono-threads-mach.c @@ -26,6 +26,7 @@ #include #include #include +#include void mono_threads_suspend_init (void) @@ -210,7 +211,7 @@ mono_threads_suspend_register (MonoThreadInfo *info) info->native_handle = mach_thread_self (); snprintf (thread_name, sizeof (thread_name), "tid_%x", (int) info->native_handle); - pthread_setname_np (thread_name); + minipal_set_thread_name (mono_thread_info_get_tid(info), thread_name); mono_threads_install_dead_letter (); } diff --git a/src/mono/mono/utils/mono-threads-posix.c b/src/mono/mono/utils/mono-threads-posix.c index ea4cf7f90fb5d..551b05892ebf4 100644 --- a/src/mono/mono/utils/mono-threads-posix.c +++ b/src/mono/mono/utils/mono-threads-posix.c @@ -30,6 +30,10 @@ #include #include +#if defined (HAVE_PTHREAD_SETNAME_NP) || defined(__HAIKU__) +#include +#endif + #include #if defined(_POSIX_VERSION) && !defined (HOST_WASM) @@ -255,64 +259,16 @@ mono_native_thread_get_name (MonoNativeThreadId tid, char *name_out, size_t max_ void mono_native_thread_set_name (MonoNativeThreadId tid, const char *name) { -#ifdef __MACH__ - /* - * We can't set the thread name for other threads, but we can at least make - * it work for threads that try to change their own name. - */ - if (tid != mono_native_thread_id_get ()) - return; - - if (!name) { - pthread_setname_np (""); - } else { - char n [63]; - - strncpy (n, name, sizeof (n) - 1); - n [sizeof (n) - 1] = '\0'; - pthread_setname_np (n); - } -#elif defined (__HAIKU__) - thread_id haiku_tid; - haiku_tid = get_pthread_thread_id (tid); - if (!name) { - rename_thread (haiku_tid, ""); - } else { - rename_thread (haiku_tid, name); - } -#elif defined (__NetBSD__) - if (!name) { - pthread_setname_np (tid, "%s", (void*)""); - } else { - char n [PTHREAD_MAX_NAMELEN_NP]; - - strncpy (n, name, sizeof (n) - 1); - n [sizeof (n) - 1] = '\0'; - pthread_setname_np (tid, "%s", (void*)n); - } -#elif defined (HAVE_PTHREAD_SETNAME_NP) -#if defined (__linux__) - /* Ignore requests to set the main thread name because it causes the - * value returned by Process.ProcessName to change. - */ +#if defined (HAVE_PTHREAD_SETNAME_NP) || defined(__HAIKU__) + // Ignore requests to set the main thread name because + // it causes the value returned by Process.ProcessName to change. MonoNativeThreadId main_thread_tid; if (mono_native_thread_id_main_thread_known (&main_thread_tid) && mono_native_thread_id_equals (tid, main_thread_tid)) return; -#endif - if (!name) { - pthread_setname_np (tid, ""); - } else { -#if defined(__FreeBSD__) - char n [20]; -#else - char n [16]; -#endif - strncpy (n, name, sizeof (n) - 1); - n [sizeof (n) - 1] = '\0'; - pthread_setname_np (tid, n); - } + int setNameResult = minipal_set_thread_name(tid, name); + g_assert(setNameResult == 0); #endif } diff --git a/src/native/libs/System.Native/pal_signal.c b/src/native/libs/System.Native/pal_signal.c index 257969dc67a94..bf59c24b9df96 100644 --- a/src/native/libs/System.Native/pal_signal.c +++ b/src/native/libs/System.Native/pal_signal.c @@ -9,13 +9,14 @@ #include #include -#include #include #include #include #include #include +#include + static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; // Saved signal handlers @@ -309,17 +310,16 @@ static void* SignalHandlerLoop(void* arg) // Passed in argument is a ptr to the file descriptor // for the read end of the pipe. assert(arg != NULL); + int pipeFd = *(int*)arg; + free(arg); assert(pipeFd >= 0); - char* threadName = ".NET SigHandler"; -#if defined(__linux__) || defined(__FreeBSD__) - pthread_setname_np(pthread_self(), threadName); -#endif -#if defined(__APPLE__) - pthread_setname_np(threadName); -#endif + // set thread name + int setNameResult = minipal_set_thread_name(pthread_self(), ".NET SigHandler"); + (void)setNameResult; // used + assert(setNameResult == 0); // Continually read a signal code from the signal pipe and process it, // until the pipe is closed. diff --git a/src/native/libs/System.Native/pal_threading.c b/src/native/libs/System.Native/pal_threading.c index 1d9f3cd6bf330..860be7121eb21 100644 --- a/src/native/libs/System.Native/pal_threading.c +++ b/src/native/libs/System.Native/pal_threading.c @@ -12,6 +12,7 @@ #include #include #include +#include #if HAVE_SCHED_GETCPU #include #endif @@ -286,47 +287,13 @@ void SystemNative_Abort(void) // Gets a non-truncated OS thread ID that is also suitable for diagnostics, for platforms that offer a 64-bit ID uint64_t SystemNative_GetUInt64OSThreadId(void) { -#ifdef __APPLE__ - uint64_t threadId; - int result = pthread_threadid_np(pthread_self(), &threadId); - assert(result == 0); - return threadId; -#else - assert(false); - return 0; -#endif + return (uint64_t)minipal_get_current_thread_id(); } -#if defined(__linux__) -#include -#include -#elif defined(__FreeBSD__) -#include -#elif defined(__NetBSD__) -#include -#endif - // Tries to get a non-truncated OS thread ID that is also suitable for diagnostics, for platforms that offer a 32-bit ID. // Returns (uint32_t)-1 when the implementation does not know how to get the OS thread ID. uint32_t SystemNative_TryGetUInt32OSThreadId(void) { - const uint32_t InvalidId = (uint32_t)-1; - -#if defined(__linux__) - assert(sizeof(pid_t) == sizeof(uint32_t)); - uint32_t threadId = (uint32_t)syscall(SYS_gettid); - assert(threadId != InvalidId); - return threadId; -#elif defined(__FreeBSD__) - uint32_t threadId = (uint32_t)pthread_getthreadid_np(); - assert(threadId != InvalidId); - return threadId; -#elif defined(__NetBSD__) - assert(sizeof(lwpid_t) == sizeof(uint32_t)); - uint32_t threadId = (uint32_t)_lwp_self(); - assert(threadId != InvalidId); - return threadId; -#else - return InvalidId; -#endif + uint32_t result = (uint32_t)minipal_get_current_thread_id(); + return result == 0 ? (uint32_t)-1 : result; } diff --git a/src/native/minipal/getexepath.h b/src/native/minipal/getexepath.h index 3c79e734b5a9e..d2a7484da9da5 100644 --- a/src/native/minipal/getexepath.h +++ b/src/native/minipal/getexepath.h @@ -25,8 +25,13 @@ extern "C" { #endif -// Returns the full path to the executable for the current process, resolving symbolic links. -// The caller is responsible for releasing the buffer. Returns null on error. +/** + * Get the full path to the executable for the current process. + * Resolves symbolic links. The caller is responsible for releasing the buffer. + * + * @return A pointer to a null-terminated string containing the executable path, + * or NULL if an error occurs. + */ static inline char* minipal_getexepath(void) { #if defined(__APPLE__) diff --git a/src/native/minipal/thread.h b/src/native/minipal/thread.h new file mode 100644 index 0000000000000..8261cc6a6d1b2 --- /dev/null +++ b/src/native/minipal/thread.h @@ -0,0 +1,118 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef HAVE_MINIPAL_THREAD_H +#define HAVE_MINIPAL_THREAD_H + +#include +#include +#include +#include + +#if defined(__linux__) +#include +#include +#elif defined(__FreeBSD__) +#include +#elif defined(__NetBSD__) +#include +#elif defined(__HAIKU__) +#include +#endif + +#ifdef PTHREAD_MAX_NAMELEN_NP +#define MINIPAL_MAX_THREAD_NAME_LENGTH (PTHREAD_MAX_NAMELEN_NP - 1) +#elif defined(__APPLE__) +#define MINIPAL_MAX_THREAD_NAME_LENGTH 63 +#elif defined(__FreeBSD__) +#define MINIPAL_MAX_THREAD_NAME_LENGTH MAXCOMLEN +#elif defined(__HAIKU__) +#define MINIPAL_MAX_THREAD_NAME_LENGTH (B_OS_NAME_LENGTH - 1) +#else +#define MINIPAL_MAX_THREAD_NAME_LENGTH 15 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Get the current thread ID. + * + * @return The current thread ID as a size_t value. + */ +static inline size_t minipal_get_current_thread_id(void) +{ +#ifdef __wasm + return 0; +#else +#if defined(__GNUC__) && !defined(__clang__) && defined(__cplusplus) + // gcc doesn't like _Thread_local when __cplusplus is defined. + // although thread_local is C2x, which other compilers don't allow with C11. + static thread_local size_t tid = 0; +#else + static _Thread_local size_t tid = 0; +#endif + + if (!tid) +#if defined(__linux__) + tid = (size_t)syscall(SYS_gettid); +#elif defined(__APPLE__) + { + uint64_t thread_id; + pthread_threadid_np(pthread_self(), &thread_id); + tid = (size_t)thread_id; // Cast the uint64_t thread ID to size_t + } +#elif defined(__FreeBSD__) + tid = (size_t)pthread_getthreadid_np(); +#elif defined(__NetBSD__) + tid = (size_t)_lwp_self(); +#else + tid = (size_t)(void*)pthread_self(); +#endif + + return tid; +#endif +} + +/** + * Set the name of the specified thread. + * + * @param thread The thread for which to set the name. + * @param name The desired name for the thread. + * @return 0 on success, or an error code if the operation fails. + */ +static inline int minipal_set_thread_name(pthread_t thread, const char* name) +{ +#ifdef __wasm + // WASM does not support pthread_setname_np yet: https://github.com/emscripten-core/emscripten/pull/18751 + return 0; +#else + const char* threadName = name; + char truncatedName[MINIPAL_MAX_THREAD_NAME_LENGTH + 1]; + + if (strlen(name) > MINIPAL_MAX_THREAD_NAME_LENGTH) + { + strncpy(truncatedName, name, MINIPAL_MAX_THREAD_NAME_LENGTH); + truncatedName[MINIPAL_MAX_THREAD_NAME_LENGTH] = '\0'; + threadName = truncatedName; + } + +#if defined(__APPLE__) + // On Apple OSes, pthread_setname_np only works for the calling thread. + if (thread != pthread_self()) return 0; + + return pthread_setname_np(threadName); +#elif defined(__HAIKU__) + return rename_thread(get_pthread_thread_id(thread), threadName); +#else + return pthread_setname_np(thread, threadName); +#endif +#endif +} + +#ifdef __cplusplus +} +#endif // extern "C" + +#endif // HAVE_MINIPAL_THREAD_H