1 /* Tests for interrupting VFS calls - by D.C. van Moolenbroek */
5 #include <sys/socket.h>
6 #include <sys/utsname.h>
7 #include <sys/syslimits.h>
8 #include <netinet/in.h>
20 * This signal handler does nothing. It just needs to be triggered, so that
21 * PM will tell VFS to unpause this process.
23 static void dummy_handler(int sig
)
29 * Interrupt a select(2) call.
34 struct sigaction act
, oact
;
36 struct sockaddr_in sin
;
39 int tfd
[2], pfd
[2], sfd
, maxfd
;
43 act
.sa_handler
= dummy_handler
;
44 sigfillset(&act
.sa_mask
);
46 if (sigaction(SIGALRM
, &act
, &oact
) < 0) e(1);
48 memset(&it
, 0, sizeof(it
));
49 it
.it_value
.tv_sec
= 0;
50 it
.it_value
.tv_usec
= 100000;
51 if (setitimer(ITIMER_REAL
, &it
, NULL
) < 0) e(2);
53 /* First try without any file descriptors. */
56 if (select(0, NULL
, NULL
, NULL
, &tv
) >= 0) e(3);
57 if (errno
!= EINTR
) e(4);
59 /* Then try with different types of file descriptors, all blocking. */
60 if (openpty(&tfd
[0], &tfd
[1], NULL
, NULL
, NULL
) < 0) e(5);
63 FD_SET(tfd
[0], &set
); /* reading from the PTY master should block */
66 if (pipe(pfd
) < 0) e(6);
67 FD_SET(pfd
[0], &set
); /* reading from an empty pipe should block */
68 if (maxfd
< pfd
[0]) maxfd
= pfd
[0];
70 if ((sfd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) e(7);
72 memset(&sin
, 0, sizeof(sin
));
73 sin
.sin_family
= AF_INET
;
74 /* Binding to an arbitrary port is fine. */
75 if (bind(sfd
, (struct sockaddr
*)&sin
, sizeof(sin
)) < 0) e(8);
77 if (listen(sfd
, 1) < 0) e(9);
79 FD_SET(sfd
, &set
); /* reading from a listening socket should block */
80 if (maxfd
< sfd
) maxfd
= sfd
;
82 memset(&it
, 0, sizeof(it
));
83 it
.it_value
.tv_sec
= 0;
84 it
.it_value
.tv_usec
= 100000;
85 if (setitimer(ITIMER_REAL
, &it
, NULL
) < 0) e(10);
89 if (select(maxfd
+ 1, &set
, NULL
, NULL
, &tv
) >= 0) e(11);
90 if (errno
!= EINTR
) e(12);
92 if (close(tfd
[0]) < 0) e(13);
93 if (close(tfd
[1]) < 0) e(14);
94 if (close(pfd
[0]) < 0) e(15);
95 if (close(pfd
[1]) < 0) e(16);
96 if (close(sfd
) < 0) e(17);
98 if (sigaction(SIGUSR1
, &oact
, NULL
) < 0) e(18);
102 * Interrupt reads and writes to a pipe. POSIX states that if the operation
103 * was partially successful, the number of bytes written so far should be
104 * returned; otherwise, the we should get the normal EINTR.
109 struct sigaction act
, oact
;
116 if ((buf
= malloc(PIPE_BUF
* 2)) == NULL
) e(1);
118 if (pipe(pfd
) < 0) e(2);
120 act
.sa_handler
= dummy_handler
;
121 sigfillset(&act
.sa_mask
);
123 if (sigaction(SIGALRM
, &act
, &oact
) < 0) e(3);
125 memset(&it
, 0, sizeof(it
));
126 it
.it_value
.tv_sec
= 0;
127 it
.it_value
.tv_usec
= 100000;
128 if (setitimer(ITIMER_REAL
, &it
, NULL
) < 0) e(4);
131 * This write is too large for the pipe, so it will block until the
132 * signal arrives. When being interrupted, it should return the pipe
133 * size, as that is the part that has been filled successfully so far.
135 if (write(pfd
[1], buf
, PIPE_BUF
* 2) != PIPE_BUF
) e(5);
138 * Since the write partially succeeded, we should be able to read all
139 * we wrote so far, without blocking.
141 if (read(pfd
[0], buf
, PIPE_BUF
) != PIPE_BUF
) e(6);
143 /* We should now be able to fill the pipe up to its full size again. */
144 if (write(pfd
[1], buf
, PIPE_BUF
) != PIPE_BUF
) e(7);
146 memset(&it
, 0, sizeof(it
));
147 it
.it_value
.tv_sec
= 0;
148 it
.it_value
.tv_usec
= 100000;
149 if (setitimer(ITIMER_REAL
, &it
, NULL
) < 0) e(8);
151 /* Now interrupt a write attempt on a full pipe. */
152 if (write(pfd
[1], buf
, 1) >= 0) e(9);
153 if (errno
!= EINTR
) e(10);
155 /* Empty the pipe again. */
156 if (read(pfd
[0], buf
, PIPE_BUF
) != PIPE_BUF
) e(11);
158 memset(&it
, 0, sizeof(it
));
159 it
.it_value
.tv_sec
= 0;
160 it
.it_value
.tv_usec
= 100000;
161 if (setitimer(ITIMER_REAL
, &it
, NULL
) < 0) e(12);
163 /* Now interrupt a read on an empty pipe. */
164 if (read(pfd
[0], buf
, PIPE_BUF
) >= 0) e(13);
165 if (errno
!= EINTR
) e(14);
167 if (close(pfd
[0]) < 0) e(15);
168 if (close(pfd
[1]) < 0) e(16);
170 if (sigaction(SIGUSR1
, &oact
, NULL
) < 0) e(17);
176 * Interrupt an ioctl(2) call. We use an alarm to interrupt an accept(3) call
177 * on a TCP socket - the accept procedure is (currently) implemented using
183 struct sigaction act
, oact
;
185 struct sockaddr_in sin
;
191 if ((sfd
= socket(AF_INET
, SOCK_STREAM
, 0)) < 0) e(1);
193 memset(&sin
, 0, sizeof(sin
));
194 sin
.sin_family
= AF_INET
;
195 /* Binding to an arbitrary port is fine. */
196 if (bind(sfd
, (struct sockaddr
*)&sin
, sizeof(sin
)) < 0) e(2);
198 if (listen(sfd
, 1) < 0) e(3);
200 act
.sa_handler
= dummy_handler
;
201 sigfillset(&act
.sa_mask
);
203 if (sigaction(SIGALRM
, &act
, &oact
) < 0) e(4);
205 memset(&it
, 0, sizeof(it
));
206 it
.it_value
.tv_sec
= 0;
207 it
.it_value
.tv_usec
= 100000;
208 if (setitimer(ITIMER_REAL
, &it
, NULL
) < 0) e(5);
210 /* This will block until the timer fires. */
212 if (accept(sfd
, (struct sockaddr
*)&sin
, &len
) >= 0) e(6);
213 if (errno
!= EINTR
) e(7);
215 if (close(sfd
) < 0) e(8);
217 if (sigaction(SIGUSR1
, &oact
, NULL
) < 0) e(9);
221 * Try to trigger semi-concurrent processing of normal system calls and
222 * postponed PM requests for a single process within VFS.
228 struct sigaction act
, oact
;
230 int r
, fd
, pfd
[2], count
, status
;
231 time_t stime
, etime
, runtime
= 30 /*seconds*/;
236 /* This test would kill wimpy platforms such as ARM. */
237 if (uname(&name
) < 0) e(1);
238 if (!strcmp(name
.machine
, "arm")) return;
240 act
.sa_handler
= dummy_handler
;
241 sigfillset(&act
.sa_mask
);
243 if (sigaction(SIGALRM
, &act
, &oact
) < 0) e(2);
245 if (pipe(pfd
) < 0) e(3);
247 /* Pre-fill the pipe. */
248 if ((pbuf
= malloc(PIPE_BUF
- 1)) == NULL
) e(4);
250 if (write(pfd
[1], pbuf
, PIPE_BUF
- 1) != PIPE_BUF
- 1) e(5);
256 if (close(pfd
[1]) < 0) e(6);
258 /* Read from the pipe, but more slowly than the writer. */
259 while ((r
= read(pfd
[0], buf
, 2)) != 0)
271 if (close(pfd
[0]) < 0) e(9);
275 /* Start an alarm mayhem. */
276 it
.it_value
.tv_sec
= 0;
277 it
.it_value
.tv_usec
= 1;
278 it
.it_interval
.tv_sec
= 0;
279 it
.it_interval
.tv_usec
= 1;
280 if (setitimer(ITIMER_REAL
, &it
, NULL
) < 0) e(10);
283 * Then start writing to the pipe, in such a way that the
284 * write operation will be suspended in every so many cases.
287 if (write(pfd
[1], buf
, 3) < 0 && errno
!= EINTR
)
291 } while ((int)(etime
- stime
) < runtime
);
300 if (close(pfd
[0]) < 0) e(13);
301 if (close(pfd
[1]) < 0) e(14);
304 * First give the two processes a while to run regularly. Then start
305 * creating additional noise to keep the VFS worker threads busy.
312 * As of writing, VFS has less than 20 worker threads. Create more
313 * processes than that.
315 for (count
= 2; count
< 20; count
++) {
322 * Opening a character device blocks the
323 * calling thread, hopefully causing work to be
324 * queued. Sadly, in practice, the high
325 * priorities of system processes prevent this
326 * case from occurring frequently. It works
327 * better with a driver that has a priority
328 * below that of of user processes.
330 if ((fd
= open("/dev/null", O_WRONLY
)) < 0)
336 } while ((int)(etime
- stime
) < runtime
);
346 /* Wait for all children to shut down. */
347 while (count
-- > 0) {
348 if (wait(&status
) <= 0) e(17);
349 if (!WIFEXITED(status
)) e(18);
350 if (WEXITSTATUS(status
) != 0) e(19);
353 if (sigaction(SIGUSR1
, &oact
, NULL
) < 0) e(20);
357 * Try to get a nonblocking select(2) call to be interrupted by a signal.
358 * In the future, VFS should prevent this from happening at all; for now, we
359 * just want to make sure it does not result in disaster when it does happen.
365 struct sigaction act
, oact
;
373 /* This test would kill wimpy platforms such as ARM. */
374 if (uname(&name
) < 0) e(1);
375 if (!strcmp(name
.machine
, "arm")) return;
377 if (openpty(&tfd
[0], &tfd
[1], NULL
, NULL
, NULL
) < 0) e(2);
379 act
.sa_handler
= dummy_handler
;
380 sigfillset(&act
.sa_mask
);
382 if (sigaction(SIGALRM
, &act
, &oact
) < 0) e(3);
385 * Start an alarm mayhem. We have to try to get a signal in between
386 * VFS sending a select request to TTY, and TTY replying to VFS with
389 it
.it_value
.tv_sec
= 0;
390 it
.it_value
.tv_usec
= 1;
391 it
.it_interval
.tv_sec
= 0;
392 it
.it_interval
.tv_usec
= 1;
393 if (setitimer(ITIMER_REAL
, &it
, NULL
) < 0) e(4);
396 * Now issue nonblocking selects until we get interrupted, or until
397 * we have gone through a hardcoded maximum of attempts.
401 if (--left
== 0) break;
404 FD_SET(tfd
[0], &set
); /* reading from master should block */
408 } while (select(2, &set
, NULL
, NULL
, &tv
) >= 0);
410 if (left
> 0 && errno
!= EINTR
) e(5);
412 it
.it_value
.tv_sec
= 0;
413 it
.it_value
.tv_usec
= 0;
414 if (setitimer(ITIMER_REAL
, &it
, NULL
) < 0) e(6);
416 /* The call failed, so the set must be unmodified. */
417 if (left
> 0 && !FD_SET(tfd
[0], &set
)) e(7);
419 if (close(tfd
[0]) < 0) e(8);
420 if (close(tfd
[1]) < 0) e(9);
422 if (sigaction(SIGUSR1
, &oact
, NULL
) < 0) e(10);
426 main(int argc
, char **argv
)
437 for (i
= 0; i
< ITERATIONS
; i
++) {
438 if (m
& 0x01) test76a();
439 if (m
& 0x02) test76b();
440 if (m
& 0x04) test76c();
441 if (m
& 0x08) test76d();
442 if (m
& 0x10) test76e();