(root)/
glibc-2.38/
rt/
tst-cpuclock2.c
       1  /* Test program for process and thread CPU clocks.
       2     Copyright (C) 2005-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 <unistd.h>
      20  #include <stdint.h>
      21  
      22  #if (_POSIX_THREADS - 0) <= 0
      23  
      24  static int
      25  do_test ()
      26  {
      27    return 0;
      28  }
      29  
      30  #else
      31  
      32  #include <stdio.h>
      33  #include <stdlib.h>
      34  #include <time.h>
      35  #include <fcntl.h>
      36  #include <string.h>
      37  #include <errno.h>
      38  #include <pthread.h>
      39  
      40  #include <support/xunistd.h>
      41  
      42  static pthread_barrier_t barrier;
      43  
      44  /* This function is intended to rack up both user and system time.  */
      45  static void *
      46  chew_cpu (void *arg)
      47  {
      48    pthread_barrier_wait (&barrier);
      49  
      50    while (1)
      51      {
      52        static volatile char buf[4096];
      53        for (int i = 0; i < 100; ++i)
      54  	for (size_t j = 0; j < sizeof buf; ++j)
      55  	  buf[j] = 0xaa;
      56        int nullfd = open ("/dev/null", O_WRONLY);
      57        for (int i = 0; i < 100; ++i)
      58  	for (size_t j = 0; j < sizeof buf; ++j)
      59  	  buf[j] = 0xbb;
      60        xwrite (nullfd, (char *) buf, sizeof buf);
      61        close (nullfd);
      62      }
      63  
      64    return NULL;
      65  }
      66  
      67  static void
      68  test_nanosleep (clockid_t clock, const char *which,
      69  		int *bad)
      70  {
      71    const struct timespec sleeptime = { .tv_nsec = 100000000 };
      72    int e = clock_nanosleep (clock, 0, &sleeptime, NULL);
      73    if (e == EINVAL || e == ENOTSUP || e == ENOSYS)
      74      {
      75        printf ("clock_nanosleep not supported for %s CPU clock: %s\n",
      76  	      which, strerror (e));
      77        return;
      78      }
      79    if (e != 0)
      80      {
      81        printf ("clock_nanosleep on %s CPU clock: %s\n", which, strerror (e));
      82        *bad = 1;
      83        return;
      84      }
      85  
      86    struct timespec after;
      87    if (clock_gettime (clock, &after) < 0)
      88      {
      89        printf ("clock_gettime on %s CPU clock %lx => %s\n",
      90  	      which, (unsigned long int) clock, strerror (errno));
      91        *bad = 1;
      92        return;
      93      }
      94  
      95    struct timespec sleeptimeabs = sleeptime;
      96    sleeptimeabs.tv_sec += after.tv_sec;
      97    sleeptimeabs.tv_nsec += after.tv_nsec;
      98    while (sleeptimeabs.tv_nsec >= 1000000000)
      99      {
     100        ++sleeptimeabs.tv_sec;
     101        sleeptimeabs.tv_nsec -= 1000000000;
     102      }
     103    e = clock_nanosleep (clock, TIMER_ABSTIME, &sleeptimeabs, NULL);
     104    if (e != 0)
     105      {
     106        printf ("absolute clock_nanosleep on %s CPU clock: %s\n",
     107  	      which, strerror (e));
     108        *bad = 1;
     109        return;
     110      }
     111  
     112    struct timespec afterabs;
     113    if (clock_gettime (clock, &afterabs) < 0)
     114      {
     115        printf ("clock_gettime on %s CPU clock %lx => %s\n",
     116  	      which, (unsigned long int) clock, strerror (errno));
     117        *bad = 1;
     118        return;
     119      }
     120  
     121    return;
     122  }
     123  
     124  
     125  
     126  static int
     127  do_test (void)
     128  {
     129    int result = 0;
     130    clockid_t process_clock, th_clock, my_thread_clock;
     131    int e;
     132    pthread_t th;
     133  
     134    e = clock_getcpuclockid (0, &process_clock);
     135    if (e != 0)
     136      {
     137        printf ("clock_getcpuclockid on self => %s\n", strerror (e));
     138        return 1;
     139      }
     140  
     141    e = pthread_getcpuclockid (pthread_self (), &my_thread_clock);
     142    if (e != 0)
     143      {
     144        printf ("pthread_getcpuclockid on self => %s\n", strerror (e));
     145        return 1;
     146      }
     147  
     148    /* This is a kludge.  This test fails if the semantics of thread and
     149       process clocks are wrong.  The old code using hp-timing without kernel
     150       support has bogus semantics if there are context switches.  We don't
     151       fail to report failure when the proper functionality is not available
     152       in the kernel.  It so happens that Linux kernels without correct CPU
     153       clock support also lack CPU timer support, so we use use that to guess
     154       that we are using the bogus code and not test it.  */
     155    timer_t t;
     156    if (timer_create (my_thread_clock, NULL, &t) != 0)
     157      {
     158        printf ("timer_create: %m\n");
     159        puts ("No support for CPU clocks with good semantics, skipping test");
     160        return 0;
     161      }
     162    timer_delete (t);
     163  
     164  
     165    pthread_barrier_init (&barrier, NULL, 2);
     166  
     167    e = pthread_create (&th, NULL, chew_cpu, NULL);
     168    if (e != 0)
     169      {
     170        printf ("pthread_create: %s\n", strerror (e));
     171        return 1;
     172      }
     173  
     174    e = pthread_getcpuclockid (th, &th_clock);
     175    if (e == ENOENT || e == ENOSYS || e == ENOTSUP)
     176      {
     177        puts ("pthread_getcpuclockid does not support other threads");
     178        return 1;
     179      }
     180  
     181    pthread_barrier_wait (&barrier);
     182  
     183    struct timespec res;
     184    if (clock_getres (th_clock, &res) < 0)
     185      {
     186        printf ("clock_getres on live thread clock %lx => %s\n",
     187  	      (unsigned long int) th_clock, strerror (errno));
     188        result = 1;
     189        return 1;
     190      }
     191    printf ("live thread clock %lx resolution %ju.%.9ju\n",
     192  	  (unsigned long int) th_clock,
     193  	  (uintmax_t) res.tv_sec, (uintmax_t) res.tv_nsec);
     194  
     195    struct timespec process_before, process_after;
     196    if (clock_gettime (process_clock, &process_before) < 0)
     197      {
     198        printf ("clock_gettime on process clock %lx => %s\n",
     199  	      (unsigned long int) process_clock, strerror (errno));
     200        return 1;
     201      }
     202  
     203    struct timespec before, after;
     204    if (clock_gettime (th_clock, &before) < 0)
     205      {
     206        printf ("clock_gettime on live thread clock %lx => %s\n",
     207  	      (unsigned long int) th_clock, strerror (errno));
     208        return 1;
     209      }
     210    printf ("live thread before sleep => %ju.%.9ju\n",
     211  	  (uintmax_t) before.tv_sec, (uintmax_t) before.tv_nsec);
     212  
     213    struct timespec me_before, me_after;
     214    if (clock_gettime (my_thread_clock, &me_before) < 0)
     215      {
     216        printf ("clock_gettime on self thread clock %lx => %s\n",
     217  	      (unsigned long int) my_thread_clock, strerror (errno));
     218        return 1;
     219      }
     220    printf ("self thread before sleep => %ju.%.9ju\n",
     221  	  (uintmax_t) me_before.tv_sec, (uintmax_t) me_before.tv_nsec);
     222  
     223    struct timespec sleeptime = { .tv_nsec = 500000000 };
     224    if (nanosleep (&sleeptime, NULL) != 0)
     225      {
     226        perror ("nanosleep");
     227        return 1;
     228      }
     229  
     230    if (clock_gettime (th_clock, &after) < 0)
     231      {
     232        printf ("clock_gettime on live thread clock %lx => %s\n",
     233  	      (unsigned long int) th_clock, strerror (errno));
     234        return 1;
     235      }
     236    printf ("live thread after sleep => %ju.%.9ju\n",
     237  	  (uintmax_t) after.tv_sec, (uintmax_t) after.tv_nsec);
     238  
     239    if (clock_gettime (process_clock, &process_after) < 0)
     240      {
     241        printf ("clock_gettime on process clock %lx => %s\n",
     242  	      (unsigned long int) process_clock, strerror (errno));
     243        return 1;
     244      }
     245  
     246    if (clock_gettime (my_thread_clock, &me_after) < 0)
     247      {
     248        printf ("clock_gettime on self thread clock %lx => %s\n",
     249  	      (unsigned long int) my_thread_clock, strerror (errno));
     250        return 1;
     251      }
     252    printf ("self thread after sleep => %ju.%.9ju\n",
     253  	  (uintmax_t) me_after.tv_sec, (uintmax_t) me_after.tv_nsec);
     254  
     255    test_nanosleep (th_clock, "live thread",
     256  		  &result);
     257    test_nanosleep (process_clock, "process",
     258  		  &result);
     259    test_nanosleep (CLOCK_PROCESS_CPUTIME_ID,
     260  		  "PROCESS_CPUTIME_ID", &result);
     261  
     262    pthread_cancel (th);
     263  
     264    e = clock_nanosleep (CLOCK_THREAD_CPUTIME_ID, 0, &sleeptime, NULL);
     265    if (e != EINVAL)
     266      {
     267        printf ("clock_nanosleep CLOCK_THREAD_CPUTIME_ID: %s\n",
     268  	      strerror (e));
     269        result = 1;
     270      }
     271  
     272    return result;
     273  }
     274  #endif
     275  
     276  #include <support/test-driver.c>