diff options
author | Jan Vorlicek <janvorli@microsoft.com> | 2019-05-28 18:06:38 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-28 18:06:38 +0200 |
commit | 3489e56c875c6144c729b51063300c7d60b1ae31 (patch) | |
tree | d00230bcefd3855b81197d1392ad64d749834ba1 /src/pal | |
parent | 9f3e89dd8634781f425a60f9a635787d0820d63d (diff) | |
download | coreclr-3489e56c875c6144c729b51063300c7d60b1ae31.tar.gz coreclr-3489e56c875c6144c729b51063300c7d60b1ae31.tar.bz2 coreclr-3489e56c875c6144c729b51063300c7d60b1ae31.zip |
Fix initial thread affinity on Linux (#24801)
* Fix initial thread affinity on Linux
On Linux, a new thread inherits the affinity mask of the thread
that created the new thread. This is a problem for background GC
threads that are created by one of the server GC threads that are
affinitized to single core.
This change adds resetting each new thread affinity to match the
current process affinity.
In addition to that, I've also fixed the extraction of the CPU count
that was using PID 0. While the doc says that 0 represents current process,
it in fact means current thread.
And as a small bonus, I've added caching of the value returned by
the PAL_GetLogicalCpuCountFromOS, since it cannot change during runtime.
Diffstat (limited to 'src/pal')
-rw-r--r-- | src/pal/src/config.h.in | 1 | ||||
-rw-r--r-- | src/pal/src/configure.cmake | 1 | ||||
-rw-r--r-- | src/pal/src/misc/sysinfo.cpp | 22 | ||||
-rw-r--r-- | src/pal/src/thread/thread.cpp | 36 |
4 files changed, 51 insertions, 9 deletions
diff --git a/src/pal/src/config.h.in b/src/pal/src/config.h.in index 3ceb180563..505b2ee208 100644 --- a/src/pal/src/config.h.in +++ b/src/pal/src/config.h.in @@ -36,6 +36,7 @@ #cmakedefine01 HAVE_PTHREAD_GETCPUCLOCKID #cmakedefine01 HAVE_PTHREAD_SIGQUEUE #cmakedefine01 HAVE_PTHREAD_GETAFFINITY_NP +#cmakedefine01 HAVE_PTHREAD_ATTR_SETAFFINITY_NP #cmakedefine01 HAVE_CPUSET_T #cmakedefine01 HAVE_SIGRETURN #cmakedefine01 HAVE__THREAD_SYS_SIGRETURN diff --git a/src/pal/src/configure.cmake b/src/pal/src/configure.cmake index d214dd3e83..7b6391f228 100644 --- a/src/pal/src/configure.cmake +++ b/src/pal/src/configure.cmake @@ -101,6 +101,7 @@ check_library_exists(${PTHREAD_LIBRARY} pthread_getattr_np "" HAVE_PTHREAD_GETAT check_library_exists(${PTHREAD_LIBRARY} pthread_getcpuclockid "" HAVE_PTHREAD_GETCPUCLOCKID) check_library_exists(${PTHREAD_LIBRARY} pthread_sigqueue "" HAVE_PTHREAD_SIGQUEUE) check_library_exists(${PTHREAD_LIBRARY} pthread_getaffinity_np "" HAVE_PTHREAD_GETAFFINITY_NP) +check_library_exists(${PTHREAD_LIBRARY} pthread_attr_setaffinity_np "" HAVE_PTHREAD_ATTR_SETAFFINITY_NP) check_function_exists(sigreturn HAVE_SIGRETURN) check_function_exists(_thread_sys_sigreturn HAVE__THREAD_SYS_SIGRETURN) diff --git a/src/pal/src/misc/sysinfo.cpp b/src/pal/src/misc/sysinfo.cpp index 1a1a12f02f..d0e8ca64dc 100644 --- a/src/pal/src/misc/sysinfo.cpp +++ b/src/pal/src/misc/sysinfo.cpp @@ -80,6 +80,7 @@ Revision History: #endif #include "pal/dbgmsg.h" +#include "pal/process.h" #include <algorithm> @@ -139,21 +140,24 @@ DWORD PALAPI PAL_GetLogicalCpuCountFromOS() { - int nrcpus = 0; + static int nrcpus = -1; + if (nrcpus == -1) + { #if HAVE_SCHED_GETAFFINITY - cpu_set_t cpuSet; - int st = sched_getaffinity(0, sizeof(cpu_set_t), &cpuSet); - if (st != 0) - { - ASSERT("sched_getaffinity failed (%d)\n", errno); - } + cpu_set_t cpuSet; + int st = sched_getaffinity(gPID, sizeof(cpu_set_t), &cpuSet); + if (st != 0) + { + ASSERT("sched_getaffinity failed (%d)\n", errno); + } - nrcpus = CPU_COUNT(&cpuSet); + nrcpus = CPU_COUNT(&cpuSet); #else // HAVE_SCHED_GETAFFINITY - nrcpus = PAL_GetTotalCpuCount(); + nrcpus = PAL_GetTotalCpuCount(); #endif // HAVE_SCHED_GETAFFINITY + } return nrcpus; } diff --git a/src/pal/src/thread/thread.cpp b/src/pal/src/thread/thread.cpp index 21775f1541..34d780845f 100644 --- a/src/pal/src/thread/thread.cpp +++ b/src/pal/src/thread/thread.cpp @@ -760,6 +760,42 @@ CorUnix::InternalCreateThread( #ifdef FEATURE_PAL_SXS _ASSERT_MSG(pNewThread->IsInPal(), "New threads we're about to spawn should always be in the PAL.\n"); #endif // FEATURE_PAL_SXS + +#if HAVE_PTHREAD_ATTR_SETAFFINITY_NP && HAVE_SCHED_GETAFFINITY + { + // Threads inherit their parent's affinity mask on Linux. This is not desired, so we reset + // the current thread's affinity mask to the mask of the current process. + cpu_set_t cpuSet; + CPU_ZERO(&cpuSet); + + int st = sched_getaffinity(gPID, sizeof(cpu_set_t), &cpuSet); + if (st != 0) + { + ASSERT("sched_getaffinity failed!\n"); + // the sched_getaffinity should never fail for getting affinity of the current process + palError = ERROR_INTERNAL_ERROR; + goto EXIT; + } + + st = pthread_attr_setaffinity_np(&pthreadAttr, sizeof(cpu_set_t), &cpuSet); + if (st != 0) + { + if (st == ENOMEM) + { + palError = ERROR_NOT_ENOUGH_MEMORY; + } + else + { + ASSERT("pthread_attr_setaffinity_np failed!\n"); + // The pthread_attr_setaffinity_np should never fail except of OOM when + // passed the mask extracted using sched_getaffinity. + palError = ERROR_INTERNAL_ERROR; + } + goto EXIT; + } + } +#endif // HAVE_PTHREAD_GETAFFINITY_NP && HAVE_SCHED_GETAFFINITY + iError = pthread_create(&pthread, &pthreadAttr, CPalThread::ThreadEntry, pNewThread); #if PTHREAD_CREATE_MODIFIES_ERRNO |