tests: add test76 for interrupting VFS operations
Change-Id: Ic436cac61de8c42e0c7ee2d442c647528654cde9
This commit is contained in:
parent
1e7b45c682
commit
d95a36f6ae
@ -5656,6 +5656,7 @@
|
|||||||
./usr/tests/minix-posix/test73 minix-sys
|
./usr/tests/minix-posix/test73 minix-sys
|
||||||
./usr/tests/minix-posix/test74 minix-sys
|
./usr/tests/minix-posix/test74 minix-sys
|
||||||
./usr/tests/minix-posix/test75 minix-sys
|
./usr/tests/minix-posix/test75 minix-sys
|
||||||
|
./usr/tests/minix-posix/test76 minix-sys
|
||||||
./usr/tests/minix-posix/test8 minix-sys
|
./usr/tests/minix-posix/test8 minix-sys
|
||||||
./usr/tests/minix-posix/test9 minix-sys
|
./usr/tests/minix-posix/test9 minix-sys
|
||||||
./usr/tests/minix-posix/testinterp minix-sys
|
./usr/tests/minix-posix/testinterp minix-sys
|
||||||
|
@ -31,6 +31,7 @@ COPTS.test68.c= -O0
|
|||||||
|
|
||||||
# Some have special libraries
|
# Some have special libraries
|
||||||
LDADD.test59= -lmthread
|
LDADD.test59= -lmthread
|
||||||
|
LDADD.test76= -lutil
|
||||||
|
|
||||||
# Some have an extra file
|
# Some have an extra file
|
||||||
OBJS.test57= test57loop.o
|
OBJS.test57= test57loop.o
|
||||||
@ -53,7 +54,7 @@ MINIX_TESTS= \
|
|||||||
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
||||||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
||||||
41 42 43 44 45 46 48 49 50 52 53 54 55 56 58 59 60 \
|
41 42 43 44 45 46 48 49 50 52 53 54 55 56 58 59 60 \
|
||||||
61 64 65 66 67 68 69 70 71 72 73 74 75
|
61 64 65 66 67 68 69 70 71 72 73 74 75 76
|
||||||
|
|
||||||
.if ${MACHINE_ARCH} == "i386"
|
.if ${MACHINE_ARCH} == "i386"
|
||||||
MINIX_TESTS+= \
|
MINIX_TESTS+= \
|
||||||
|
4
test/run
4
test/run
@ -21,14 +21,14 @@ badones= # list of tests that failed
|
|||||||
|
|
||||||
# Programs that require setuid
|
# Programs that require setuid
|
||||||
setuids="test11 test33 test43 test44 test46 test56 test60 test61 test65 \
|
setuids="test11 test33 test43 test44 test46 test56 test60 test61 test65 \
|
||||||
test69" # test73"
|
test69 test76" # test73"
|
||||||
# Scripts that require to be run as root
|
# Scripts that require to be run as root
|
||||||
rootscripts="testisofs"
|
rootscripts="testisofs"
|
||||||
|
|
||||||
alltests="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
alltests="1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
||||||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
||||||
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
|
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 \
|
||||||
61 62 63 64 65 66 67 68 69 70 71 72 75 \
|
61 62 63 64 65 66 67 68 69 70 71 72 75 76 \
|
||||||
sh1 sh2 interp mfs isofs"
|
sh1 sh2 interp mfs isofs"
|
||||||
tests_no=`expr 0`
|
tests_no=`expr 0`
|
||||||
|
|
||||||
|
446
test/test76.c
Normal file
446
test/test76.c
Normal file
@ -0,0 +1,446 @@
|
|||||||
|
/* Tests for interrupting VFS calls - by D.C. van Moolenbroek */
|
||||||
|
/* This test needs to be run as root; otherwise, openpty() won't work. */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/utsname.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <util.h>
|
||||||
|
|
||||||
|
#define ITERATIONS 1
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This signal handler does nothing. It just needs to be triggered, so that
|
||||||
|
* PM will tell VFS to unpause this process.
|
||||||
|
*/
|
||||||
|
static void dummy_handler(int sig)
|
||||||
|
{
|
||||||
|
/* Nothing. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interrupt a select(2) call.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
test76a(void)
|
||||||
|
{
|
||||||
|
struct sigaction act, oact;
|
||||||
|
struct itimerval it;
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
struct timeval tv;
|
||||||
|
fd_set set;
|
||||||
|
int tfd[2], pfd[2], sfd, maxfd;
|
||||||
|
|
||||||
|
subtest = 1;
|
||||||
|
|
||||||
|
act.sa_handler = dummy_handler;
|
||||||
|
sigfillset(&act.sa_mask);
|
||||||
|
act.sa_flags = 0;
|
||||||
|
if (sigaction(SIGALRM, &act, &oact) < 0) e(1);
|
||||||
|
|
||||||
|
memset(&it, 0, sizeof(it));
|
||||||
|
it.it_value.tv_sec = 0;
|
||||||
|
it.it_value.tv_usec = 10000;
|
||||||
|
if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(2);
|
||||||
|
|
||||||
|
/* First try without any file descriptors. */
|
||||||
|
tv.tv_sec = 1;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
if (select(0, NULL, NULL, NULL, &tv) >= 0) e(3);
|
||||||
|
if (errno != EINTR) e(4);
|
||||||
|
|
||||||
|
/* Then try with different types of file descriptors, all blocking. */
|
||||||
|
if (openpty(&tfd[0], &tfd[1], NULL, NULL, NULL) < 0) e(5);
|
||||||
|
|
||||||
|
FD_ZERO(&set);
|
||||||
|
FD_SET(tfd[0], &set); /* reading from the PTY master should block */
|
||||||
|
maxfd = tfd[0];
|
||||||
|
|
||||||
|
if (pipe(pfd) < 0) e(6);
|
||||||
|
FD_SET(pfd[0], &set); /* reading from an empty pipe should block */
|
||||||
|
if (maxfd < pfd[0]) maxfd = pfd[0];
|
||||||
|
|
||||||
|
if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) e(7);
|
||||||
|
|
||||||
|
memset(&sin, 0, sizeof(sin));
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
/* Binding to an arbitrary port is fine. */
|
||||||
|
if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) e(8);
|
||||||
|
|
||||||
|
if (listen(sfd, 1) < 0) e(9);
|
||||||
|
|
||||||
|
FD_SET(sfd, &set); /* reading from a listening socket should block */
|
||||||
|
if (maxfd < sfd) maxfd = sfd;
|
||||||
|
|
||||||
|
memset(&it, 0, sizeof(it));
|
||||||
|
it.it_value.tv_sec = 0;
|
||||||
|
it.it_value.tv_usec = 100000;
|
||||||
|
if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(10);
|
||||||
|
|
||||||
|
tv.tv_sec = 1;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
if (select(maxfd + 1, &set, NULL, NULL, &tv) >= 0) e(11);
|
||||||
|
if (errno != EINTR) e(12);
|
||||||
|
|
||||||
|
if (close(tfd[0]) < 0) e(13);
|
||||||
|
if (close(tfd[1]) < 0) e(14);
|
||||||
|
if (close(pfd[0]) < 0) e(15);
|
||||||
|
if (close(pfd[1]) < 0) e(16);
|
||||||
|
if (close(sfd) < 0) e(17);
|
||||||
|
|
||||||
|
if (sigaction(SIGUSR1, &oact, NULL) < 0) e(18);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interrupt reads and writes to a pipe. POSIX states that if the operation
|
||||||
|
* was partially successful, the number of bytes written so far should be
|
||||||
|
* returned; otherwise, the we should get the normal EINTR.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
test76b(void)
|
||||||
|
{
|
||||||
|
struct sigaction act, oact;
|
||||||
|
struct itimerval it;
|
||||||
|
char *buf;
|
||||||
|
int pfd[2];
|
||||||
|
|
||||||
|
subtest = 2;
|
||||||
|
|
||||||
|
if ((buf = malloc(PIPE_BUF * 2)) == NULL) e(1);
|
||||||
|
|
||||||
|
if (pipe(pfd) < 0) e(2);
|
||||||
|
|
||||||
|
act.sa_handler = dummy_handler;
|
||||||
|
sigfillset(&act.sa_mask);
|
||||||
|
act.sa_flags = 0;
|
||||||
|
if (sigaction(SIGALRM, &act, &oact) < 0) e(3);
|
||||||
|
|
||||||
|
memset(&it, 0, sizeof(it));
|
||||||
|
it.it_value.tv_sec = 0;
|
||||||
|
it.it_value.tv_usec = 10000;
|
||||||
|
if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(4);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This write is too large for the pipe, so it will block until the
|
||||||
|
* signal arrives. When being interrupted, it should return the pipe
|
||||||
|
* size, as that is the part that has been filled successfully so far.
|
||||||
|
*/
|
||||||
|
if (write(pfd[1], buf, PIPE_BUF * 2) != PIPE_BUF) e(5);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since the write partially succeeded, we should be able to read all
|
||||||
|
* we wrote so far, without blocking.
|
||||||
|
*/
|
||||||
|
if (read(pfd[0], buf, PIPE_BUF) != PIPE_BUF) e(6);
|
||||||
|
|
||||||
|
/* We should now be able to fill the pipe up to its full size again. */
|
||||||
|
if (write(pfd[1], buf, PIPE_BUF) != PIPE_BUF) e(7);
|
||||||
|
|
||||||
|
memset(&it, 0, sizeof(it));
|
||||||
|
it.it_value.tv_sec = 0;
|
||||||
|
it.it_value.tv_usec = 10000;
|
||||||
|
if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(8);
|
||||||
|
|
||||||
|
/* Now interrupt a write attempt on a full pipe. */
|
||||||
|
if (write(pfd[1], buf, 1) >= 0) e(9);
|
||||||
|
if (errno != EINTR) e(10);
|
||||||
|
|
||||||
|
/* Empty the pipe again. */
|
||||||
|
if (read(pfd[0], buf, PIPE_BUF) != PIPE_BUF) e(11);
|
||||||
|
|
||||||
|
memset(&it, 0, sizeof(it));
|
||||||
|
it.it_value.tv_sec = 0;
|
||||||
|
it.it_value.tv_usec = 10000;
|
||||||
|
if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(12);
|
||||||
|
|
||||||
|
/* Now interrupt a read on an empty pipe. */
|
||||||
|
if (read(pfd[0], buf, PIPE_BUF) >= 0) e(13);
|
||||||
|
if (errno != EINTR) e(14);
|
||||||
|
|
||||||
|
if (close(pfd[0]) < 0) e(15);
|
||||||
|
if (close(pfd[1]) < 0) e(16);
|
||||||
|
|
||||||
|
if (sigaction(SIGUSR1, &oact, NULL) < 0) e(17);
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Interrupt an ioctl(2) call. We use an alarm to interrupt an accept(3) call
|
||||||
|
* on a TCP socket - the accept procedure is (currently) implemented using
|
||||||
|
* ioctl(2) calls.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
test76c(void)
|
||||||
|
{
|
||||||
|
struct sigaction act, oact;
|
||||||
|
struct itimerval it;
|
||||||
|
struct sockaddr_in sin;
|
||||||
|
socklen_t len;
|
||||||
|
int sfd;
|
||||||
|
|
||||||
|
subtest = 3;
|
||||||
|
|
||||||
|
if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) e(1);
|
||||||
|
|
||||||
|
memset(&sin, 0, sizeof(sin));
|
||||||
|
sin.sin_family = AF_INET;
|
||||||
|
/* Binding to an arbitrary port is fine. */
|
||||||
|
if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) e(2);
|
||||||
|
|
||||||
|
if (listen(sfd, 1) < 0) e(3);
|
||||||
|
|
||||||
|
act.sa_handler = dummy_handler;
|
||||||
|
sigfillset(&act.sa_mask);
|
||||||
|
act.sa_flags = 0;
|
||||||
|
if (sigaction(SIGALRM, &act, &oact) < 0) e(4);
|
||||||
|
|
||||||
|
memset(&it, 0, sizeof(it));
|
||||||
|
it.it_value.tv_sec = 0;
|
||||||
|
it.it_value.tv_usec = 10000;
|
||||||
|
if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(5);
|
||||||
|
|
||||||
|
/* This will block until the timer fires. */
|
||||||
|
len = sizeof(sin);
|
||||||
|
if (accept(sfd, (struct sockaddr *)&sin, &len) >= 0) e(6);
|
||||||
|
if (errno != EINTR) e(7);
|
||||||
|
|
||||||
|
if (close(sfd) < 0) e(8);
|
||||||
|
|
||||||
|
if (sigaction(SIGUSR1, &oact, NULL) < 0) e(9);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to trigger semi-concurrent processing of normal system calls and
|
||||||
|
* postponed PM requests for a single process within VFS.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
test76d(void)
|
||||||
|
{
|
||||||
|
struct utsname name;
|
||||||
|
struct sigaction act, oact;
|
||||||
|
struct itimerval it;
|
||||||
|
int r, fd, pfd[2], count, status;
|
||||||
|
time_t stime, etime, runtime = 30 /*seconds*/;
|
||||||
|
char buf[3], *pbuf;
|
||||||
|
|
||||||
|
subtest = 4;
|
||||||
|
|
||||||
|
/* This test would kill wimpy platforms such as ARM. */
|
||||||
|
if (uname(&name) < 0) e(1);
|
||||||
|
if (!strcmp(name.machine, "arm")) return;
|
||||||
|
|
||||||
|
act.sa_handler = dummy_handler;
|
||||||
|
sigfillset(&act.sa_mask);
|
||||||
|
act.sa_flags = 0;
|
||||||
|
if (sigaction(SIGALRM, &act, &oact) < 0) e(2);
|
||||||
|
|
||||||
|
if (pipe(pfd) < 0) e(3);
|
||||||
|
|
||||||
|
/* Pre-fill the pipe. */
|
||||||
|
if ((pbuf = malloc(PIPE_BUF - 1)) == NULL) e(4);
|
||||||
|
|
||||||
|
if (write(pfd[1], pbuf, PIPE_BUF - 1) != PIPE_BUF - 1) e(5);
|
||||||
|
|
||||||
|
free(pbuf);
|
||||||
|
|
||||||
|
switch (fork()) {
|
||||||
|
case 0:
|
||||||
|
if (close(pfd[1]) < 0) e(6);
|
||||||
|
|
||||||
|
/* Read from the pipe, but more slowly than the writer. */
|
||||||
|
while ((r = read(pfd[0], buf, 2)) != 0)
|
||||||
|
if (r < 0) e(7);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
case -1:
|
||||||
|
e(8);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (fork()) {
|
||||||
|
case 0:
|
||||||
|
if (close(pfd[0]) < 0) e(9);
|
||||||
|
|
||||||
|
time(&stime);
|
||||||
|
|
||||||
|
/* Start an alarm mayhem. */
|
||||||
|
it.it_value.tv_sec = 0;
|
||||||
|
it.it_value.tv_usec = 1;
|
||||||
|
it.it_interval.tv_sec = 0;
|
||||||
|
it.it_interval.tv_usec = 1;
|
||||||
|
if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(10);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Then start writing to the pipe, in such a way that the
|
||||||
|
* write operation will be suspended in every so many cases.
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
if (write(pfd[1], buf, 3) < 0 && errno != EINTR)
|
||||||
|
e(11);
|
||||||
|
|
||||||
|
time(&etime);
|
||||||
|
} while ((int)(etime - stime) < runtime);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
case -1:
|
||||||
|
e(12);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (close(pfd[0]) < 0) e(13);
|
||||||
|
if (close(pfd[1]) < 0) e(14);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First give the two processes a while to run regularly. Then start
|
||||||
|
* creating additional noise to keep the VFS worker threads busy.
|
||||||
|
*/
|
||||||
|
runtime /= 2;
|
||||||
|
|
||||||
|
sleep(runtime);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As of writing, VFS has less than 20 worker threads. Create more
|
||||||
|
* processes than that.
|
||||||
|
*/
|
||||||
|
for (count = 2; count < 20; count++) {
|
||||||
|
switch (fork()) {
|
||||||
|
case 0:
|
||||||
|
time(&stime);
|
||||||
|
|
||||||
|
do {
|
||||||
|
/*
|
||||||
|
* Opening a character device blocks the
|
||||||
|
* calling thread, hopefully causing work to be
|
||||||
|
* queued. Sadly, in practice, the high
|
||||||
|
* priorities of system processes prevent this
|
||||||
|
* case from occurring frequently. It works
|
||||||
|
* better with a driver that has a priority
|
||||||
|
* below that of of user processes.
|
||||||
|
*/
|
||||||
|
if ((fd = open("/dev/null", O_WRONLY)) < 0)
|
||||||
|
e(15);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
time(&etime);
|
||||||
|
} while ((int)(etime - stime) < runtime);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
case -1:
|
||||||
|
e(16);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for all children to shut down. */
|
||||||
|
while (count-- > 0) {
|
||||||
|
if (wait(&status) <= 0) e(17);
|
||||||
|
if (!WIFEXITED(status)) e(18);
|
||||||
|
if (WEXITSTATUS(status) != 0) e(19);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sigaction(SIGUSR1, &oact, NULL) < 0) e(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to get a nonblocking select(2) call to be interrupted by a signal.
|
||||||
|
* In the future, VFS should prevent this from happening at all; for now, we
|
||||||
|
* just want to make sure it does not result in disaster when it does happen.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
test76e(void)
|
||||||
|
{
|
||||||
|
struct utsname name;
|
||||||
|
struct sigaction act, oact;
|
||||||
|
struct itimerval it;
|
||||||
|
struct timeval tv;
|
||||||
|
fd_set set;
|
||||||
|
int tfd[2], left;
|
||||||
|
|
||||||
|
subtest = 5;
|
||||||
|
|
||||||
|
/* This test would kill wimpy platforms such as ARM. */
|
||||||
|
if (uname(&name) < 0) e(1);
|
||||||
|
if (!strcmp(name.machine, "arm")) return;
|
||||||
|
|
||||||
|
if (openpty(&tfd[0], &tfd[1], NULL, NULL, NULL) < 0) e(2);
|
||||||
|
|
||||||
|
act.sa_handler = dummy_handler;
|
||||||
|
sigfillset(&act.sa_mask);
|
||||||
|
act.sa_flags = 0;
|
||||||
|
if (sigaction(SIGALRM, &act, &oact) < 0) e(3);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start an alarm mayhem. We have to try to get a signal in between
|
||||||
|
* VFS sending a select request to TTY, and TTY replying to VFS with
|
||||||
|
* initial results.
|
||||||
|
*/
|
||||||
|
it.it_value.tv_sec = 0;
|
||||||
|
it.it_value.tv_usec = 1;
|
||||||
|
it.it_interval.tv_sec = 0;
|
||||||
|
it.it_interval.tv_usec = 1;
|
||||||
|
if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(4);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now issue nonblocking selects until we get interrupted, or until
|
||||||
|
* we have gone through a hardcoded maximum of attempts.
|
||||||
|
*/
|
||||||
|
left = 100000;
|
||||||
|
do {
|
||||||
|
if (--left == 0) break;
|
||||||
|
|
||||||
|
FD_ZERO(&set);
|
||||||
|
FD_SET(tfd[0], &set); /* reading from master should block */
|
||||||
|
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
} while (select(2, &set, NULL, NULL, &tv) >= 0);
|
||||||
|
|
||||||
|
if (left > 0 && errno != EINTR) e(5);
|
||||||
|
|
||||||
|
it.it_value.tv_sec = 0;
|
||||||
|
it.it_value.tv_usec = 0;
|
||||||
|
if (setitimer(ITIMER_REAL, &it, NULL) < 0) e(6);
|
||||||
|
|
||||||
|
/* The call failed, so the set must be unmodified. */
|
||||||
|
if (left > 0 && !FD_SET(tfd[0], &set)) e(7);
|
||||||
|
|
||||||
|
if (close(tfd[0]) < 0) e(8);
|
||||||
|
if (close(tfd[1]) < 0) e(9);
|
||||||
|
|
||||||
|
if (sigaction(SIGUSR1, &oact, NULL) < 0) e(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int i, m;
|
||||||
|
|
||||||
|
start(76);
|
||||||
|
|
||||||
|
if (argc == 2)
|
||||||
|
m = atoi(argv[1]);
|
||||||
|
else
|
||||||
|
m = 0xFF;
|
||||||
|
|
||||||
|
for (i = 0; i < ITERATIONS; i++) {
|
||||||
|
if (m & 0x01) test76a();
|
||||||
|
if (m & 0x02) test76b();
|
||||||
|
if (m & 0x04) test76c();
|
||||||
|
if (m & 0x08) test76d();
|
||||||
|
if (m & 0x10) test76e();
|
||||||
|
}
|
||||||
|
|
||||||
|
quit();
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user