Testing Your CHPOX Installation
Once you have finished, you can test your first CHPOX installation using Listing One (chpoxtest.c).
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/socket.h> #include <sys/un.h> #include <sys/wait.h> #include <errno.h> static volatile sig_atomic_t print_count = 0; void sighandler(int signo) { printf("Executing signal handler\n"); sleep(10); print_count = 1; } void reader_process(int fd, const char *fname, int delay) { FILE *input, *pfile; char buf[256]; printf("reader enter\n"); pfile = fdopen(fd, "w"); input = fopen(fname, "r"); if (!input) { perror(fname); exit(EXIT_FAILURE); } while (fgets(buf, sizeof(buf), input) != NULL) { printf("reader\n"); sleep(delay); fputs(buf, pfile); fflush(pfile); } printf("reader exit\n"); } void writer_process(int fd, const char *fname) { FILE *output, *sfile; char buf[256]; printf("writer enter\n"); sfile = fdopen(fd, "r"); output = fopen(fname, "w"); if (!output) { perror(fname); exit(EXIT_FAILURE); } while (fgets(buf, sizeof(buf), sfile) != NULL) { printf("writer\n"); fputs(buf, output); fflush(output); } printf("writer exit\n"); } int main(int argc, char **argv) { /* Pipe discriptors */ int pfd[2]; /* Socketpair descriptors */ int sfd[2]; int delay; pid_t pid; FILE *input, *output; char buf[256]; int val; struct sigaction sa; int count = 0; sigset_t mask; if (argc != 4) { fprintf(stderr, "Usage: %s <delay> <input> <output>\n", argv[0]); exit(EXIT_FAILURE); } delay = atoi(argv[1]); /* Let's create communication channels ...*/ if (pipe(pfd) == -1) { perror("pipe"); exit(EXIT_FAILURE); } if (socketpair(PF_UNIX, SOCK_STREAM, 0, sfd) == -1) { perror("socketpair"); exit(EXIT_FAILURE); } /* ... and fork children */ pid = fork(); switch (pid) { case -1: perror("fork 1"); exit(EXIT_FAILURE); case 0: close(pfd[0]); close(sfd[0]); close(sfd[1]); reader_process(pfd[1], argv[2], delay); exit(EXIT_SUCCESS); } close(pfd[1]); pid = fork(); switch (pid) { case -1: perror("fork 2"); exit(EXIT_FAILURE); case 0: close(pfd[1]); close(sfd[1]); writer_process(sfd[0], argv[3]); exit(EXIT_SUCCESS); } close(sfd[0]); /* And let's do our hard work */ input = fdopen(pfd[0], "r"); output = fdopen(sfd[1], "w"); memset(&sa, 0, sizeof(sa)); sa.sa_handler = sighandler; sigaction(SIGUSR1, &sa, NULL); sigemptyset(&mask); sigaddset(&mask, SIGUSR1); for (;;) { if (print_count) { printf("numbers processed: %d\n", count); print_count = 0; } sigprocmask(SIG_BLOCK, &mask, NULL); if (fgets(buf, sizeof(buf), input) == NULL) break; printf("main\n"); val = atoi(buf); fprintf(output, "%d\n", val * val); fflush(output); sigprocmask(SIG_UNBLOCK, &mask, NULL); count++; } fclose(input); fclose(output); wait(NULL); wait(NULL); exit(EXIT_SUCCESS); }
Listing Two is the Makefile for compiling chpoxtest.c.
The program forks two new children, creates a pipe and a UNIX socket for IPC between forked children, and sets a signal handler for the parent. This enables the parent to print the current progress to standard output every time a SIGUSR1 signal is received.
CFLAGS = -Wall -O2 CC=gcc chpoxtest: chpoxtest.o clean: rm -f -- chpoxtest *.o .PHONY: all clean