etc/services - sync with NetBSD-8
[minix.git] / minix / tests / t40f.c
blob47f97491483cd450808bffd28eee9cec9bf92748
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 #include "common.h"
24 #define DO_HANDLEDATA 1
25 #define DO_PAUSE 3
26 #define DO_TIMEOUT 7
27 #define DO_DELTA 0.5
28 #define MAX_ERROR 5
29 #define DELTA(x,y) (x.tv_sec - y.tv_sec) * system_hz \
30 + (x.tv_usec - y.tv_usec) * system_hz / 1000000
32 int got_signal = 0;
33 int fd_ap[2];
35 int system_hz;
37 static void catch_signal(int sig_no) {
38 got_signal = 1;
41 static float compute_diff(struct timeval start, struct timeval end, float compare) {
42 /* Compute time difference. It is assumed that the value of start <= end. */
43 clock_t delta;
44 int seconds, hundreths;
45 float diff;
47 delta = DELTA(end, start); /* delta is in ticks */
48 seconds = (int) (delta / system_hz);
49 hundreths = (int) (delta * 100 / system_hz) - (seconds * 100);
51 diff = seconds + (hundreths / 100.0);
52 diff -= compare;
53 if(diff < 0) diff *= -1; /* Make diff a positive value */
55 return diff;
58 static void do_child(void) {
59 struct timeval tv;
61 /* Let the parent do initial read and write tests from and to the pipe. */
62 tv.tv_sec = DO_PAUSE + DO_PAUSE + 1;
63 tv.tv_usec = 0;
64 (void) select(0, NULL, NULL, NULL, &tv);
66 /* At this point the parent has a pending select with a DO_TIMEOUT timeout.
67 We're going to interrupt by sending a signal */
68 if(kill(getppid(), SIGUSR1) < 0) perror("Failed to send signal");
70 exit(0);
73 static void do_parent(int child) {
74 fd_set fds_read;
75 struct timeval tv, start_time, end_time;
76 int retval;
78 /* Install signal handler for SIGUSR1 */
79 signal(SIGUSR1, catch_signal);
81 /* Parent and child share an anonymous pipe. Select for read and wait for the
82 timeout to occur. We wait for DO_PAUSE seconds. Let's see if that's
83 approximately right.*/
84 FD_ZERO(&fds_read);
85 FD_SET(fd_ap[0], &fds_read);
86 tv.tv_sec = DO_PAUSE;
87 tv.tv_usec = 0;
89 (void) gettimeofday(&start_time, NULL); /* Record starting time */
90 retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
91 (void) gettimeofday(&end_time, NULL); /* Record ending time */
93 /* Did we time out? */
94 if(retval != 0) em(1, "Should have timed out");
96 /* Approximately right? The standard does not specify how precise the timeout
97 should be. Instead, the granularity is implementation-defined. In this
98 test we assume that the difference should be no more than half a second.*/
99 if(compute_diff(start_time, end_time, DO_PAUSE) > DO_DELTA)
100 em(2, "Time difference too large");
102 /* Let's wait for another DO_PAUSE seconds, expressed as microseconds */
103 FD_ZERO(&fds_read);
104 FD_SET(fd_ap[0], &fds_read);
105 tv.tv_sec = 0;
106 tv.tv_usec = DO_PAUSE * 1000000L;
108 (void) gettimeofday(&start_time, NULL); /* Record starting time */
109 retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
110 (void) gettimeofday(&end_time, NULL); /* Record ending time */
112 if(retval != -1) em(3, "Should have failed");
113 if(errno != EINVAL) em(4, "Incorrect error thrown");
115 /* Do a few more tests for invalid timeout values. */
116 tv.tv_sec = 0;
117 tv.tv_usec = 1000000;
118 retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
119 if (retval != -1) em(0, "Should have failed");
120 if (errno != EINVAL) em(0, "Incorrect error thrown");
122 tv.tv_sec = 0;
123 tv.tv_usec = ~0;
124 retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
125 if (retval != -1) em(0, "Should have failed");
126 if (errno != EINVAL) em(0, "Incorrect error thrown");
128 /* Let's wait for another DO_PAUSE seconds, expressed in seconds and micro
129 seconds. */
130 FD_ZERO(&fds_read);
131 FD_SET(fd_ap[0], &fds_read);
132 tv.tv_sec = DO_PAUSE - 1;
133 tv.tv_usec = 999999L; /* close enough */
135 (void) gettimeofday(&start_time, NULL); /* Record starting time */
136 retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
137 (void) gettimeofday(&end_time, NULL); /* Record ending time */
139 if(retval != 0) em(5, "Should have timed out");
140 if(compute_diff(start_time, end_time, DO_PAUSE) > DO_DELTA)
141 em(6, "Time difference too large");
143 /* Finally, we test if our timeout is interrupted by a signal */
144 FD_ZERO(&fds_read);
145 FD_SET(fd_ap[0], &fds_read);
146 tv.tv_sec = DO_TIMEOUT;
147 tv.tv_usec = 0;
149 (void) gettimeofday(&start_time, NULL); /* Record starting time */
150 retval = select(fd_ap[0]+1, &fds_read, NULL, NULL, &tv);
151 (void) gettimeofday(&end_time, NULL); /* Record ending time */
153 if(retval != -1) em(7, "Should have been interrupted");
154 if(compute_diff(start_time, end_time, DO_TIMEOUT) < DO_DELTA)
155 em(8, "Failed to get interrupted by a signal");
157 if(!got_signal) em(9, "Failed to get interrupted by a signal");
159 waitpid(child, &retval, 0);
160 exit(errct);
163 int main(int argc, char **argv) {
164 int forkres;
166 /* Retrieve actual system frequency. */
167 system_hz = sysconf(_SC_CLK_TCK);
168 /* Get subtest number */
169 if(argc != 2) {
170 printf("Usage: %s subtest_no\n", argv[0]);
171 exit(-2);
172 } else if(sscanf(argv[1], "%d", &subtest) != 1) {
173 printf("Usage: %s subtest_no\n", argv[0]);
174 exit(-2);
177 /* Set up anonymous pipe */
178 if(pipe(fd_ap) < 0) {
179 perror("Could not create anonymous pipe");
180 exit(-1);
183 forkres = fork();
184 if(forkres == 0) do_child();
185 else if(forkres > 0) do_parent(forkres);
186 else { /* Fork failed */
187 perror("Unable to fork");
188 exit(-1);
191 exit(-2); /* We're not supposed to get here. Both do_* routines should exit*/