retire nonsymbolic rootdev, dev2name
[minix.git] / test / t40f.c
blobccdf7d61e9ff46a014e1866a34fe9173708dceee
1 /* t40f.c
3 * Test timing
5 * Select works on regular files, (pseudo) terminal devices, streams-based
6 * files, FIFOs, pipes, and sockets. This test verifies selecting with a time
7 * out set.
8 */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <sys/types.h>
14 #include <sys/select.h>
15 #include <sys/wait.h>
16 #include <sys/time.h>
17 #include <time.h>
18 #include <errno.h>
19 #include <string.h>
20 #include <signal.h>
22 #define DO_HANDLEDATA 1
23 #define DO_PAUSE 3
24 #define DO_TIMEOUT 7
25 #define DO_DELTA 0.5
26 #define MAX_ERROR 5
27 #define DELTA(x,y) (x.tv_sec - y.tv_sec) * CLOCKS_PER_SEC \
28 + (x.tv_usec - y.tv_usec) * CLOCKS_PER_SEC / 1000000
30 int errct = 0, subtest = -1, got_signal = 0;
31 int fd_ap[2];
33 void catch_signal(int sig_no) {
34 got_signal = 1;
37 void e(int n, char *s) {
38 printf("Subtest %d, error %d, %s\n", subtest, n, s);
40 if (errct++ > MAX_ERROR) {
41 printf("Too many errors; test aborted\n");
42 exit(errct);
46 float compute_diff(struct timeval start, struct timeval end, float compare) {
47 /* Compute time difference. It is assumed that the value of start <= end. */
48 clock_t delta;
49 int seconds, hundreths;
50 float diff;
52 delta = DELTA(end, start); /* delta is in ticks */
53 seconds = (int) (delta / CLOCKS_PER_SEC);
54 hundreths = (int) (delta * 100 / CLOCKS_PER_SEC) - (seconds * 100);
56 diff = seconds + (hundreths / 100.0);
57 diff -= compare;
58 if(diff < 0) diff *= -1; /* Make diff a positive value */
60 return diff;
63 void do_child(void) {
64 struct timeval tv;
65 int retval;
67 /* Let the parent do initial read and write tests from and to the pipe. */
68 tv.tv_sec = DO_PAUSE + DO_PAUSE + DO_PAUSE + 1;
69 tv.tv_usec = 0;
70 retval = select(0, NULL, NULL, NULL, &tv);
72 /* At this point the parent has a pending select with a DO_TIMEOUT timeout.
73 We're going to interrupt by sending a signal */
74 if(kill(getppid(), SIGUSR1) < 0) perror("Failed to send signal");
76 exit(0);
79 void do_parent(int child) {
80 fd_set fds_read;
81 struct timeval tv, start_time, end_time;
82 int retval;
84 /* Install signal handler for SIGUSR1 */
85 signal(SIGUSR1, catch_signal);
87 /* Parent and child share an anonymous pipe. Select for read and wait for the
88 timeout to occur. We wait for DO_PAUSE seconds. Let's see if that's
89 approximately right.*/
90 FD_ZERO(&fds_read);
91 FD_SET(fd_ap[0], &fds_read);
92 tv.tv_sec = DO_PAUSE;
93 tv.tv_usec = 0;
95 (void) gettimeofday(&start_time, NULL); /* Record starting time */
96 retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
97 (void) gettimeofday(&end_time, NULL); /* Record ending time */
99 /* Did we time out? */
100 if(retval != 0) e(1, "Should have timed out");
102 /* Approximately right? The standard does not specify how precise the timeout
103 should be. Instead, the granularity is implementation-defined. In this
104 test we assume that the difference should be no more than half a second.*/
105 if(compute_diff(start_time, end_time, DO_PAUSE) > DO_DELTA)
106 e(2, "Time difference too large");
108 /* Let's wait for another DO_PAUSE seconds, expressed as microseconds */
109 FD_ZERO(&fds_read);
110 FD_SET(fd_ap[0], &fds_read);
111 tv.tv_sec = 0;
112 tv.tv_usec = DO_PAUSE * 1000000L;
114 (void) gettimeofday(&start_time, NULL); /* Record starting time */
115 retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
116 (void) gettimeofday(&end_time, NULL); /* Record ending time */
118 if(retval != 0) e(3, "Should have timed out");
119 if(compute_diff(start_time, end_time, DO_PAUSE) > DO_DELTA)
120 e(4, "Time difference too large");
122 /* Let's wait for another DO_PAUSE seconds, expressed in seconds and micro
123 seconds. */
124 FD_ZERO(&fds_read);
125 FD_SET(fd_ap[0], &fds_read);
126 tv.tv_sec = DO_PAUSE - 1;
127 tv.tv_usec = (DO_PAUSE - tv.tv_sec) * 1000000L;
129 (void) gettimeofday(&start_time, NULL); /* Record starting time */
130 retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
131 (void) gettimeofday(&end_time, NULL); /* Record ending time */
133 if(retval != 0) e(5, "Should have timed out");
134 if(compute_diff(start_time, end_time, DO_PAUSE) > DO_DELTA)
135 e(6, "Time difference too large");
137 /* Finally, we test if our timeout is interrupted by a signal */
138 FD_ZERO(&fds_read);
139 FD_SET(fd_ap[0], &fds_read);
140 tv.tv_sec = DO_TIMEOUT;
141 tv.tv_usec = 0;
143 (void) gettimeofday(&start_time, NULL); /* Record starting time */
144 retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
145 (void) gettimeofday(&end_time, NULL); /* Record ending time */
147 if(retval != -1) e(7, "Should have been interrupted");
148 if(compute_diff(start_time, end_time, DO_TIMEOUT) < DO_DELTA)
149 e(8, "Failed to get interrupted by a signal");
151 if(!got_signal) e(9, "Failed to get interrupted by a signal");
153 waitpid(child, &retval, 0);
154 exit(errct);
157 int main(int argc, char **argv) {
158 int forkres;
160 /* Get subtest number */
161 if(argc != 2) {
162 printf("Usage: %s subtest_no\n", argv[0]);
163 exit(-2);
164 } else if(sscanf(argv[1], "%d", &subtest) != 1) {
165 printf("Usage: %s subtest_no\n", argv[0]);
166 exit(-2);
169 /* Set up anonymous pipe */
170 if(pipe(fd_ap) < 0) {
171 perror("Could not create anonymous pipe");
172 exit(-1);
175 forkres = fork();
176 if(forkres == 0) do_child();
177 else if(forkres > 0) do_parent(forkres);
178 else { /* Fork failed */
179 perror("Unable to fork");
180 exit(-1);
183 exit(-2); /* We're not supposed to get here. Both do_* routines should exit*/