release script fixes
[minix3.git] / test / test76.c
blobc7268329a3232691f05472fb226f566843e6d9a8
1 /* Tests for interrupting VFS calls - by D.C. van Moolenbroek */
2 /* This test needs to be run as root; otherwise, openpty() won't work. */
3 #include <stdio.h>
4 #include <sys/time.h>
5 #include <sys/wait.h>
6 #include <sys/socket.h>
7 #include <sys/utsname.h>
8 #include <sys/syslimits.h>
9 #include <netinet/in.h>
10 #include <signal.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <errno.h>
14 #include <util.h>
16 #define ITERATIONS 1
18 #include "common.h"
21 * This signal handler does nothing. It just needs to be triggered, so that
22 * PM will tell VFS to unpause this process.
24 static void dummy_handler(int sig)
26 /* Nothing. */
30 * Interrupt a select(2) call.
32 static void
33 test76a(void)
35 struct sigaction act, oact;
36 struct itimerval it;
37 struct sockaddr_in sin;
38 struct timeval tv;
39 fd_set set;
40 int tfd[2], pfd[2], sfd, maxfd;
42 subtest = 1;
44 act.sa_handler = dummy_handler;
45 sigfillset(&act.sa_mask);
46 act.sa_flags = 0;
47 if (sigaction(SIGALRM, &act, &oact) < 0) e(1);
49 memset(&it, 0, sizeof(it));
50 it.it_value.tv_sec = 0;
51 it.it_value.tv_usec = 10000;
52 if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(2);
54 /* First try without any file descriptors. */
55 tv.tv_sec = 1;
56 tv.tv_usec = 0;
57 if (select(0, NULL, NULL, NULL, &tv) >= 0) e(3);
58 if (errno != EINTR) e(4);
60 /* Then try with different types of file descriptors, all blocking. */
61 if (openpty(&tfd[0], &tfd[1], NULL, NULL, NULL) < 0) e(5);
63 FD_ZERO(&set);
64 FD_SET(tfd[0], &set); /* reading from the PTY master should block */
65 maxfd = tfd[0];
67 if (pipe(pfd) < 0) e(6);
68 FD_SET(pfd[0], &set); /* reading from an empty pipe should block */
69 if (maxfd < pfd[0]) maxfd = pfd[0];
71 if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) e(7);
73 memset(&sin, 0, sizeof(sin));
74 sin.sin_family = AF_INET;
75 /* Binding to an arbitrary port is fine. */
76 if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) e(8);
78 if (listen(sfd, 1) < 0) e(9);
80 FD_SET(sfd, &set); /* reading from a listening socket should block */
81 if (maxfd < sfd) maxfd = sfd;
83 memset(&it, 0, sizeof(it));
84 it.it_value.tv_sec = 0;
85 it.it_value.tv_usec = 100000;
86 if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(10);
88 tv.tv_sec = 1;
89 tv.tv_usec = 0;
90 if (select(maxfd + 1, &set, NULL, NULL, &tv) >= 0) e(11);
91 if (errno != EINTR) e(12);
93 if (close(tfd[0]) < 0) e(13);
94 if (close(tfd[1]) < 0) e(14);
95 if (close(pfd[0]) < 0) e(15);
96 if (close(pfd[1]) < 0) e(16);
97 if (close(sfd) < 0) e(17);
99 if (sigaction(SIGUSR1, &oact, NULL) < 0) e(18);
103 * Interrupt reads and writes to a pipe. POSIX states that if the operation
104 * was partially successful, the number of bytes written so far should be
105 * returned; otherwise, the we should get the normal EINTR.
107 static void
108 test76b(void)
110 struct sigaction act, oact;
111 struct itimerval it;
112 char *buf;
113 int pfd[2];
115 subtest = 2;
117 if ((buf = malloc(PIPE_BUF * 2)) == NULL) e(1);
119 if (pipe(pfd) < 0) e(2);
121 act.sa_handler = dummy_handler;
122 sigfillset(&act.sa_mask);
123 act.sa_flags = 0;
124 if (sigaction(SIGALRM, &act, &oact) < 0) e(3);
126 memset(&it, 0, sizeof(it));
127 it.it_value.tv_sec = 0;
128 it.it_value.tv_usec = 10000;
129 if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(4);
132 * This write is too large for the pipe, so it will block until the
133 * signal arrives. When being interrupted, it should return the pipe
134 * size, as that is the part that has been filled successfully so far.
136 if (write(pfd[1], buf, PIPE_BUF * 2) != PIPE_BUF) e(5);
139 * Since the write partially succeeded, we should be able to read all
140 * we wrote so far, without blocking.
142 if (read(pfd[0], buf, PIPE_BUF) != PIPE_BUF) e(6);
144 /* We should now be able to fill the pipe up to its full size again. */
145 if (write(pfd[1], buf, PIPE_BUF) != PIPE_BUF) e(7);
147 memset(&it, 0, sizeof(it));
148 it.it_value.tv_sec = 0;
149 it.it_value.tv_usec = 10000;
150 if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(8);
152 /* Now interrupt a write attempt on a full pipe. */
153 if (write(pfd[1], buf, 1) >= 0) e(9);
154 if (errno != EINTR) e(10);
156 /* Empty the pipe again. */
157 if (read(pfd[0], buf, PIPE_BUF) != PIPE_BUF) e(11);
159 memset(&it, 0, sizeof(it));
160 it.it_value.tv_sec = 0;
161 it.it_value.tv_usec = 10000;
162 if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(12);
164 /* Now interrupt a read on an empty pipe. */
165 if (read(pfd[0], buf, PIPE_BUF) >= 0) e(13);
166 if (errno != EINTR) e(14);
168 if (close(pfd[0]) < 0) e(15);
169 if (close(pfd[1]) < 0) e(16);
171 if (sigaction(SIGUSR1, &oact, NULL) < 0) e(17);
173 free(buf);
177 * Interrupt an ioctl(2) call. We use an alarm to interrupt an accept(3) call
178 * on a TCP socket - the accept procedure is (currently) implemented using
179 * ioctl(2) calls.
181 static void
182 test76c(void)
184 struct sigaction act, oact;
185 struct itimerval it;
186 struct sockaddr_in sin;
187 socklen_t len;
188 int sfd;
190 subtest = 3;
192 if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) e(1);
194 memset(&sin, 0, sizeof(sin));
195 sin.sin_family = AF_INET;
196 /* Binding to an arbitrary port is fine. */
197 if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) e(2);
199 if (listen(sfd, 1) < 0) e(3);
201 act.sa_handler = dummy_handler;
202 sigfillset(&act.sa_mask);
203 act.sa_flags = 0;
204 if (sigaction(SIGALRM, &act, &oact) < 0) e(4);
206 memset(&it, 0, sizeof(it));
207 it.it_value.tv_sec = 0;
208 it.it_value.tv_usec = 10000;
209 if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(5);
211 /* This will block until the timer fires. */
212 len = sizeof(sin);
213 if (accept(sfd, (struct sockaddr *)&sin, &len) >= 0) e(6);
214 if (errno != EINTR) e(7);
216 if (close(sfd) < 0) e(8);
218 if (sigaction(SIGUSR1, &oact, NULL) < 0) e(9);
222 * Try to trigger semi-concurrent processing of normal system calls and
223 * postponed PM requests for a single process within VFS.
225 static void
226 test76d(void)
228 struct utsname name;
229 struct sigaction act, oact;
230 struct itimerval it;
231 int r, fd, pfd[2], count, status;
232 time_t stime, etime, runtime = 30 /*seconds*/;
233 char buf[3], *pbuf;
235 subtest = 4;
237 /* This test would kill wimpy platforms such as ARM. */
238 if (uname(&name) < 0) e(1);
239 if (!strcmp(name.machine, "arm")) return;
241 act.sa_handler = dummy_handler;
242 sigfillset(&act.sa_mask);
243 act.sa_flags = 0;
244 if (sigaction(SIGALRM, &act, &oact) < 0) e(2);
246 if (pipe(pfd) < 0) e(3);
248 /* Pre-fill the pipe. */
249 if ((pbuf = malloc(PIPE_BUF - 1)) == NULL) e(4);
251 if (write(pfd[1], pbuf, PIPE_BUF - 1) != PIPE_BUF - 1) e(5);
253 free(pbuf);
255 switch (fork()) {
256 case 0:
257 if (close(pfd[1]) < 0) e(6);
259 /* Read from the pipe, but more slowly than the writer. */
260 while ((r = read(pfd[0], buf, 2)) != 0)
261 if (r < 0) e(7);
263 exit(0);
264 case -1:
265 e(8);
266 default:
267 break;
270 switch (fork()) {
271 case 0:
272 if (close(pfd[0]) < 0) e(9);
274 time(&stime);
276 /* Start an alarm mayhem. */
277 it.it_value.tv_sec = 0;
278 it.it_value.tv_usec = 1;
279 it.it_interval.tv_sec = 0;
280 it.it_interval.tv_usec = 1;
281 if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(10);
284 * Then start writing to the pipe, in such a way that the
285 * write operation will be suspended in every so many cases.
287 do {
288 if (write(pfd[1], buf, 3) < 0 && errno != EINTR)
289 e(11);
291 time(&etime);
292 } while ((int)(etime - stime) < runtime);
294 exit(0);
295 case -1:
296 e(12);
297 default:
298 break;
301 if (close(pfd[0]) < 0) e(13);
302 if (close(pfd[1]) < 0) e(14);
305 * First give the two processes a while to run regularly. Then start
306 * creating additional noise to keep the VFS worker threads busy.
308 runtime /= 2;
310 sleep(runtime);
313 * As of writing, VFS has less than 20 worker threads. Create more
314 * processes than that.
316 for (count = 2; count < 20; count++) {
317 switch (fork()) {
318 case 0:
319 time(&stime);
321 do {
323 * Opening a character device blocks the
324 * calling thread, hopefully causing work to be
325 * queued. Sadly, in practice, the high
326 * priorities of system processes prevent this
327 * case from occurring frequently. It works
328 * better with a driver that has a priority
329 * below that of of user processes.
331 if ((fd = open("/dev/null", O_WRONLY)) < 0)
332 e(15);
334 close(fd);
336 time(&etime);
337 } while ((int)(etime - stime) < runtime);
339 exit(0);
340 case -1:
341 e(16);
342 default:
343 break;
347 /* Wait for all children to shut down. */
348 while (count-- > 0) {
349 if (wait(&status) <= 0) e(17);
350 if (!WIFEXITED(status)) e(18);
351 if (WEXITSTATUS(status) != 0) e(19);
354 if (sigaction(SIGUSR1, &oact, NULL) < 0) e(20);
358 * Try to get a nonblocking select(2) call to be interrupted by a signal.
359 * In the future, VFS should prevent this from happening at all; for now, we
360 * just want to make sure it does not result in disaster when it does happen.
362 static void
363 test76e(void)
365 struct utsname name;
366 struct sigaction act, oact;
367 struct itimerval it;
368 struct timeval tv;
369 fd_set set;
370 int tfd[2], left;
372 subtest = 5;
374 /* This test would kill wimpy platforms such as ARM. */
375 if (uname(&name) < 0) e(1);
376 if (!strcmp(name.machine, "arm")) return;
378 if (openpty(&tfd[0], &tfd[1], NULL, NULL, NULL) < 0) e(2);
380 act.sa_handler = dummy_handler;
381 sigfillset(&act.sa_mask);
382 act.sa_flags = 0;
383 if (sigaction(SIGALRM, &act, &oact) < 0) e(3);
386 * Start an alarm mayhem. We have to try to get a signal in between
387 * VFS sending a select request to TTY, and TTY replying to VFS with
388 * initial results.
390 it.it_value.tv_sec = 0;
391 it.it_value.tv_usec = 1;
392 it.it_interval.tv_sec = 0;
393 it.it_interval.tv_usec = 1;
394 if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(4);
397 * Now issue nonblocking selects until we get interrupted, or until
398 * we have gone through a hardcoded maximum of attempts.
400 left = 100000;
401 do {
402 if (--left == 0) break;
404 FD_ZERO(&set);
405 FD_SET(tfd[0], &set); /* reading from master should block */
407 tv.tv_sec = 0;
408 tv.tv_usec = 0;
409 } while (select(2, &set, NULL, NULL, &tv) >= 0);
411 if (left > 0 && errno != EINTR) e(5);
413 it.it_value.tv_sec = 0;
414 it.it_value.tv_usec = 0;
415 if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(6);
417 /* The call failed, so the set must be unmodified. */
418 if (left > 0 && !FD_SET(tfd[0], &set)) e(7);
420 if (close(tfd[0]) < 0) e(8);
421 if (close(tfd[1]) < 0) e(9);
423 if (sigaction(SIGUSR1, &oact, NULL) < 0) e(10);
427 main(int argc, char **argv)
429 int i, m;
431 start(76);
433 if (argc == 2)
434 m = atoi(argv[1]);
435 else
436 m = 0xFF;
438 for (i = 0; i < ITERATIONS; i++) {
439 if (m & 0x01) test76a();
440 if (m & 0x02) test76b();
441 if (m & 0x04) test76c();
442 if (m & 0x08) test76d();
443 if (m & 0x10) test76e();
446 quit();