/* Test for sched_getaffinity and sched_setaffinity, PID version. Copyright (C) 2015-2024 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see . */ /* Function definitions for the benefit of tst-skeleton-affinity.c. This variant forks a child process which then invokes sched_getaffinity and sched_setaffinity on the parent PID. */ #include #include #include #include #include #include #include #include static int write_fully (int fd, const void *buffer, size_t length) { const void *end = buffer + length; while (buffer < end) { ssize_t bytes_written = TEMP_FAILURE_RETRY (write (fd, buffer, end - buffer)); if (bytes_written < 0) return -1; if (bytes_written == 0) { errno = ENOSPC; return -1; } buffer += bytes_written; } return 0; } static ssize_t read_fully (int fd, void *buffer, size_t length) { const void *start = buffer; const void *end = buffer + length; while (buffer < end) { ssize_t bytes_read = TEMP_FAILURE_RETRY (read (fd, buffer, end - buffer)); if (bytes_read < 0) return -1; if (bytes_read == 0) return buffer - start; buffer += bytes_read; } return length; } static int process_child_response (int *pipes, pid_t child, cpu_set_t *set, size_t size) { close (pipes[1]); int value_from_child; ssize_t bytes_read = read_fully (pipes[0], &value_from_child, sizeof (value_from_child)); if (bytes_read < 0) { printf ("error: read from child: %m\n"); exit (1); } if (bytes_read != sizeof (value_from_child)) { printf ("error: not enough bytes from child: %zd\n", bytes_read); exit (1); } if (value_from_child == 0) { bytes_read = read_fully (pipes[0], set, size); if (bytes_read < 0) { printf ("error: read: %m\n"); exit (1); } if (bytes_read != size) { printf ("error: not enough bytes from child: %zd\n", bytes_read); exit (1); } } int status; if (waitpid (child, &status, 0) < 0) { printf ("error: waitpid: %m\n"); exit (1); } if (!(WIFEXITED (status) && WEXITSTATUS (status) == 0)) { printf ("error: invalid status from : %m\n"); exit (1); } close (pipes[0]); if (value_from_child != 0) { errno = value_from_child; return -1; } return 0; } static int getaffinity (size_t size, cpu_set_t *set) { int pipes[2]; if (pipe (pipes) < 0) { printf ("error: pipe: %m\n"); exit (1); } int ret = fork (); if (ret < 0) { printf ("error: fork: %m\n"); exit (1); } if (ret == 0) { /* Child. */ int ret = sched_getaffinity (getppid (), size, set); if (ret < 0) ret = errno; if (write_fully (pipes[1], &ret, sizeof (ret)) < 0 || write_fully (pipes[1], set, size) < 0 || (ret == 0 && write_fully (pipes[1], set, size) < 0)) { printf ("error: write: %m\n"); _exit (1); } _exit (0); } /* Parent. */ return process_child_response (pipes, ret, set, size); } static int setaffinity (size_t size, const cpu_set_t *set) { int pipes[2]; if (pipe (pipes) < 0) { printf ("error: pipe: %m\n"); exit (1); } int ret = fork (); if (ret < 0) { printf ("error: fork: %m\n"); exit (1); } if (ret == 0) { /* Child. */ int ret = sched_setaffinity (getppid (), size, set); if (write_fully (pipes[1], &ret, sizeof (ret)) < 0) { printf ("error: write: %m\n"); _exit (1); } _exit (0); } /* Parent. There is no affinity mask to read from the child, so the size is 0. */ return process_child_response (pipes, ret, NULL, 0); } struct conf; static bool early_test (struct conf *unused) { return true; } #include "tst-skeleton-affinity.c"