(root)/
glibc-2.38/
sysdeps/
unix/
sysv/
linux/
tst-affinity-pid.c
       1  /* Test for sched_getaffinity and sched_setaffinity, PID version.
       2     Copyright (C) 2015-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  /* Function definitions for the benefit of tst-skeleton-affinity.c.
      20     This variant forks a child process which then invokes
      21     sched_getaffinity and sched_setaffinity on the parent PID.  */
      22  
      23  #include <errno.h>
      24  #include <stdlib.h>
      25  #include <sched.h>
      26  #include <stdbool.h>
      27  #include <stdio.h>
      28  #include <stdlib.h>
      29  #include <sys/wait.h>
      30  #include <unistd.h>
      31  
      32  static int
      33  write_fully (int fd, const void *buffer, size_t length)
      34  {
      35    const void *end = buffer + length;
      36    while (buffer < end)
      37      {
      38        ssize_t bytes_written = TEMP_FAILURE_RETRY
      39          (write (fd, buffer, end - buffer));
      40        if (bytes_written < 0)
      41          return -1;
      42        if (bytes_written == 0)
      43          {
      44            errno = ENOSPC;
      45            return -1;
      46          }
      47        buffer += bytes_written;
      48      }
      49    return 0;
      50  }
      51  
      52  static ssize_t
      53  read_fully (int fd, void *buffer, size_t length)
      54  {
      55    const void *start = buffer;
      56    const void *end = buffer + length;
      57    while (buffer < end)
      58      {
      59        ssize_t bytes_read = TEMP_FAILURE_RETRY
      60          (read (fd, buffer, end - buffer));
      61        if (bytes_read < 0)
      62          return -1;
      63        if (bytes_read == 0)
      64          return buffer - start;
      65        buffer += bytes_read;
      66      }
      67    return length;
      68  }
      69  
      70  static int
      71  process_child_response (int *pipes, pid_t child,
      72                          cpu_set_t *set, size_t size)
      73  {
      74    close (pipes[1]);
      75  
      76    int value_from_child;
      77    ssize_t bytes_read = read_fully
      78      (pipes[0], &value_from_child, sizeof (value_from_child));
      79    if (bytes_read < 0)
      80      {
      81        printf ("error: read from child: %m\n");
      82        exit (1);
      83      }
      84    if (bytes_read != sizeof (value_from_child))
      85      {
      86        printf ("error: not enough bytes from child: %zd\n", bytes_read);
      87        exit (1);
      88      }
      89    if (value_from_child == 0)
      90      {
      91        bytes_read = read_fully (pipes[0], set, size);
      92        if (bytes_read < 0)
      93          {
      94            printf ("error: read: %m\n");
      95            exit (1);
      96          }
      97        if (bytes_read != size)
      98          {
      99            printf ("error: not enough bytes from child: %zd\n", bytes_read);
     100            exit (1);
     101          }
     102      }
     103  
     104    int status;
     105    if (waitpid (child, &status, 0) < 0)
     106      {
     107        printf ("error: waitpid: %m\n");
     108        exit (1);
     109      }
     110    if (!(WIFEXITED (status) && WEXITSTATUS (status) == 0))
     111      {
     112        printf ("error: invalid status from : %m\n");
     113        exit (1);
     114      }
     115  
     116    close (pipes[0]);
     117  
     118    if (value_from_child != 0)
     119      {
     120        errno = value_from_child;
     121        return -1;
     122      }
     123    return 0;
     124  }
     125  
     126  static int
     127  getaffinity (size_t size, cpu_set_t *set)
     128  {
     129    int pipes[2];
     130    if (pipe (pipes) < 0)
     131      {
     132        printf ("error: pipe: %m\n");
     133        exit (1);
     134      }
     135  
     136    int ret = fork ();
     137    if (ret < 0)
     138      {
     139        printf ("error: fork: %m\n");
     140        exit (1);
     141      }
     142    if (ret == 0)
     143      {
     144        /* Child.  */
     145        int ret = sched_getaffinity (getppid (), size, set);
     146        if (ret < 0)
     147          ret = errno;
     148        if (write_fully (pipes[1], &ret, sizeof (ret)) < 0
     149            || write_fully (pipes[1], set, size) < 0
     150            || (ret == 0 && write_fully (pipes[1], set, size) < 0))
     151          {
     152            printf ("error: write: %m\n");
     153            _exit (1);
     154          }
     155        _exit (0);
     156      }
     157  
     158    /* Parent.  */
     159    return process_child_response (pipes, ret, set, size);
     160  }
     161  
     162  static int
     163  setaffinity (size_t size, const cpu_set_t *set)
     164  {
     165    int pipes[2];
     166    if (pipe (pipes) < 0)
     167      {
     168        printf ("error: pipe: %m\n");
     169        exit (1);
     170      }
     171  
     172    int ret = fork ();
     173    if (ret < 0)
     174      {
     175        printf ("error: fork: %m\n");
     176        exit (1);
     177      }
     178    if (ret == 0)
     179      {
     180        /* Child.  */
     181        int ret = sched_setaffinity (getppid (), size, set);
     182        if (write_fully (pipes[1], &ret, sizeof (ret)) < 0)
     183          {
     184            printf ("error: write: %m\n");
     185            _exit (1);
     186          }
     187        _exit (0);
     188      }
     189  
     190    /* Parent.  There is no affinity mask to read from the child, so the
     191       size is 0.  */
     192    return process_child_response (pipes, ret, NULL, 0);
     193  }
     194  
     195  struct conf;
     196  static bool early_test (struct conf *unused)
     197  {
     198    return true;
     199  }
     200  
     201  #include "tst-skeleton-affinity.c"