239 lines
4.2 KiB
C
239 lines
4.2 KiB
C
/* Test case written by Bharat Joshi */
|
|
#include <sys/cdefs.h>
|
|
__RCSID("$NetBSD: t_fifo.c,v 1.2 2017/01/10 22:36:29 christos Exp $");
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <err.h>
|
|
#include <signal.h>
|
|
|
|
#ifndef STANDALONE
|
|
#include <atf-c.h>
|
|
#endif
|
|
|
|
#define FIFO_FILE_PATH "./fifo_file"
|
|
#define NUM_MESSAGES 20
|
|
#define MSG_SIZE 240
|
|
#define MESSAGE "I am fine"
|
|
|
|
static int verbose = 0;
|
|
|
|
/*
|
|
* child_writer
|
|
*
|
|
* Function that runs in child context and opens and write to the FIFO.
|
|
*/
|
|
static void
|
|
child_writer(void)
|
|
{
|
|
ssize_t rv;
|
|
int fd;
|
|
size_t count;
|
|
char message[MSG_SIZE] = MESSAGE;
|
|
static const struct timespec ts = { 0, 10000 };
|
|
|
|
/* Open the fifo in write-mode */
|
|
for (;;) {
|
|
fd = open(FIFO_FILE_PATH, O_WRONLY, 0);
|
|
if (fd == -1) {
|
|
if (errno == EINTR)
|
|
continue;
|
|
err(1, "Child: can't open fifo in write mode");
|
|
}
|
|
break;
|
|
}
|
|
|
|
for (count = 0; count < NUM_MESSAGES; count++) {
|
|
rv = write(fd, message, MSG_SIZE);
|
|
if (rv == -1) {
|
|
warn("Child: Failed to write");
|
|
break;
|
|
}
|
|
if (rv != MSG_SIZE)
|
|
warnx("Child: wrote only %zd", rv);
|
|
nanosleep(&ts, NULL);
|
|
}
|
|
|
|
close(fd);
|
|
if (verbose) {
|
|
printf("Child: Closed the fifo file\n");
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* _sigchild_handler
|
|
*
|
|
* Called when a sigchild is delivered
|
|
*/
|
|
static void
|
|
sigchild_handler(int signo)
|
|
{
|
|
if (verbose) {
|
|
if (signo == SIGCHLD) {
|
|
printf("Got sigchild\n");
|
|
} else {
|
|
printf("Got %d signal\n", signo);
|
|
}
|
|
fflush(stdout);
|
|
}
|
|
|
|
}
|
|
|
|
static int
|
|
run(void)
|
|
{
|
|
pid_t pid;
|
|
ssize_t rv;
|
|
int fd, status;
|
|
size_t buf_size = MSG_SIZE;
|
|
char buf[MSG_SIZE];
|
|
struct sigaction action;
|
|
static const struct timespec ts = { 0, 500000000 };
|
|
|
|
/* Catch sigchild Signal */
|
|
memset(&action, 0, sizeof(action));
|
|
action.sa_handler = sigchild_handler;
|
|
sigemptyset(&action.sa_mask);
|
|
|
|
if (sigaction(SIGCHLD, &action, NULL) == -1)
|
|
err(1, "sigaction");
|
|
|
|
(void)unlink(FIFO_FILE_PATH);
|
|
/* First create a fifo */
|
|
if (mkfifo(FIFO_FILE_PATH, S_IRUSR | S_IWUSR) == -1)
|
|
err(1, "mkfifo");
|
|
|
|
switch ((pid = fork())) {
|
|
case -1:
|
|
err(1, "fork");
|
|
case 0:
|
|
/* Open the file in write mode so that subsequent read
|
|
* from parent side does not block the parent..
|
|
*/
|
|
if ((fd = open(FIFO_FILE_PATH, O_WRONLY, 0)) == -1)
|
|
err(1, "failed to open fifo");
|
|
|
|
/* In child */
|
|
child_writer();
|
|
return 0;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (verbose) {
|
|
printf("Child pid is %d\n", pid );
|
|
fflush(stdout);
|
|
}
|
|
|
|
/* In parent */
|
|
for (;;) {
|
|
if ((fd = open(FIFO_FILE_PATH, O_RDONLY, 0)) == -1) {
|
|
if (errno == EINTR)
|
|
continue;
|
|
else
|
|
err(1, "Failed to open the fifo in read mode");
|
|
}
|
|
/* Read mode is opened */
|
|
break;
|
|
|
|
}
|
|
|
|
nanosleep(&ts, NULL);
|
|
if (verbose) {
|
|
printf("Was sleeping...\n");
|
|
fflush(stdout);
|
|
}
|
|
|
|
for (;;) {
|
|
rv = read(fd, buf, buf_size);
|
|
|
|
if (rv == -1) {
|
|
warn("Failed to read");
|
|
if (errno == EINTR) {
|
|
if (verbose) {
|
|
printf("Parent interrupted, "
|
|
"continuing...\n");
|
|
fflush(stdout);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if (rv == 0) {
|
|
if (verbose) {
|
|
printf("Writers have closed, looks like we "
|
|
"are done\n");
|
|
fflush(stdout);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (verbose) {
|
|
printf("Received %zd bytes message '%s'\n", rv, buf);
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
|
|
close(fd);
|
|
|
|
if (verbose) {
|
|
printf("We are done.. now reap the child");
|
|
fflush(stdout);
|
|
}
|
|
|
|
// Read the child...
|
|
while (waitpid(pid, &status, 0) == -1)
|
|
if (errno != EINTR) {
|
|
warn("Failed to reap the child");
|
|
return 1;
|
|
}
|
|
|
|
if (verbose) {
|
|
printf("We are done completely\n");
|
|
fflush(stdout);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#ifndef STANDALONE
|
|
ATF_TC(parent_child);
|
|
|
|
ATF_TC_HEAD(parent_child, tc)
|
|
{
|
|
atf_tc_set_md_var(tc, "descr", "Checks that when a fifo is shared "
|
|
"between a reader parent and a writer child, that read will "
|
|
"return EOF, and not get stuck after the child exits");
|
|
}
|
|
|
|
ATF_TC_BODY(parent_child, tc)
|
|
{
|
|
ATF_REQUIRE(run() == 0);
|
|
}
|
|
|
|
ATF_TP_ADD_TCS(tp)
|
|
{
|
|
ATF_TP_ADD_TC(tp, parent_child);
|
|
|
|
return atf_no_error();
|
|
}
|
|
#else
|
|
int
|
|
main(void)
|
|
{
|
|
verbose = 1;
|
|
return run();
|
|
}
|
|
#endif
|