[v3,0/7] Fix some libm static issues
[platform/upstream/glibc.git] / time / tst-cpuclock1.c
1 /* Test program for process CPU clocks.
2    Copyright (C) 2004-2024 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"