122 lines
4.0 KiB
C
122 lines
4.0 KiB
C
// User-mode smoke test for POSIX pipe, nonblocking, and poll semantics.
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <poll.h>
|
|
#include <sys/stat.h>
|
|
|
|
// Writes one NUL-terminated diagnostic to stdout.
|
|
static void print(const char* text) {
|
|
(void)write(1, text, strlen(text));
|
|
}
|
|
|
|
// Terminates the smoke test with one diagnostic.
|
|
static void fail(const char* message) {
|
|
print("posix_pipe_smoke: ");
|
|
print(message);
|
|
print("\n");
|
|
exit(1);
|
|
}
|
|
|
|
// Requires one descriptor to expose the expected immediate poll bits.
|
|
static short poll_now(int fd, short events) {
|
|
struct pollfd descriptor;
|
|
descriptor.fd = fd;
|
|
descriptor.events = events;
|
|
descriptor.revents = 0;
|
|
int result = poll(&descriptor, 1, 0);
|
|
if (result < 0)
|
|
fail("poll failed");
|
|
return descriptor.revents;
|
|
}
|
|
|
|
// Runs pipe lifetime, readiness, EOF, broken-pipe, and atomic-write checks.
|
|
int main(void) {
|
|
int descriptors[2];
|
|
if (pipe(descriptors) != 0)
|
|
fail("pipe failed");
|
|
|
|
struct stat st;
|
|
if (fstat(descriptors[0], &st) != 0 || !S_ISFIFO(st.st_mode))
|
|
fail("read endpoint is not FIFO");
|
|
if (fstat(descriptors[1], &st) != 0 || !S_ISFIFO(st.st_mode))
|
|
fail("write endpoint is not FIFO");
|
|
|
|
if (poll_now(descriptors[0], POLLIN) & POLLIN)
|
|
fail("empty pipe reported readable");
|
|
if (!(poll_now(descriptors[1], POLLOUT) & POLLOUT))
|
|
fail("empty pipe write endpoint not writable");
|
|
|
|
if (write(descriptors[1], "abc", 3) != 3)
|
|
fail("basic write failed");
|
|
if (!(poll_now(descriptors[0], POLLIN) & POLLIN))
|
|
fail("pipe data did not become readable");
|
|
|
|
char buffer[4] = {0, 0, 0, 0};
|
|
if (read(descriptors[0], buffer, 3) != 3 || strcmp(buffer, "abc") != 0)
|
|
fail("basic read failed");
|
|
|
|
if (fcntl(descriptors[0], F_SETFL, O_NONBLOCK) != 0)
|
|
fail("read F_SETFL O_NONBLOCK failed");
|
|
errno = 0;
|
|
if (read(descriptors[0], buffer, 1) != -1 || errno != EAGAIN)
|
|
fail("empty nonblocking read did not return EAGAIN");
|
|
|
|
int writerAlias = dup(descriptors[1]);
|
|
if (writerAlias < 0)
|
|
fail("writer dup failed");
|
|
if (close(descriptors[1]) != 0)
|
|
fail("close original writer failed");
|
|
if (poll_now(descriptors[0], POLLIN | POLLHUP) & POLLHUP)
|
|
fail("HUP published before final writer closed");
|
|
if (close(writerAlias) != 0)
|
|
fail("close final writer failed");
|
|
|
|
short eofEvents = poll_now(descriptors[0], POLLIN | POLLHUP);
|
|
if ((eofEvents & (POLLIN | POLLHUP)) != (POLLIN | POLLHUP))
|
|
fail("EOF readiness transition missing");
|
|
if (read(descriptors[0], buffer, 1) != 0)
|
|
fail("final writer close did not produce EOF");
|
|
if (close(descriptors[0]) != 0)
|
|
fail("close read endpoint failed");
|
|
|
|
if (pipe(descriptors) != 0)
|
|
fail("second pipe failed");
|
|
if (close(descriptors[0]) != 0)
|
|
fail("close second read endpoint failed");
|
|
errno = 0;
|
|
if (write(descriptors[1], "x", 1) != -1 || errno != EPIPE)
|
|
fail("write without readers did not return EPIPE");
|
|
if (close(descriptors[1]) != 0)
|
|
fail("close broken writer failed");
|
|
|
|
if (pipe(descriptors) != 0)
|
|
fail("atomic pipe failed");
|
|
if (fcntl(descriptors[1], F_SETFL, O_NONBLOCK) != 0)
|
|
fail("write F_SETFL O_NONBLOCK failed");
|
|
char atomic[PIPE_BUF];
|
|
memset(atomic, 'A', sizeof(atomic));
|
|
for (;;) {
|
|
errno = 0;
|
|
ssize_t written = write(descriptors[1], atomic, sizeof(atomic));
|
|
if (written == (ssize_t)sizeof(atomic))
|
|
continue;
|
|
if (written == -1 && errno == EAGAIN)
|
|
break;
|
|
fail("PIPE_BUF write was partially committed");
|
|
}
|
|
if (poll_now(descriptors[1], POLLOUT) & POLLOUT)
|
|
fail("full pipe still reported writable");
|
|
if (!(poll_now(descriptors[0], POLLIN) & POLLIN))
|
|
fail("full pipe read endpoint not readable");
|
|
|
|
if (close(descriptors[0]) != 0 || close(descriptors[1]) != 0)
|
|
fail("atomic pipe close failed");
|
|
|
|
print("posix_pipe_smoke: PASS\n");
|
|
return 0;
|
|
}
|