[BACK]Return to t_fifo.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / tests / fs / fifofs

File: [cvs.NetBSD.org] / src / tests / fs / fifofs / t_fifo.c (download)

Revision 1.1, Wed Dec 21 00:17:07 2011 UTC (12 years, 4 months ago) by christos
Branch: MAIN
CVS Tags: yamt-pagecache-base9, yamt-pagecache-base8, yamt-pagecache-base7, yamt-pagecache-base6, yamt-pagecache-base5, yamt-pagecache-base4, tls-maxphys-base, tls-maxphys, tls-earlyentropy-base, tls-earlyentropy, riastradh-xf86-video-intel-2-7-1-pre-2-21-15, riastradh-drm2-base3, riastradh-drm2-base2, riastradh-drm2-base1, riastradh-drm2-base, riastradh-drm2, pgoyette-localcount-base, pgoyette-localcount-20170107, pgoyette-localcount-20161104, pgoyette-localcount-20160806, pgoyette-localcount-20160726, netbsd-7-nhusb-base-20170116, netbsd-7-nhusb-base, netbsd-7-nhusb, netbsd-7-base, netbsd-7-2-RELEASE, netbsd-7-1-RELEASE, netbsd-7-1-RC2, netbsd-7-1-RC1, netbsd-7-1-2-RELEASE, netbsd-7-1-1-RELEASE, netbsd-7-1, netbsd-7-0-RELEASE, netbsd-7-0-RC3, netbsd-7-0-RC2, netbsd-7-0-RC1, netbsd-7-0-2-RELEASE, netbsd-7-0-1-RELEASE, netbsd-7-0, netbsd-7, netbsd-6-base, netbsd-6-1-RELEASE, netbsd-6-1-RC4, netbsd-6-1-RC3, netbsd-6-1-RC2, netbsd-6-1-RC1, netbsd-6-1-5-RELEASE, netbsd-6-1-4-RELEASE, netbsd-6-1-3-RELEASE, netbsd-6-1-2-RELEASE, netbsd-6-1-1-RELEASE, netbsd-6-1, netbsd-6-0-RELEASE, netbsd-6-0-RC2, netbsd-6-0-RC1, netbsd-6-0-6-RELEASE, netbsd-6-0-5-RELEASE, netbsd-6-0-4-RELEASE, netbsd-6-0-3-RELEASE, netbsd-6-0-2-RELEASE, netbsd-6-0-1-RELEASE, netbsd-6-0, netbsd-6, matt-nb6-plus-nbase, matt-nb6-plus-base, matt-nb6-plus, localcount-20160914, agc-symver-base, agc-symver
Branch point for: yamt-pagecache, pgoyette-localcount

Add a test for the latest fifofs fix.

/* Test case written by Bharat Joshi */
#include <sys/cdefs.h>
__RCSID("$NetBSD: t_fifo.c,v 1.1 2011/12/21 00:17:07 christos Exp $");

#include <sys/types.h>
#include <sys/wait.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