S390: Fix building with --disable-mutli-arch [BZ #31196]
[platform/upstream/glibc.git] / rt / tst-cpuclock2.c
1 /* Test program for process and thread CPU clocks.
2    Copyright (C) 2005-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 <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>