Home | History | Annotate | Line # | Download | only in fifofs
      1  1.1  christos /* Test case written by Bharat Joshi */
      2  1.1  christos #include <sys/cdefs.h>
      3  1.2  christos __RCSID("$NetBSD: t_fifo.c,v 1.2 2017/01/10 22:36:29 christos Exp $");
      4  1.1  christos 
      5  1.1  christos #include <sys/types.h>
      6  1.1  christos #include <sys/wait.h>
      7  1.2  christos #include <sys/stat.h>
      8  1.1  christos 
      9  1.1  christos #include <stdio.h>
     10  1.1  christos #include <stdlib.h>
     11  1.1  christos #include <unistd.h>
     12  1.1  christos #include <fcntl.h>
     13  1.1  christos #include <errno.h>
     14  1.1  christos #include <string.h>
     15  1.1  christos #include <err.h>
     16  1.1  christos #include <signal.h>
     17  1.1  christos 
     18  1.1  christos #ifndef STANDALONE
     19  1.1  christos #include <atf-c.h>
     20  1.1  christos #endif
     21  1.1  christos 
     22  1.1  christos #define FIFO_FILE_PATH       "./fifo_file"
     23  1.1  christos #define NUM_MESSAGES         20
     24  1.1  christos #define MSG_SIZE             240
     25  1.1  christos #define MESSAGE              "I am fine"
     26  1.1  christos 
     27  1.1  christos static int verbose = 0;
     28  1.1  christos 
     29  1.1  christos /*
     30  1.1  christos  * child_writer
     31  1.1  christos  *
     32  1.1  christos  * Function that runs in child context and opens and write to the FIFO.
     33  1.1  christos  */
     34  1.1  christos static void
     35  1.1  christos child_writer(void)
     36  1.1  christos {
     37  1.1  christos 	ssize_t rv;
     38  1.1  christos 	int fd;
     39  1.1  christos 	size_t count;
     40  1.1  christos 	char message[MSG_SIZE] = MESSAGE;
     41  1.1  christos 	static const struct timespec ts = { 0, 10000 };
     42  1.1  christos 
     43  1.1  christos 	/* Open the fifo in write-mode */
     44  1.1  christos 	for (;;) {
     45  1.1  christos 		fd = open(FIFO_FILE_PATH, O_WRONLY, 0);
     46  1.1  christos 		if (fd == -1) {
     47  1.1  christos 			if (errno == EINTR)
     48  1.1  christos 				continue;
     49  1.1  christos 			err(1, "Child: can't open fifo in write mode");
     50  1.1  christos 		}
     51  1.1  christos 		break;
     52  1.1  christos 	}
     53  1.1  christos 
     54  1.1  christos 	for (count = 0; count < NUM_MESSAGES; count++) {
     55  1.1  christos 		rv = write(fd, message, MSG_SIZE);
     56  1.1  christos 		if (rv == -1) {
     57  1.1  christos 			warn("Child: Failed to write");
     58  1.1  christos 			break;
     59  1.1  christos 		}
     60  1.1  christos 		if (rv != MSG_SIZE)
     61  1.1  christos 			warnx("Child: wrote only %zd", rv);
     62  1.1  christos 		nanosleep(&ts, NULL);
     63  1.1  christos 	}
     64  1.1  christos 
     65  1.1  christos 	close(fd);
     66  1.1  christos 	if (verbose) {
     67  1.1  christos 		printf("Child: Closed the fifo file\n");
     68  1.1  christos 		fflush(stdout);
     69  1.1  christos 	}
     70  1.1  christos }
     71  1.1  christos 
     72  1.1  christos /*
     73  1.1  christos  * _sigchild_handler
     74  1.1  christos  *
     75  1.1  christos  * Called when a sigchild is delivered
     76  1.1  christos  */
     77  1.1  christos static void
     78  1.1  christos sigchild_handler(int signo)
     79  1.1  christos {
     80  1.1  christos 	if (verbose) {
     81  1.1  christos 		if (signo == SIGCHLD) {
     82  1.1  christos 			printf("Got sigchild\n");
     83  1.1  christos 		} else {
     84  1.1  christos 			printf("Got %d signal\n", signo);
     85  1.1  christos 		}
     86  1.1  christos 		fflush(stdout);
     87  1.1  christos 	}
     88  1.1  christos 
     89  1.1  christos }
     90  1.1  christos 
     91  1.1  christos static int
     92  1.1  christos run(void)
     93  1.1  christos {
     94  1.1  christos 	pid_t pid;
     95  1.1  christos 	ssize_t rv;
     96  1.1  christos 	int fd, status;
     97  1.1  christos 	size_t buf_size = MSG_SIZE;
     98  1.1  christos 	char buf[MSG_SIZE];
     99  1.1  christos 	struct sigaction action;
    100  1.1  christos 	static const struct timespec ts = { 0, 500000000 };
    101  1.1  christos 
    102  1.1  christos 	/* Catch sigchild Signal */
    103  1.1  christos 	memset(&action, 0, sizeof(action));
    104  1.1  christos 	action.sa_handler = sigchild_handler;
    105  1.1  christos 	sigemptyset(&action.sa_mask);
    106  1.1  christos 
    107  1.1  christos 	if (sigaction(SIGCHLD, &action, NULL) == -1)
    108  1.1  christos 		err(1, "sigaction");
    109  1.1  christos 
    110  1.1  christos 	(void)unlink(FIFO_FILE_PATH);
    111  1.1  christos 	/* First create a fifo */
    112  1.1  christos 	if (mkfifo(FIFO_FILE_PATH, S_IRUSR | S_IWUSR) == -1)
    113  1.1  christos 		err(1, "mkfifo");
    114  1.1  christos 
    115  1.1  christos 	switch ((pid = fork())) {
    116  1.1  christos 	case -1:
    117  1.1  christos 		err(1, "fork");
    118  1.1  christos 	case 0:
    119  1.1  christos 		/* Open the file in write mode so that subsequent read
    120  1.1  christos 		 * from parent side does not block the parent..
    121  1.1  christos 		 */
    122  1.1  christos 		if ((fd = open(FIFO_FILE_PATH, O_WRONLY, 0)) == -1)
    123  1.1  christos 			err(1, "failed to open fifo");
    124  1.1  christos 
    125  1.1  christos 		/* In child */
    126  1.1  christos 		child_writer();
    127  1.1  christos 		return 0;
    128  1.1  christos 
    129  1.1  christos 	default:
    130  1.1  christos 		break;
    131  1.1  christos 	}
    132  1.1  christos 
    133  1.1  christos 	if (verbose) {
    134  1.1  christos 		printf("Child pid is %d\n", pid );
    135  1.1  christos 		fflush(stdout);
    136  1.1  christos 	}
    137  1.1  christos 
    138  1.1  christos 	/* In parent */
    139  1.1  christos 	for (;;) {
    140  1.1  christos 		if ((fd = open(FIFO_FILE_PATH, O_RDONLY, 0)) == -1) {
    141  1.1  christos 			if (errno == EINTR)
    142  1.1  christos 				continue;
    143  1.1  christos 			else
    144  1.1  christos 				err(1, "Failed to open the fifo in read mode");
    145  1.1  christos 		}
    146  1.1  christos 		/* Read mode is opened */
    147  1.1  christos 		break;
    148  1.1  christos 
    149  1.1  christos 	}
    150  1.1  christos 
    151  1.1  christos 	nanosleep(&ts, NULL);
    152  1.1  christos 	if (verbose) {
    153  1.1  christos 		printf("Was sleeping...\n");
    154  1.1  christos 		fflush(stdout);
    155  1.1  christos 	}
    156  1.1  christos 
    157  1.1  christos 	for (;;) {
    158  1.1  christos 		rv = read(fd, buf, buf_size);
    159  1.1  christos 
    160  1.1  christos 		if (rv == -1) {
    161  1.1  christos 			warn("Failed to read");
    162  1.1  christos 			if (errno == EINTR) {
    163  1.1  christos 				if (verbose) {
    164  1.1  christos 					printf("Parent interrupted, "
    165  1.1  christos 					    "continuing...\n");
    166  1.1  christos 					fflush(stdout);
    167  1.1  christos 				}
    168  1.1  christos 				continue;
    169  1.1  christos 			}
    170  1.1  christos 
    171  1.1  christos 			break;
    172  1.1  christos 		}
    173  1.1  christos 
    174  1.1  christos 		if (rv == 0) {
    175  1.1  christos 			if (verbose) {
    176  1.1  christos 				printf("Writers have closed, looks like we "
    177  1.1  christos 				    "are done\n");
    178  1.1  christos 				fflush(stdout);
    179  1.1  christos 			}
    180  1.1  christos 			break;
    181  1.1  christos 		}
    182  1.1  christos 
    183  1.1  christos 		if (verbose) {
    184  1.1  christos 			printf("Received %zd bytes message '%s'\n", rv, buf);
    185  1.1  christos 			fflush(stdout);
    186  1.1  christos 		}
    187  1.1  christos 	}
    188  1.1  christos 
    189  1.1  christos 	close(fd);
    190  1.1  christos 
    191  1.1  christos 	if (verbose) {
    192  1.1  christos 		printf("We are done.. now reap the child");
    193  1.1  christos 		fflush(stdout);
    194  1.1  christos 	}
    195  1.1  christos 
    196  1.1  christos 	// Read the child...
    197  1.1  christos 	while (waitpid(pid, &status, 0) == -1)
    198  1.1  christos 		if (errno != EINTR) {
    199  1.1  christos 			warn("Failed to reap the child");
    200  1.1  christos 			return 1;
    201  1.1  christos 		}
    202  1.1  christos 
    203  1.1  christos 	if (verbose) {
    204  1.1  christos 		printf("We are done completely\n");
    205  1.1  christos 		fflush(stdout);
    206  1.1  christos 	}
    207  1.1  christos 	return 0;
    208  1.1  christos }
    209  1.1  christos 
    210  1.1  christos #ifndef STANDALONE
    211  1.1  christos ATF_TC(parent_child);
    212  1.1  christos 
    213  1.1  christos ATF_TC_HEAD(parent_child, tc)
    214  1.1  christos {
    215  1.1  christos         atf_tc_set_md_var(tc, "descr", "Checks that when a fifo is shared "
    216  1.1  christos 	    "between a reader parent and a writer child, that read will "
    217  1.1  christos 	    "return EOF, and not get stuck after the child exits");
    218  1.1  christos }
    219  1.1  christos 
    220  1.1  christos ATF_TC_BODY(parent_child, tc)
    221  1.1  christos {
    222  1.1  christos         ATF_REQUIRE(run() == 0);
    223  1.1  christos }
    224  1.1  christos 
    225  1.1  christos ATF_TP_ADD_TCS(tp)
    226  1.1  christos {
    227  1.1  christos         ATF_TP_ADD_TC(tp, parent_child);
    228  1.1  christos 
    229  1.1  christos         return atf_no_error();
    230  1.1  christos }
    231  1.1  christos #else
    232  1.1  christos int
    233  1.1  christos main(void)
    234  1.1  christos {
    235  1.1  christos 	verbose = 1;
    236  1.1  christos 	return run();
    237  1.1  christos }
    238  1.1  christos #endif
    239