(root)/
glibc-2.38/
nptl/
tst-clock2.c
       1  /* Copyright (C) 2003-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <errno.h>
      19  #include <pthread.h>
      20  #include <stdio.h>
      21  #include <stdlib.h>
      22  #include <time.h>
      23  #include <unistd.h>
      24  
      25  
      26  #if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0
      27  static pthread_barrier_t b2;
      28  static pthread_barrier_t bN;
      29  
      30  
      31  static void *
      32  tf (void *arg)
      33  {
      34    int e = pthread_barrier_wait (&b2);
      35    if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
      36      {
      37        puts ("barrier_wait failed");
      38        exit (1);
      39      }
      40  
      41    e = pthread_barrier_wait (&bN);
      42    if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
      43      {
      44        puts ("barrier_wait failed");
      45        exit (1);
      46      }
      47  
      48    return NULL;
      49  }
      50  #endif
      51  
      52  
      53  int
      54  do_test (void)
      55  {
      56  #if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0
      57  # define N 10
      58  
      59  # if _POSIX_THREAD_CPUTIME == 0
      60    if (sysconf (_SC_THREAD_CPUTIME) < 0)
      61      {
      62        puts ("_POSIX_THREAD_CPUTIME option not available");
      63        return 0;
      64      }
      65  # endif
      66  
      67    if (pthread_barrier_init (&b2, NULL, 2) != 0
      68        || pthread_barrier_init (&bN, NULL, N + 1) != 0)
      69      {
      70        puts ("barrier_init failed");
      71        return 1;
      72      }
      73  
      74    struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 };
      75    TEMP_FAILURE_RETRY (nanosleep (&ts, &ts));
      76  
      77    pthread_t th[N + 1];
      78    clockid_t cl[N + 1];
      79  # ifndef CLOCK_THREAD_CPUTIME_ID
      80    if (pthread_getcpuclockid (pthread_self (), &cl[0]) != 0)
      81      {
      82        puts ("own pthread_getcpuclockid failed");
      83        return 1;
      84      }
      85  # else
      86    cl[0] = CLOCK_THREAD_CPUTIME_ID;
      87  # endif
      88  
      89    pthread_attr_t at;
      90  
      91    if (pthread_attr_init (&at) != 0)
      92      {
      93        puts ("attr_init failed");
      94        return 1;
      95      }
      96  
      97    if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0)
      98      {
      99        puts ("attr_setstacksize failed");
     100        return 1;
     101      }
     102  
     103    int i;
     104    int e;
     105    for (i = 0; i < N; ++i)
     106      {
     107        if (pthread_create (&th[i], &at, tf, NULL) != 0)
     108  	{
     109  	  puts ("create failed");
     110  	  return 1;
     111  	}
     112  
     113        e = pthread_barrier_wait (&b2);
     114        if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
     115  	{
     116  	  puts ("barrier_wait failed");
     117  	  return 1;
     118  	}
     119  
     120        ts.tv_sec = 0;
     121        ts.tv_nsec = 100000000;
     122        TEMP_FAILURE_RETRY (nanosleep (&ts, &ts));
     123  
     124        if (pthread_getcpuclockid (th[i], &cl[i + 1]) != 0)
     125  	{
     126  	  puts ("pthread_getcpuclockid failed");
     127  	  return 1;
     128  	}
     129      }
     130  
     131    if (pthread_attr_destroy (&at) != 0)
     132      {
     133        puts ("attr_destroy failed");
     134        return 1;
     135      }
     136  
     137    struct timespec t[N + 1];
     138    for (i = 0; i < N + 1; ++i)
     139      if (clock_gettime (cl[i], &t[i]) != 0)
     140        {
     141  	printf ("clock_gettime round %d failed\n", i);
     142  	return 1;
     143        }
     144  
     145    for (i = 0; i < N; ++i)
     146      {
     147        struct timespec diff;
     148  
     149        diff.tv_sec = t[i].tv_sec - t[i + 1].tv_sec;
     150        diff.tv_nsec = t[i].tv_nsec - t[i + 1].tv_nsec;
     151        if (diff.tv_nsec < 0)
     152  	{
     153  	  diff.tv_nsec += 1000000000;
     154  	  --diff.tv_sec;
     155  	}
     156  
     157        if (diff.tv_sec < 0 || (diff.tv_sec == 0 && diff.tv_nsec < 100000000))
     158  	{
     159  	  printf ("\
     160  difference between thread %d and %d too small (%ld.%09ld)\n",
     161  		  i, i + 1, (long int) diff.tv_sec, (long int) diff.tv_nsec);
     162  	  return 1;
     163  	}
     164  
     165        printf ("diff %d->%d: %ld.%09ld\n",
     166  	      i, i + 1, (long int) diff.tv_sec, (long int) diff.tv_nsec);
     167      }
     168  
     169    ts.tv_sec = 0;
     170    ts.tv_nsec = 0;
     171    for (i = 0; i < N + 1; ++i)
     172      if (clock_settime (cl[i], &ts) != 0)
     173        {
     174  	printf ("clock_settime(%d) round %d failed\n", cl[i], i);
     175  	return 1;
     176        }
     177  
     178    for (i = 0; i < N + 1; ++i)
     179      {
     180        if (clock_gettime (cl[i], &ts) != 0)
     181  	{
     182  	  puts ("clock_gettime failed");
     183  	  return 1;
     184  	}
     185  
     186        if (ts.tv_sec > t[i].tv_sec
     187  	  || (ts.tv_sec == t[i].tv_sec && ts.tv_nsec > t[i].tv_nsec))
     188  	{
     189  	  puts ("clock_settime didn't reset clock");
     190  	  return 1;
     191  	}
     192      }
     193  #endif
     194  
     195    return 0;
     196  }
     197  
     198  
     199  #define TEST_FUNCTION do_test ()
     200  #include "../test-skeleton.c"