Back to index

glibc  2.9
tst-cpuclock1.c
Go to the documentation of this file.
00001 /* Test program for process CPU clocks.
00002    Copyright (C) 2004 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <stdio.h>
00021 #include <stdlib.h>
00022 #include <time.h>
00023 #include <unistd.h>
00024 #include <fcntl.h>
00025 #include <string.h>
00026 #include <errno.h>
00027 #include <signal.h>
00028 #include <sys/wait.h>
00029 
00030 /* This function is intended to rack up both user and system time.  */
00031 static void
00032 chew_cpu (void)
00033 {
00034   while (1)
00035     {
00036       static volatile char buf[4096];
00037       for (int i = 0; i < 100; ++i)
00038        for (size_t j = 0; j < sizeof buf; ++j)
00039          buf[j] = 0xaa;
00040       int nullfd = open ("/dev/null", O_WRONLY);
00041       for (int i = 0; i < 100; ++i)
00042        for (size_t j = 0; j < sizeof buf; ++j)
00043          buf[j] = 0xbb;
00044       write (nullfd, (char *) buf, sizeof buf);
00045       close (nullfd);
00046       if (getppid () == 1)
00047        _exit (2);
00048     }
00049 }
00050 
00051 static int
00052 do_test (void)
00053 {
00054   int result = 0;
00055   clockid_t cl;
00056   int e;
00057   pid_t dead_child, child;
00058 
00059   /* Fork a child and let it die, to give us a PID known not be valid
00060      (assuming PIDs don't wrap around during the test).  */
00061   {
00062     dead_child = fork ();
00063     if (dead_child == 0)
00064       _exit (0);
00065     if (dead_child < 0)
00066       {
00067        perror ("fork");
00068        return 1;
00069       }
00070     int x;
00071     if (wait (&x) != dead_child)
00072       {
00073        perror ("wait");
00074        return 2;
00075       }
00076   }
00077 
00078   /* POSIX says we should get ESRCH for this.  */
00079   e = clock_getcpuclockid (dead_child, &cl);
00080   if (e != ENOSYS && e != ESRCH && e != EPERM)
00081     {
00082       printf ("clock_getcpuclockid on dead PID %d => %s\n",
00083              dead_child, strerror (e));
00084       result = 1;
00085     }
00086 
00087   /* Now give us a live child eating up CPU time.  */
00088   child = fork ();
00089   if (child == 0)
00090     {
00091       chew_cpu ();
00092       _exit (1);
00093     }
00094   if (child < 0)
00095     {
00096       perror ("fork");
00097       return 1;
00098     }
00099 
00100   e = clock_getcpuclockid (child, &cl);
00101   if (e == EPERM)
00102     {
00103       puts ("clock_getcpuclockid does not support other processes");
00104       goto done;
00105     }
00106   if (e != 0)
00107     {
00108       printf ("clock_getcpuclockid on live PID %d => %s\n",
00109              child, strerror (e));
00110       result = 1;
00111       goto done;
00112     }
00113 
00114   const clockid_t child_clock = cl;
00115   struct timespec res;
00116   if (clock_getres (child_clock, &res) < 0)
00117     {
00118       printf ("clock_getres on live PID %d clock %lx => %s\n",
00119              child, (unsigned long int) child_clock, strerror (errno));
00120       result = 1;
00121       goto done;
00122     }
00123   printf ("live PID %d clock %lx resolution %lu.%.9lu\n",
00124          child, (unsigned long int) child_clock, res.tv_sec, res.tv_nsec);
00125 
00126   struct timespec before, after;
00127   if (clock_gettime (child_clock, &before) < 0)
00128     {
00129       printf ("clock_gettime on live PID %d clock %lx => %s\n",
00130              child, (unsigned long int) child_clock, strerror (errno));
00131       result = 1;
00132       goto done;
00133     }
00134   printf ("live PID %d before sleep => %lu.%.9lu\n",
00135          child, before.tv_sec, before.tv_nsec);
00136 
00137   struct timespec sleeptime = { .tv_nsec = 500000000 };
00138   nanosleep (&sleeptime, NULL);
00139 
00140   if (clock_gettime (child_clock, &after) < 0)
00141     {
00142       printf ("clock_gettime on live PID %d clock %lx => %s\n",
00143              child, (unsigned long int) child_clock, strerror (errno));
00144       result = 1;
00145       goto done;
00146     }
00147   printf ("live PID %d after sleep => %lu.%.9lu\n",
00148          child, after.tv_sec, after.tv_nsec);
00149 
00150   struct timespec diff = { .tv_sec = after.tv_sec - before.tv_sec,
00151                         .tv_nsec = after.tv_nsec - before.tv_nsec };
00152   if (diff.tv_nsec < 0)
00153     {
00154       --diff.tv_sec;
00155       diff.tv_nsec += 1000000000;
00156     }
00157   if (diff.tv_sec != 0
00158       || diff.tv_nsec > 600000000
00159       || diff.tv_nsec < 100000000)
00160     {
00161       printf ("before - after %lu.%.9lu outside reasonable range\n",
00162              diff.tv_sec, diff.tv_nsec);
00163       result = 1;
00164     }
00165 
00166   sleeptime.tv_nsec = 100000000;
00167   e = clock_nanosleep (child_clock, 0, &sleeptime, NULL);
00168   if (e == EINVAL || e == ENOTSUP || e == ENOSYS)
00169     {
00170       printf ("clock_nanosleep not supported for other process clock: %s\n",
00171              strerror (e));
00172     }
00173   else if (e != 0)
00174     {
00175       printf ("clock_nanosleep on other process clock: %s\n", strerror (e));
00176       result = 1;
00177     }
00178   else
00179     {
00180       struct timespec afterns;
00181       if (clock_gettime (child_clock, &afterns) < 0)
00182        {
00183          printf ("clock_gettime on live PID %d clock %lx => %s\n",
00184                 child, (unsigned long int) child_clock, strerror (errno));
00185          result = 1;
00186        }
00187       else
00188        {
00189          struct timespec d = { .tv_sec = afterns.tv_sec - after.tv_sec,
00190                             .tv_nsec = afterns.tv_nsec - after.tv_nsec };
00191          if (d.tv_nsec < 0)
00192            {
00193              --d.tv_sec;
00194              d.tv_nsec += 1000000000;
00195            }
00196          if (d.tv_sec > 0
00197              || d.tv_nsec < sleeptime.tv_nsec
00198              || d.tv_nsec > sleeptime.tv_nsec * 2)
00199            {
00200              printf ("nanosleep time %lu.%.9lu outside reasonable range\n",
00201                     d.tv_sec, d.tv_nsec);
00202              result = 1;
00203            }
00204        }
00205     }
00206 
00207   if (kill (child, SIGKILL) != 0)
00208     {
00209       perror ("kill");
00210       result = 2;
00211       goto done;
00212     }
00213 
00214   /* Wait long enough to let the child finish dying.  */
00215 
00216   sleeptime.tv_nsec = 200000000;
00217   nanosleep (&sleeptime, NULL);
00218 
00219   struct timespec dead;
00220   if (clock_gettime (child_clock, &dead) < 0)
00221     {
00222       printf ("clock_gettime on dead PID %d clock %lx => %s\n",
00223              child, (unsigned long int) child_clock, strerror (errno));
00224       result = 1;
00225       goto done;
00226     }
00227   printf ("dead PID %d => %lu.%.9lu\n",
00228          child, dead.tv_sec, dead.tv_nsec);
00229 
00230   diff.tv_sec = dead.tv_sec - after.tv_sec;
00231   diff.tv_nsec = dead.tv_nsec - after.tv_nsec;
00232   if (diff.tv_nsec < 0)
00233     {
00234       --diff.tv_sec;
00235       diff.tv_nsec += 1000000000;
00236     }
00237   if (diff.tv_sec != 0 || diff.tv_nsec > 200000000)
00238     {
00239       printf ("dead - after %lu.%.9lu outside reasonable range\n",
00240              diff.tv_sec, diff.tv_nsec);
00241       result = 1;
00242     }
00243 
00244   /* Now reap the child and verify that its clock is no longer valid.  */
00245   {
00246     int x;
00247     if (waitpid (child, &x, 0) != child)
00248       {
00249        perror ("waitpid");
00250        result = 1;
00251       }
00252   }
00253 
00254   if (clock_gettime (child_clock, &dead) == 0)
00255     {
00256       printf ("clock_gettime on reaped PID %d clock %lx => %lu%.9lu\n",
00257              child, (unsigned long int) child_clock,
00258              dead.tv_sec, dead.tv_nsec);
00259       result = 1;
00260     }
00261   else
00262     {
00263       if (errno != EINVAL)
00264        result = 1;
00265       printf ("clock_gettime on reaped PID %d clock %lx => %s\n",
00266              child, (unsigned long int) child_clock, strerror (errno));
00267     }
00268 
00269   if (clock_getres (child_clock, &dead) == 0)
00270     {
00271       printf ("clock_getres on reaped PID %d clock %lx => %lu%.9lu\n",
00272              child, (unsigned long int) child_clock,
00273              dead.tv_sec, dead.tv_nsec);
00274       result = 1;
00275     }
00276   else
00277     {
00278       if (errno != EINVAL)
00279        result = 1;
00280       printf ("clock_getres on reaped PID %d clock %lx => %s\n",
00281              child, (unsigned long int) child_clock, strerror (errno));
00282     }
00283 
00284   return result;
00285 
00286  done:
00287   {
00288     if (kill (child, SIGKILL) != 0 && errno != ESRCH)
00289       {
00290        perror ("kill");
00291        return 2;
00292       }
00293     int x;
00294     if (waitpid (child, &x, 0) != child && errno != ECHILD)
00295       {
00296        perror ("waitpid");
00297        return 2;
00298       }
00299   }
00300 
00301   return result;
00302 }
00303 
00304 
00305 #define TIMEOUT 5
00306 #define TEST_FUNCTION do_test ()
00307 #include "../test-skeleton.c"