Skip to content

Instantly share code, notes, and snippets.

@pasko
Last active November 9, 2023 14:29
Show Gist options
  • Save pasko/c016b27e9a4d466b641a988861beac41 to your computer and use it in GitHub Desktop.
Save pasko/c016b27e9a4d466b641a988861beac41 to your computer and use it in GitHub Desktop.
// g++ -D_GNU_SOURCE -O2 -Wall async_read_test.cc
#include <fcntl.h>
#include <poll.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cstdint>
#include <iostream>
#include <string>
#define HANDLE_EINTR(x) \
({ \
decltype(x) eintr_wrapper_result; \
do { \
eintr_wrapper_result = (x); \
} while (eintr_wrapper_result == -1 && \
(errno == EINTR || errno == EAGAIN)); \
eintr_wrapper_result; \
})
int main() {
int pipe_fd[2];
if (pipe2(pipe_fd, O_NONBLOCK) == -1) {
perror("pipe2");
exit(1);
}
if (HANDLE_EINTR(write(pipe_fd[1], "H", 1)) != 1) {
perror("write");
exit(1);
}
char read_value;
if (HANDLE_EINTR(read(pipe_fd[0], &read_value, 1)) != 1) {
perror("read");
exit(1);
}
if (read_value != 'H') {
std::cerr << "Incorrect value read from the pipe" << std::endl;
exit(1);
}
std::cout << "Pipe is working" << std::endl;
int read_ret = read(pipe_fd[0], &read_value, 0);
std::cout << "Reading zero-length from an empty pipe returns: "
<< read_ret
<< ", errno=" << errno << std::endl;
if (HANDLE_EINTR(write(pipe_fd[1], "N", 1)) != 1) {
perror("write2");
exit(1);
}
read_ret = read(pipe_fd[0], &read_value, 0);
std::cout << "Reading from a non-empty pipe returns: "
<< read_ret
<< ", errno=" << errno << std::endl;
struct pollfd poll_fd{};
poll_fd.fd = pipe_fd[0];
poll_fd.events = POLLIN;
if (poll(&poll_fd, 1, 0) == -1) {
perror("poll");
exit(1);
}
int revents = poll_fd.revents;
if (revents & POLLIN) {
std::cout << "Poll non-empty pipe: available data detected" << std::endl;
} else if (revents != 0) {
std::string err1, err2;
err1 = revents == POLLERR ? "POLLERR" : "";
err2 = revents == POLLHUP ? "POLLHUP" : "";
std::cout << "Poll errors: " << err1 << " " << err2 << std::endl;
}
if (HANDLE_EINTR(read(pipe_fd[0], &read_value, 1)) != 1) {
perror("read from non-empty pipe");
exit(1);
}
if (read_value != 'N') {
std::cerr << "Incorrect value read from the pipe" << std::endl;
exit(1);
}
struct pollfd poll_fd2{};
poll_fd2.fd = pipe_fd[0];
poll_fd2.events = POLLIN;
if (poll(&poll_fd, 1, 0) == -1) {
perror("poll empty pipe");
exit(1);
}
revents = poll_fd2.revents;
if (revents != 0) {
std::cerr << "Poll empty pipe: revents=" << revents << std::endl;
exit(1);
}
std::cout << "Poll empty pipe: no data detected" << std::endl;
int sockets[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
perror("socketpair");
exit(1);
}
int bufferSize = 32 * 1024;
setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
int send_sock = sockets[1];
int recv_sock = sockets[0];
if (sendto(send_sock, "C", 1, MSG_DONTWAIT | MSG_NOSIGNAL, 0, 0) == -1) {
perror("sendto");
exit(1);
}
if (recvfrom(recv_sock, &read_value, 1, MSG_DONTWAIT, NULL, NULL) == -1) {
perror("recvfrom");
exit(1);
}
if (read_value != 'C') {
std::cerr << "Incorrect value read from the socket" << std::endl;
exit(1);
}
read_ret = read(recv_sock, &read_value, 0);
std::cout << "Reading zero-length from an empty socket returns: "
<< read_ret
<< ", errno=" << errno << std::endl;
if (sendto(send_sock, "D", 1, MSG_DONTWAIT | MSG_NOSIGNAL, 0, 0) == -1) {
perror("sendto");
exit(1);
}
read_ret = read(recv_sock, &read_value, 0);
std::cout << "Reading zero-length from a non-empty socket returns: "
<< read_ret
<< ", errno=" << errno << std::endl;
read_ret = read(recv_sock, &read_value, 1);
std::cout << "Reading 1 byte from a non-empty socket returns: "
<< read_ret
<< ", errno=" << errno << std::endl;
std::string reading_status_msg;
if (read_ret == 1 && read_value == 'D') {
std::cout << " Reading was correct" << std::endl;
} else if (read_ret != 1) {
std::cout << "Wrong number of bytes was read: " << read_ret << std::endl;
} else {
std::cout << "Wrong value was read: " << read_value << std::endl;
}
return 0;
}
@pasko
Copy link
Author

pasko commented Nov 6, 2023

Output:

Pipe is working
Reading zero-length from an empty pipe returns: 0, errno=0
Reading from a non-empty pipe returns: 0, errno=0
Poll non-empty pipe: available data detected
Poll empty pipe: no data detected
Reading zero-length from an empty socket returns: 0, errno=0
Reading zero-length from a non-empty socket returns: 0, errno=0
Reading 1 byte from a non-empty socket returns: 1, errno=0
  Reading was correct

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment