1 /* Tests for POSIX timer implementation using another process's CPU clock.  */
2 
3 #include <unistd.h>
4 
5 #if _POSIX_THREADS && defined _POSIX_CPUTIME
6 
7 #include <errno.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <fcntl.h>
12 #include <time.h>
13 #include <signal.h>
14 #include <sys/wait.h>
15 
16 static clockid_t child_clock;
17 
18 #define TEST_CLOCK child_clock
19 #define TEST_CLOCK_MISSING(clock) \
20   (setup_test () ? "other-process CPU clock timer support" : NULL)
21 
22 /* This function is intended to rack up both user and system time.  */
23 static void
chew_cpu(void)24 chew_cpu (void)
25 {
26   while (1)
27     {
28       static volatile char buf[4096];
29       for (int i = 0; i < 100; ++i)
30 	for (size_t j = 0; j < sizeof buf; ++j)
31 	  buf[j] = 0xaa;
32       int nullfd = open ("/dev/null", O_WRONLY);
33       for (int i = 0; i < 100; ++i)
34 	for (size_t j = 0; j < sizeof buf; ++j)
35 	  buf[j] = 0xbb;
36       write (nullfd, (char *) buf, sizeof buf);
37       close (nullfd);
38       if (getppid () == 1)
39 	_exit (2);
40     }
41 }
42 
43 static pid_t child;
44 static void
cleanup_child(void)45 cleanup_child (void)
46 {
47   if (child <= 0)
48     return;
49   if (kill (child, SIGKILL) < 0 && errno != ESRCH)
50     printf ("cannot kill child %d: %m\n", child);
51   else
52     {
53       int status;
54       errno = 0;
55       if (waitpid (child, &status, 0) != child)
56 	printf ("waitpid %d: %m\n", child);
57     }
58 }
59 #define CLEANUP_HANDLER cleanup_child ()
60 
61 static int
setup_test(void)62 setup_test (void)
63 {
64   /* Test timers on a process CPU clock by having a child process eating
65      CPU.  First make sure we can make such timers at all.  */
66 
67   int pipefd[2];
68   if (pipe (pipefd) < 0)
69     {
70       printf ("pipe: %m\n");
71       exit (1);
72     }
73 
74   child = fork ();
75 
76   if (child == 0)
77     {
78       char c;
79       close (pipefd[1]);
80       if (read (pipefd[0], &c, 1) == 1)
81 	chew_cpu ();
82       _exit (1);
83     }
84 
85   if (child < 0)
86     {
87       printf ("fork: %m\n");
88       exit (1);
89     }
90 
91   atexit (&cleanup_child);
92 
93   close (pipefd[0]);
94 
95   int e = clock_getcpuclockid (child, &child_clock);
96   if (e == EPERM)
97     {
98       puts ("clock_getcpuclockid does not support other processes");
99       return 1;
100     }
101   if (e != 0)
102     {
103       printf ("clock_getcpuclockid: %s\n", strerror (e));
104       exit (1);
105     }
106 
107   timer_t t;
108   if (timer_create (TEST_CLOCK, NULL, &t) != 0)
109     {
110       printf ("timer_create: %m\n");
111       return 1;
112     }
113   timer_delete (t);
114 
115   /* Get the child started chewing.  */
116   if (write (pipefd[1], "x", 1) != 1)
117     {
118       printf ("write to pipe: %m\n");
119       return 1;
120     }
121   close (pipefd[1]);
122 
123   return 0;
124 }
125 
126 #else
127 # define TEST_CLOCK_MISSING(clock) "process clocks"
128 #endif
129 
130 #include "tst-timer4.c"
131