5 * Select works on regular files, (pseudo) terminal devices, streams-based
6 * files, FIFOs, pipes, and sockets. This test verifies selecting with a time
13 #include <sys/types.h>
14 #include <sys/select.h>
24 #define DO_HANDLEDATA 1
29 #define DELTA(x,y) (x.tv_sec - y.tv_sec) * system_hz \
30 + (x.tv_usec - y.tv_usec) * system_hz / 1000000
37 static void catch_signal(int sig_no
) {
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. */
44 int seconds
, hundreths
;
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);
53 if(diff
< 0) diff
*= -1; /* Make diff a positive value */
58 static void do_child(void) {
61 /* Let the parent do initial read and write tests from and to the pipe. */
62 tv
.tv_sec
= DO_PAUSE
+ DO_PAUSE
+ 1;
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");
73 static void do_parent(int child
) {
75 struct timeval tv
, start_time
, end_time
;
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.*/
85 FD_SET(fd_ap
[0], &fds_read
);
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 */
104 FD_SET(fd_ap
[0], &fds_read
);
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. */
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");
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
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 */
145 FD_SET(fd_ap
[0], &fds_read
);
146 tv
.tv_sec
= DO_TIMEOUT
;
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);
163 int main(int argc
, char **argv
) {
166 /* Retrieve actual system frequency. */
167 system_hz
= sysconf(_SC_CLK_TCK
);
168 /* Get subtest number */
170 printf("Usage: %s subtest_no\n", argv
[0]);
172 } else if(sscanf(argv
[1], "%d", &subtest
) != 1) {
173 printf("Usage: %s subtest_no\n", argv
[0]);
177 /* Set up anonymous pipe */
178 if(pipe(fd_ap
) < 0) {
179 perror("Could not create anonymous pipe");
184 if(forkres
== 0) do_child();
185 else if(forkres
> 0) do_parent(forkres
);
186 else { /* Fork failed */
187 perror("Unable to fork");
191 exit(-2); /* We're not supposed to get here. Both do_* routines should exit*/