(root)/
glibc-2.38/
time/
tst-cpuclock1.c
       1  /* Test program for process CPU clocks.
       2     Copyright (C) 2004-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  #include <stdio.h>
      20  #include <stdlib.h>
      21  #include <time.h>
      22  #include <unistd.h>
      23  #include <fcntl.h>
      24  #include <string.h>
      25  #include <errno.h>
      26  #include <signal.h>
      27  #include <stdint.h>
      28  #include <sys/wait.h>
      29  
      30  #include <support/xunistd.h>
      31  
      32  /* This function is intended to rack up both user and system time.  */
      33  static void
      34  chew_cpu (void)
      35  {
      36    while (1)
      37      {
      38        static volatile char buf[4096];
      39        for (int i = 0; i < 100; ++i)
      40  	for (size_t j = 0; j < sizeof buf; ++j)
      41  	  buf[j] = 0xaa;
      42        int nullfd = open ("/dev/null", O_WRONLY);
      43        for (int i = 0; i < 100; ++i)
      44  	for (size_t j = 0; j < sizeof buf; ++j)
      45  	  buf[j] = 0xbb;
      46        xwrite (nullfd, (char *) buf, sizeof buf);
      47        close (nullfd);
      48        if (getppid () == 1)
      49  	_exit (2);
      50      }
      51  }
      52  
      53  static int
      54  do_test (void)
      55  {
      56    int result = 0;
      57    clockid_t cl;
      58    int e;
      59    pid_t dead_child, child;
      60  
      61    /* Fork a child and let it die, to give us a PID known not be valid
      62       (assuming PIDs don't wrap around during the test).  */
      63    {
      64      dead_child = fork ();
      65      if (dead_child == 0)
      66        _exit (0);
      67      if (dead_child < 0)
      68        {
      69  	perror ("fork");
      70  	return 1;
      71        }
      72      int x;
      73      if (wait (&x) != dead_child)
      74        {
      75  	perror ("wait");
      76  	return 2;
      77        }
      78    }
      79  
      80    /* POSIX says we should get ESRCH for this.  */
      81    e = clock_getcpuclockid (dead_child, &cl);
      82    if (e != ENOSYS && e != ESRCH && e != EPERM)
      83      {
      84        printf ("clock_getcpuclockid on dead PID %d => %s\n",
      85  	      dead_child, strerror (e));
      86        result = 1;
      87      }
      88  
      89    /* Now give us a live child eating up CPU time.  */
      90    child = fork ();
      91    if (child == 0)
      92      {
      93        chew_cpu ();
      94        _exit (1);
      95      }
      96    if (child < 0)
      97      {
      98        perror ("fork");
      99        return 1;
     100      }
     101  
     102    e = clock_getcpuclockid (child, &cl);
     103    if (e == EPERM)
     104      {
     105        puts ("clock_getcpuclockid does not support other processes");
     106        goto done;
     107      }
     108    if (e != 0)
     109      {
     110        printf ("clock_getcpuclockid on live PID %d => %s\n",
     111  	      child, strerror (e));
     112        result = 1;
     113        goto done;
     114      }
     115  
     116    const clockid_t child_clock = cl;
     117    struct timespec res;
     118    if (clock_getres (child_clock, &res) < 0)
     119      {
     120        printf ("clock_getres on live PID %d clock %lx => %s\n",
     121  	      child, (unsigned long int) child_clock, strerror (errno));
     122        result = 1;
     123        goto done;
     124      }
     125    printf ("live PID %d clock %lx resolution %ju.%.9ju\n",
     126  	  child, (unsigned long int) child_clock,
     127  	  (uintmax_t) res.tv_sec, (uintmax_t) res.tv_nsec);
     128  
     129    struct timespec before;
     130    if (clock_gettime (child_clock, &before) < 0)
     131      {
     132        printf ("clock_gettime on live PID %d clock %lx => %s\n",
     133  	      child, (unsigned long int) child_clock, strerror (errno));
     134        result = 1;
     135        goto done;
     136      }
     137    /* Should be close to 0.0.  */
     138    printf ("live PID %d before sleep => %ju.%.9ju\n",
     139  	  child, (uintmax_t) before.tv_sec, (uintmax_t) before.tv_nsec);
     140  
     141    struct timespec sleeptime = { .tv_nsec = 100000000 };
     142    e = clock_nanosleep (child_clock, 0, &sleeptime, NULL);
     143    if (e == EINVAL || e == ENOTSUP || e == ENOSYS)
     144      {
     145        printf ("clock_nanosleep not supported for other process clock: %s\n",
     146  	      strerror (e));
     147      }
     148    else if (e != 0)
     149      {
     150        printf ("clock_nanosleep on other process clock: %s\n", strerror (e));
     151        result = 1;
     152      }
     153    else
     154      {
     155        struct timespec afterns;
     156        if (clock_gettime (child_clock, &afterns) < 0)
     157  	{
     158  	  printf ("clock_gettime on live PID %d clock %lx => %s\n",
     159  		  child, (unsigned long int) child_clock, strerror (errno));
     160  	  result = 1;
     161  	}
     162        else
     163  	{
     164  	  printf ("live PID %d after sleep => %ju.%.9ju\n",
     165  		  child, (uintmax_t) afterns.tv_sec,
     166  		  (uintmax_t) afterns.tv_nsec);
     167  	}
     168      }
     169  
     170    if (kill (child, SIGKILL) != 0)
     171      {
     172        perror ("kill");
     173        result = 2;
     174        goto done;
     175      }
     176  
     177    /* Wait long enough to let the child finish dying.  */
     178  
     179    sleeptime.tv_nsec = 200000000;
     180    if (nanosleep (&sleeptime, NULL) != 0)
     181      {
     182        perror ("nanosleep");
     183        result = 1;
     184        goto done;
     185      }
     186  
     187    struct timespec dead;
     188    if (clock_gettime (child_clock, &dead) < 0)
     189      {
     190        printf ("clock_gettime on dead PID %d clock %lx => %s\n",
     191  	      child, (unsigned long int) child_clock, strerror (errno));
     192        result = 1;
     193        goto done;
     194      }
     195    /* Should be close to 0.1.  */
     196    printf ("dead PID %d => %ju.%.9ju\n",
     197  	  child, (uintmax_t) dead.tv_sec, (uintmax_t) dead.tv_nsec);
     198  
     199    /* Now reap the child and verify that its clock is no longer valid.  */
     200    {
     201      int x;
     202      if (waitpid (child, &x, 0) != child)
     203        {
     204  	perror ("waitpid");
     205  	result = 1;
     206        }
     207    }
     208  
     209    if (clock_gettime (child_clock, &dead) == 0)
     210      {
     211        printf ("clock_gettime on reaped PID %d clock %lx => %ju%.9ju\n",
     212  	      child, (unsigned long int) child_clock,
     213  	      (uintmax_t) dead.tv_sec, (uintmax_t) dead.tv_nsec);
     214        result = 1;
     215      }
     216    else
     217      {
     218        if (errno != EINVAL)
     219  	result = 1;
     220        printf ("clock_gettime on reaped PID %d clock %lx => %s\n",
     221  	      child, (unsigned long int) child_clock, strerror (errno));
     222      }
     223  
     224    if (clock_getres (child_clock, &dead) == 0)
     225      {
     226        printf ("clock_getres on reaped PID %d clock %lx => %ju%.9ju\n",
     227  	      child, (unsigned long int) child_clock,
     228  	      (uintmax_t) dead.tv_sec, (uintmax_t) dead.tv_nsec);
     229        result = 1;
     230      }
     231    else
     232      {
     233        if (errno != EINVAL)
     234  	result = 1;
     235        printf ("clock_getres on reaped PID %d clock %lx => %s\n",
     236  	      child, (unsigned long int) child_clock, strerror (errno));
     237      }
     238  
     239    return result;
     240  
     241   done:
     242    {
     243      if (kill (child, SIGKILL) != 0 && errno != ESRCH)
     244        {
     245  	perror ("kill");
     246  	return 2;
     247        }
     248      int x;
     249      if (waitpid (child, &x, 0) != child && errno != ECHILD)
     250        {
     251  	perror ("waitpid");
     252  	return 2;
     253        }
     254    }
     255  
     256    return result;
     257  }
     258  
     259  
     260  #define TEST_FUNCTION do_test ()
     261  #include "../test-skeleton.c"