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