-
Notifications
You must be signed in to change notification settings - Fork 4.9k
Shim'ing out the processor affinity function calls for the Linux kernel #3798
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
// Licensed under the MIT license. See LICENSE file in the project root for full license information. | ||
|
||
using System; | ||
using System.Runtime.InteropServices; | ||
|
||
internal static partial class Interop | ||
{ | ||
internal static partial class Sys | ||
{ | ||
internal unsafe struct CpuSetBits | ||
{ | ||
private fixed ulong Bits[16]; | ||
} | ||
|
||
[DllImport(Libraries.SystemNative, SetLastError = true)] | ||
internal static extern int SchedSetAffinity(int pid, ref CpuSetBits mask); | ||
|
||
[DllImport(Libraries.SystemNative, SetLastError = true)] | ||
internal static extern int SchedGetAffinity(int pid, out CpuSetBits mask); | ||
|
||
[DllImport(Libraries.SystemNative)] | ||
internal static extern void CpuSet(int cpu, ref CpuSetBits set); | ||
|
||
[DllImport(Libraries.SystemNative)] | ||
internal static extern bool CpuIsSet(int cpu, ref CpuSetBits set); | ||
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,10 @@ | |
#include <syslog.h> | ||
#include <unistd.h> | ||
|
||
#if HAVE_SCHED_SETAFFINITY || HAVE_SCHED_GETAFFINITY | ||
#include <sched.h> | ||
#endif | ||
|
||
// Validate that our Signals enum values are correct for the platform | ||
static_assert(PAL_SIGKILL == SIGKILL, ""); | ||
|
||
|
@@ -59,6 +63,12 @@ static_assert(PAL_PRIO_PROCESS == static_cast<int>(PRIO_PROCESS), ""); | |
static_assert(PAL_PRIO_PGRP == static_cast<int>(PRIO_PGRP), ""); | ||
static_assert(PAL_PRIO_USER == static_cast<int>(PRIO_USER), ""); | ||
|
||
#if HAVE_SCHED_SETAFFINITY || HAVE_SCHED_GETAFFINITY | ||
// Validate that the number of bits in the PAL CPU affinity struct is | ||
// greater than or equal to the native one so we can memcpy correctly | ||
static_assert(sizeof(CpuSetBits) >= sizeof(cpu_set_t), ""); | ||
#endif | ||
|
||
enum | ||
{ | ||
READ_END_OF_PIPE = 0, | ||
|
@@ -417,3 +427,68 @@ extern "C" char* GetCwd(char* buffer, int32_t bufferSize) | |
|
||
return getcwd(buffer, UnsignedCast(bufferSize)); | ||
} | ||
|
||
#if HAVE_SCHED_SETAFFINITY | ||
static bool ConvertPalToNativeCpuSet(const CpuSetBits& pal, cpu_set_t& native) | ||
{ | ||
if (sizeof(pal) > sizeof(native)) | ||
{ | ||
// If the PAL struct is bigger than the native struct | ||
// then make sure the user hasn't put data in the | ||
// bits that would be inaccessible to the underlying OS | ||
for (size_t i = sizeof(native); i < sizeof(pal); i++) | ||
{ | ||
if (pal.Bits[i] != 0) | ||
return false; | ||
} | ||
} | ||
|
||
memcpy(native.__bits, pal.Bits, ARRAY_SIZE(native.__bits)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Earlier we statically asserted that sizeof(CpuSetBits) >= sizeof(cpu_set_t). So while unlikely, it's possible that CpuSetBits is larger than cpu_set_t, which means it's possible that this call could be trying to set affinity to a value that's out of range for the native side, and because we're only coping ARRAY_SIZE(native.__bits), we'll end up trimming those off and losing the information. Are we ok with that? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll add a check when sizeof(pal) > sizeof(native) that will look at the bits from the end of pal until the end of native and make sure they are all 0 so that we won't truncate data. If we would truncate, I'll set errno to EINVAL so it will bubble up to the managed layer |
||
return true; | ||
} | ||
|
||
extern "C" int32_t SchedSetAffinity(int32_t pid, CpuSetBits* mask) | ||
{ | ||
assert(mask != nullptr); | ||
cpu_set_t set = {}; | ||
if (!ConvertPalToNativeCpuSet(*mask, set)) | ||
{ | ||
errno = EINVAL; | ||
return -1; | ||
} | ||
return sched_setaffinity(pid, sizeof(cpu_set_t), &set); | ||
} | ||
#endif | ||
|
||
#if HAVE_SCHED_GETAFFINITY | ||
static void ConvertNativeToPalCpuSet(const cpu_set_t& native, CpuSetBits& pal) | ||
{ | ||
pal = {}; | ||
memcpy(pal.Bits, native.__bits, ARRAY_SIZE(native.__bits)); | ||
} | ||
|
||
extern "C" int32_t SchedGetAffinity(int32_t pid, CpuSetBits* mask) | ||
{ | ||
assert(mask != nullptr); | ||
cpu_set_t set; | ||
int32_t result = sched_getaffinity(pid, sizeof(cpu_set_t), &set); | ||
if (result == 0) | ||
{ | ||
ConvertNativeToPalCpuSet(set, *mask); | ||
} | ||
|
||
return result; | ||
} | ||
#endif | ||
|
||
#if HAVE_SCHED_GETAFFINITY || HAVE_SCHED_SETAFFINITY | ||
extern "C" void CpuSet(int32_t cpu, CpuSetBits* set) | ||
{ | ||
set->Bits[__CPUELT(cpu)] |= __CPUMASK(cpu); | ||
} | ||
|
||
extern "C" bool CpuIsSet(int32_t cpu, CpuSetBits* set) | ||
{ | ||
return (set->Bits[__CPUELT(cpu)] & __CPUMASK(cpu)) != 0; | ||
} | ||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One more thought. Since the Bits field is never used and is here purely to impact the size of the struct, you could just add a StructLayout attribute to the type to set its size to 128. Then the type wouldn't need to be unsafe. But if you'd prefer to stick with what you have, that's fine, though you might chaynge the visibility of Bits to be private.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll change the field to be private so that it's still visible what the struct contains and how it fits with the native implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok.