@@ -819,41 +819,6 @@ CorUnix::InternalCreateThread(
819819 _ASSERT_MSG (pNewThread->IsInPal (), " New threads we're about to spawn should always be in the PAL.\n " );
820820#endif // FEATURE_PAL_SXS
821821
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-
857822 iError = pthread_create (&pthread, &pthreadAttr, CPalThread::ThreadEntry, pNewThread);
858823
859824#if PTHREAD_CREATE_MODIFIES_ERRNO
@@ -1713,6 +1678,10 @@ CPalThread::ThreadEntry(
17131678 PTHREAD_START_ROUTINE pfnStartRoutine;
17141679 LPVOID pvPar;
17151680 DWORD retValue;
1681+ #if HAVE_SCHED_GETAFFINITY && HAVE_SCHED_SETAFFINITY
1682+ cpu_set_t cpuSet;
1683+ int st;
1684+ #endif
17161685
17171686 pThread = reinterpret_cast <CPalThread*>(pvParam);
17181687
@@ -1722,6 +1691,42 @@ CPalThread::ThreadEntry(
17221691 goto fail;
17231692 }
17241693
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+
17251730#if !HAVE_MACH_EXCEPTIONS
17261731 if (!pThread->EnsureSignalAlternateStack ())
17271732 {
@@ -3038,18 +3043,31 @@ BOOL
30383043PALAPI
30393044PAL_SetCurrentThreadAffinity (WORD procNo)
30403045{
3041- #if HAVE_PTHREAD_GETAFFINITY_NP
3046+ #if HAVE_SCHED_SETAFFINITY || HAVE_PTHREAD_SETAFFINITY_NP
30423047 cpu_set_t cpuSet;
30433048 CPU_ZERO (&cpuSet);
3044-
30453049 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
30463063 int st = pthread_setaffinity_np (pthread_self (), sizeof (cpu_set_t ), &cpuSet);
3064+ #endif
30473065
30483066 return st == 0 ;
3049- #else // HAVE_PTHREAD_GETAFFINITY_NP
3067+ #else // !(HAVE_SCHED_SETAFFINITY || HAVE_PTHREAD_SETAFFINITY_NP)
30503068 // There is no API to manage thread affinity, so let's ignore the request
30513069 return FALSE ;
3052- #endif // HAVE_PTHREAD_GETAFFINITY_NP
3070+ #endif // HAVE_SCHED_SETAFFINITY || HAVE_PTHREAD_SETAFFINITY_NP
30533071}
30543072
30553073/* ++
0 commit comments