#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #define MY_SIGNAL SIGUSR1 /** * Print error message and exit. */ static void my_error(int errnum, const char *msg) { char buf[1024]; strerror_r(errnum, buf, sizeof(buf)); fprintf(stderr, "%s: [%d] %s\n", msg, errnum, buf); exit(1); } /** * Signal handler. */ static void my_handler(int signum) { ; } static void my_sigaction(int signum, siginfo_t *info, void *data) { ; } /** * Child reader. */ static void do_child(int reader) { int i, rv, data; fd_set readfds; struct timeval timeout; struct sigaction oldact, act; act.sa_handler = my_handler; act.sa_sigaction = my_sigaction; sigemptyset(&act.sa_mask); sigaddset(&act.sa_mask, MY_SIGNAL); act.sa_flags = 0; act.sa_restorer = NULL; rv = sigaction(MY_SIGNAL, &act, &oldact); if (rv < 0) my_error(errno, "C: sigaction() failed"); for (i = 100; i > 0; i--) { FD_ZERO(&readfds); FD_SET(reader, &readfds); timeout.tv_sec = 1; timeout.tv_usec = 0; again: rv = select(reader + 1, &readfds, NULL, NULL, &timeout); switch (rv) { case -1: /* error */ switch (errno) { case EINTR: printf("C: EINTR\n"); goto again; default: my_error(errno, "C: select() failed"); break; } break; case 0: /* timeout */ printf("C: timeout %d\n", i); break; case 1: /* readable */ rv = read(reader, &data, sizeof(data)); switch (rv) { case -1: /* error */ my_error(errno, "C: read() failed"); case sizeof(data): printf("C: read %d\n", data); break; default: printf("C: strange read: %d\n", rv); break; } break; default: printf("C: strange select: %d\n", rv); break; } } } /** * Parent writer. */ static void do_parent(int writer, pid_t child) { int i, rv; unsigned int usecs; for (i = 100; i > 0; i--) { usecs = random() % 2000000L; rv = usleep(usecs); if (rv < 0) my_error(errno, "P: usleep() failed"); if (i & 1) { printf("P: sending signal\n"); rv = kill(child, MY_SIGNAL); if (rv < 0) my_error(errno, "P: kill() failed"); } else { printf("P: sending character\n"); rv = write(writer, &i, sizeof(i)); switch (rv) { case -1: /* error */ my_error(errno, "P: write() failed"); case sizeof(i): break; default: printf("P: strange write: %d\n", rv); break; } } } } /** * Main tester. */ int main(int argc, char *argv[], char *envp[]) { int rv; pid_t pid; int pipefd[2]; /* reader, writer */ rv = pipe2(pipefd, 0 /* | O_NONBLOCK | O_CLOEXEC */); if (rv < 0) my_error(errno, "pipe() failed"); pid = fork(); switch (pid) { case -1: /* error */ my_error(errno, "fork() failed"); case 0: /* child */ close(pipefd[1]); /* close writer */ do_child(pipefd[0]); /* reader */ break; default: /* parent */ close(pipefd[0]); /* close reader */ do_parent(pipefd[1], pid); /* writer */ break; } return 0; }