summaryrefslogtreecommitdiff
path: root/src/pal
diff options
context:
space:
mode:
authorJan Vorlicek <janvorli@microsoft.com>2019-05-28 18:06:38 +0200
committerGitHub <noreply@github.com>2019-05-28 18:06:38 +0200
commit3489e56c875c6144c729b51063300c7d60b1ae31 (patch)
treed00230bcefd3855b81197d1392ad64d749834ba1 /src/pal
parent9f3e89dd8634781f425a60f9a635787d0820d63d (diff)
downloadcoreclr-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.in1
-rw-r--r--src/pal/src/configure.cmake1
-rw-r--r--src/pal/src/misc/sysinfo.cpp22
-rw-r--r--src/pal/src/thread/thread.cpp36
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