@@ -819,41 +819,6 @@ CorUnix::InternalCreateThread(
819
819
_ASSERT_MSG (pNewThread->IsInPal (), " New threads we're about to spawn should always be in the PAL.\n " );
820
820
#endif // FEATURE_PAL_SXS
821
821
822
- #if HAVE_PTHREAD_ATTR_SETAFFINITY_NP && HAVE_SCHED_GETAFFINITY
823
- {
824
- // Threads inherit their parent's affinity mask on Linux. This is not desired, so we reset
825
- // the current thread's affinity mask to the mask of the current process.
826
- cpu_set_t cpuSet;
827
- CPU_ZERO (&cpuSet);
828
-
829
- int st = sched_getaffinity (gPID , sizeof (cpu_set_t ), &cpuSet);
830
- if (st != 0 )
831
- {
832
- ASSERT (" sched_getaffinity failed!\n " );
833
- // the sched_getaffinity should never fail for getting affinity of the current process
834
- palError = ERROR_INTERNAL_ERROR;
835
- goto EXIT;
836
- }
837
-
838
- st = pthread_attr_setaffinity_np (&pthreadAttr, sizeof (cpu_set_t ), &cpuSet);
839
- if (st != 0 )
840
- {
841
- if (st == ENOMEM)
842
- {
843
- palError = ERROR_NOT_ENOUGH_MEMORY;
844
- }
845
- else
846
- {
847
- ASSERT (" pthread_attr_setaffinity_np failed!\n " );
848
- // The pthread_attr_setaffinity_np should never fail except of OOM when
849
- // passed the mask extracted using sched_getaffinity.
850
- palError = ERROR_INTERNAL_ERROR;
851
- }
852
- goto EXIT;
853
- }
854
- }
855
- #endif // HAVE_PTHREAD_GETAFFINITY_NP && HAVE_SCHED_GETAFFINITY
856
-
857
822
iError = pthread_create (&pthread, &pthreadAttr, CPalThread::ThreadEntry, pNewThread);
858
823
859
824
#if PTHREAD_CREATE_MODIFIES_ERRNO
@@ -1713,6 +1678,10 @@ CPalThread::ThreadEntry(
1713
1678
PTHREAD_START_ROUTINE pfnStartRoutine;
1714
1679
LPVOID pvPar;
1715
1680
DWORD retValue;
1681
+ #if HAVE_SCHED_GETAFFINITY && HAVE_SCHED_SETAFFINITY
1682
+ cpu_set_t cpuSet;
1683
+ int st;
1684
+ #endif
1716
1685
1717
1686
pThread = reinterpret_cast <CPalThread*>(pvParam);
1718
1687
@@ -1722,6 +1691,42 @@ CPalThread::ThreadEntry(
1722
1691
goto fail;
1723
1692
}
1724
1693
1694
+ #if HAVE_SCHED_GETAFFINITY && HAVE_SCHED_SETAFFINITY
1695
+ // Threads inherit their parent's affinity mask on Linux. This is not desired, so we reset
1696
+ // the current thread's affinity mask to the mask of the current process.
1697
+ //
1698
+ // Typically, we would use pthread_attr_setaffinity_np() and have pthread_create() create the thread with the specified
1699
+ // affinity. At least one implementation of pthread_create() following a pthread_attr_setaffinity_np() calls
1700
+ // sched_setaffinity(<newThreadPid>, ...), which is not allowed under Snap's default strict confinement without manually
1701
+ // connecting the process-control plug. To work around that, have the thread set the affinity after it starts.
1702
+ // sched_setaffinity(<currentThreadPid>, ...) is also currently not allowed, only sched_setaffinity(0, ...).
1703
+ // pthread_setaffinity_np(pthread_self(), ...) seems to call sched_setaffinity(<currentThreadPid>, ...) in at least one
1704
+ // implementation, and does not work. Use sched_setaffinity(0, ...) instead. See the following for more information:
1705
+ // - https://github.com/dotnet/runtime/pull/38795
1706
+ // - https://github.com/dotnet/runtime/issues/1634
1707
+ // - https://forum.snapcraft.io/t/requesting-autoconnect-for-interfaces-in-pigmeat-process-control-home/17987/13
1708
+
1709
+ CPU_ZERO (&cpuSet);
1710
+
1711
+ st = sched_getaffinity (gPID , sizeof (cpu_set_t ), &cpuSet);
1712
+ if (st != 0 )
1713
+ {
1714
+ ASSERT (" sched_getaffinity failed!\n " );
1715
+ // The sched_getaffinity should never fail for getting affinity of the current process
1716
+ palError = ERROR_INTERNAL_ERROR;
1717
+ goto fail;
1718
+ }
1719
+
1720
+ st = sched_setaffinity (0 , sizeof (cpu_set_t ), &cpuSet);
1721
+ if (st != 0 )
1722
+ {
1723
+ ASSERT (" sched_setaffinity failed!\n " );
1724
+ // The sched_setaffinity should never fail when passed the mask extracted using sched_getaffinity
1725
+ palError = ERROR_INTERNAL_ERROR;
1726
+ goto fail;
1727
+ }
1728
+ #endif // HAVE_SCHED_GETAFFINITY && HAVE_SCHED_SETAFFINITY
1729
+
1725
1730
#if !HAVE_MACH_EXCEPTIONS
1726
1731
if (!pThread->EnsureSignalAlternateStack ())
1727
1732
{
@@ -3038,18 +3043,31 @@ BOOL
3038
3043
PALAPI
3039
3044
PAL_SetCurrentThreadAffinity (WORD procNo)
3040
3045
{
3041
- #if HAVE_PTHREAD_GETAFFINITY_NP
3046
+ #if HAVE_SCHED_SETAFFINITY || HAVE_PTHREAD_SETAFFINITY_NP
3042
3047
cpu_set_t cpuSet;
3043
3048
CPU_ZERO (&cpuSet);
3044
-
3045
3049
CPU_SET (procNo, &cpuSet);
3050
+
3051
+ // Snap's default strict confinement does not allow sched_setaffinity(<nonzeroPid>, ...) without manually connecting the
3052
+ // process-control plug. sched_setaffinity(<currentThreadPid>, ...) is also currently not allowed, only
3053
+ // sched_setaffinity(0, ...). pthread_setaffinity_np(pthread_self(), ...) seems to call
3054
+ // sched_setaffinity(<currentThreadPid>, ...) in at least one implementation, and does not work. To work around those
3055
+ // issues, use sched_setaffinity(0, ...) if available and only otherwise fall back to pthread_setaffinity_np(). See the
3056
+ // following for more information:
3057
+ // - https://github.com/dotnet/runtime/pull/38795
3058
+ // - https://github.com/dotnet/runtime/issues/1634
3059
+ // - https://forum.snapcraft.io/t/requesting-autoconnect-for-interfaces-in-pigmeat-process-control-home/17987/13
3060
+ #if HAVE_SCHED_SETAFFINITY
3061
+ int st = sched_setaffinity (0 , sizeof (cpu_set_t ), &cpuSet);
3062
+ #else
3046
3063
int st = pthread_setaffinity_np (pthread_self (), sizeof (cpu_set_t ), &cpuSet);
3064
+ #endif
3047
3065
3048
3066
return st == 0 ;
3049
- #else // HAVE_PTHREAD_GETAFFINITY_NP
3067
+ #else // !(HAVE_SCHED_SETAFFINITY || HAVE_PTHREAD_SETAFFINITY_NP)
3050
3068
// There is no API to manage thread affinity, so let's ignore the request
3051
3069
return FALSE ;
3052
- #endif // HAVE_PTHREAD_GETAFFINITY_NP
3070
+ #endif // HAVE_SCHED_SETAFFINITY || HAVE_PTHREAD_SETAFFINITY_NP
3053
3071
}
3054
3072
3055
3073
/* ++
0 commit comments