Re: git: e2650af157bc - main - Make CPU_SET macros compliant with other implementations
- Reply: Konstantin Belousov : "Re: git: e2650af157bc - main - Make CPU_SET macros compliant with other implementations"
- In reply to: Konstantin Belousov : "Re: git: e2650af157bc - main - Make CPU_SET macros compliant with other implementations"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 02 Jan 2022 23:35:39 UTC
Am 02.01.22 um 23:16 schrieb Konstantin Belousov:
> On Sun, Jan 02, 2022 at 10:45:14PM +0100, Stefan Esser wrote:
>> Am 02.01.22 um 20:51 schrieb Antoine Brodin:
[...]
>> Python 3.8.12 (default, Dec 31 2021, 10:50:47)
>>>>> import os
>>>>> os.sched_getaffinity(0)
>> Traceback (most recent call last):
>> File "<stdin>", line 1, in <module>
>> OSError: [Errno 34] Result too large
>>
>> This is a Python interpreter problem: it seems that the wrapper
>> for the sched_getaffinity() function that has been introduced by
>> kib in <sched.h> is buggy.
>>
>> As a work-around I have added a patch to comment out the
>> os.sched_getaffinity(0) call (which used to cause an Attribute
>> error that was caught by try/except, before).
>>
>> See ports commit 507c189b2876.
>
> Buggy in which way?
My assumption was that the wrapper in the Python interpreter in
Modules/posixmodules.c function os_sched_getaffinity_impl() does
not work with the FreeBSD implementation of sched_getaffinity().
The relevant code in the Python wrapper is:
ncpus = NCPUS_START;
while (1) {
setsize = CPU_ALLOC_SIZE(ncpus);
mask = CPU_ALLOC(ncpus);
if (mask == NULL)
return PyErr_NoMemory();
if (sched_getaffinity(pid, setsize, mask) == 0)
break;
CPU_FREE(mask);
if (errno != EINVAL)
return posix_error();
if (ncpus > INT_MAX / 2) {
PyErr_SetString(PyExc_OverflowError, "could not allocate "
"a large enough CPU set");
return NULL;
}
ncpus = ncpus * 2;
}
NCPUS_START is 8 * sizeof(unsigned long) = 64 on a 64 bit CPU.
> Our cpuset_getaffinity(2) syscall returns ERANGE for cpuset size not
> equal to CPU_SETSIZE. It seems that python source expects EINVAL in
> this case.
Yes, anything except EINVAL will cause the loop to exit prematurely.
> I can change the wrapper to translate ERANGE to EINVAL. sched_setaffinity()
> probably would require a symmetrical patch, but lets postpone it.
Yes.
> diff --git a/lib/libc/gen/sched_getaffinity.c b/lib/libc/gen/sched_getaffinity.c
> index 2ae8c5b763a3..8748d7a60278 100644
> --- a/lib/libc/gen/sched_getaffinity.c
> +++ b/lib/libc/gen/sched_getaffinity.c
> @@ -26,11 +26,29 @@
> * SUCH DAMAGE.
> */
>
> +#include <errno.h>
> #include <sched.h>
> +#include <string.h>
>
> int
> sched_getaffinity(pid_t pid, size_t cpusetsz, cpuset_t *cpuset)
> {
> + /*
> + * Be more Linux-compatible:
> + * - return EINVAL in passed size is less than size of cpuset_t
> + * in advance, instead of ERANGE from the syscall
> + * - if passed size is larger than the size of cpuset_t, be
> + * permissive by claming it back to sizeof(cpuset_t) and
> + * zeroing the rest.
> + */
> + if (cpusetsz < sizeof(cpuset_t))
> + return (EINVAL);
> + if (cpusetsz > sizeof(cpuset_t)) {
> + memset((char *)cpuset + sizeof(cpuset_t), 0,
> + cpusetsz - sizeof(cpuset_t));
> + cpusetsz = sizeof(cpuset_t);
> + }
> +
> return (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
> pid == 0 ? -1 : pid, cpusetsz, cpuset));
> }
I have rebuilt the C library with this patch, but it did not fix
the problem, since the value checked in the loop is errno, not
the return code of sched_getaffinity().
The following code is tested to work:
#include <errno.h>
#include <sched.h>
int
sched_getaffinity(pid_t pid, size_t cpusetsz, cpuset_t *cpuset)
{
int result;
result = cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
pid == 0 ? -1 : pid, cpusetsz, cpuset);
if (result && errno == ERANGE)
errno = EINVAL;
return (result);
}
Regards, STefan