diff options
Diffstat (limited to 'sysdeps/unix/sysv/linux/tst-affinity-pid.c')
-rw-r--r-- | sysdeps/unix/sysv/linux/tst-affinity-pid.c | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/sysdeps/unix/sysv/linux/tst-affinity-pid.c b/sysdeps/unix/sysv/linux/tst-affinity-pid.c new file mode 100644 index 0000000000..309f1add6a --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-affinity-pid.c @@ -0,0 +1,201 @@ +/* Test for sched_getaffinity and sched_setaffinity, PID version. + Copyright (C) 2015 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 + <http://www.gnu.org/licenses/>. */ + +/* 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 <errno.h> +#include <stdlib.h> +#include <sched.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <unistd.h> + +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" |