|
@@ -1,137 +1,195 @@
|
|
|
-#include <stdio.h>
|
|
|
-#include <stdlib.h>
|
|
|
-#include <fcntl.h>
|
|
|
-#include <unistd.h>
|
|
|
#include <errno.h>
|
|
|
+#include <fcntl.h>
|
|
|
#include <signal.h>
|
|
|
+#include <stdio.h>
|
|
|
+#include <stdlib.h>
|
|
|
+#include <string.h>
|
|
|
#include <sys/stat.h>
|
|
|
#include <sys/wait.h>
|
|
|
+#include <unistd.h>
|
|
|
+
|
|
|
+#define TEST_ASSERT(left, right, success_msg, fail_msg) \
|
|
|
+ do { \
|
|
|
+ if ((left) == (right)) { \
|
|
|
+ printf("[PASS] %s\n", success_msg); \
|
|
|
+ } else { \
|
|
|
+ printf("[FAIL] %s: Expected %d, but got %d\n", fail_msg, (right), \
|
|
|
+ (left)); \
|
|
|
+ } \
|
|
|
+ } while (0)
|
|
|
|
|
|
#define FIFO_PATH "/bin/test_fifo" // 使用 /tmp 目录避免权限问题
|
|
|
|
|
|
+typedef struct {
|
|
|
+ int fd;
|
|
|
+ int error_code;
|
|
|
+} FifoWriteResult;
|
|
|
+
|
|
|
// 信号处理函数
|
|
|
void sigpipe_handler(int signo) {
|
|
|
- if (signo == SIGPIPE) {
|
|
|
- printf("Received SIGPIPE signal. Write operation failed.\n");
|
|
|
- }
|
|
|
+ if (signo == SIGPIPE) {
|
|
|
+ printf("Received SIGPIPE signal. Write operation failed.\n");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-void test_fifo_write(const char *scenario_desc, int nonblocking) {
|
|
|
- int fd;
|
|
|
- char *data = "Hello, FIFO!";
|
|
|
- printf("\n--- Testing: %s (nonblocking=%d) ---\n", scenario_desc, nonblocking);
|
|
|
-
|
|
|
- // 设置写模式和非阻塞模式标志
|
|
|
- int flags = O_WRONLY;
|
|
|
- if (nonblocking) {
|
|
|
- flags |= O_NONBLOCK;
|
|
|
+const char *scenarios[] = {"No readers (FIFO never had readers)",
|
|
|
+ "Reader exists but disconnects",
|
|
|
+ "Active reader exists"};
|
|
|
+
|
|
|
+FifoWriteResult test_fifo_write(int scenario_index, int nonblocking) {
|
|
|
+ FifoWriteResult result = {.fd = -1, .error_code = 0};
|
|
|
+ int fd;
|
|
|
+ const char *data = "Hello, FIFO!";
|
|
|
+
|
|
|
+ // Set write mode and non-blocking flag
|
|
|
+ int flags = O_WRONLY;
|
|
|
+ if (nonblocking) {
|
|
|
+ flags |= O_NONBLOCK;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Open the FIFO write end
|
|
|
+ fd = open(FIFO_PATH, flags);
|
|
|
+ if (fd == -1) {
|
|
|
+ result.fd = fd;
|
|
|
+ result.error_code = errno;
|
|
|
+
|
|
|
+ if (errno == ENXIO) {
|
|
|
+ printf("Result: Failed to open FIFO for writing (ENXIO: No readers).\n");
|
|
|
+ } else {
|
|
|
+ perror("Failed to open FIFO for writing");
|
|
|
}
|
|
|
+ return result; // Return early with error details
|
|
|
+ }
|
|
|
|
|
|
- // 打开 FIFO 写端
|
|
|
- fd = open(FIFO_PATH, flags);
|
|
|
- if (fd == -1) {
|
|
|
- if (errno == ENXIO) {
|
|
|
- printf("Result: Failed to open FIFO for writing (ENXIO: No readers).\n");
|
|
|
- } else {
|
|
|
- perror("Failed to open FIFO for writing");
|
|
|
- }
|
|
|
- return;
|
|
|
- }
|
|
|
+ // Write data
|
|
|
+ ssize_t bytes_written = write(fd, data, strlen(data));
|
|
|
+ if (bytes_written == -1) {
|
|
|
+ result.error_code = errno;
|
|
|
|
|
|
- // 写入数据
|
|
|
- ssize_t bytes_written = write(fd, data, sizeof(data));
|
|
|
if (bytes_written == -1) {
|
|
|
- if (errno == EPIPE) {
|
|
|
- printf("Result: Write failed with EPIPE (no readers available).\n");
|
|
|
- } else if (errno == ENXIO) {
|
|
|
- printf("Result: Write failed with ENXIO (FIFO never had readers).\n");
|
|
|
- } else if (errno == EAGAIN) {
|
|
|
- printf("Result: Write failed with EAGAIN (nonblocking write, pipe full or no readers).\n");
|
|
|
- } else {
|
|
|
- perror("Write failed with an unexpected error");
|
|
|
- }
|
|
|
+ if (errno == EPIPE) {
|
|
|
+ printf("Result: Write failed with EPIPE (no readers available).\n");
|
|
|
+ } else if (errno == ENXIO) {
|
|
|
+ printf("Result: Write failed with ENXIO (FIFO never had readers).\n");
|
|
|
+ } else if (errno == EAGAIN) {
|
|
|
+ printf("Result: Write failed with EAGAIN (nonblocking write, pipe full "
|
|
|
+ "or no readers).\n");
|
|
|
+ } else {
|
|
|
+ perror("Write failed with an unexpected error");
|
|
|
+ }
|
|
|
} else {
|
|
|
- printf("Result: Write succeeded. Bytes written: %zd\n", bytes_written);
|
|
|
+ printf("Result: Write succeeded. Bytes written: %zd\n", bytes_written);
|
|
|
}
|
|
|
|
|
|
- // 关闭 FIFO 写端
|
|
|
+ result.fd = fd;
|
|
|
close(fd);
|
|
|
+ return result; // Return with fd and error_code
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void test_case1(int nonblocking) {
|
|
|
- // Case 1: No readers (FIFO never had readers)
|
|
|
- test_fifo_write("No readers (FIFO never had readers)", nonblocking);
|
|
|
+ // Case 1: No readers (FIFO never had readers)
|
|
|
+ FifoWriteResult result = test_fifo_write(0, nonblocking);
|
|
|
+
|
|
|
+ char buffer[100];
|
|
|
+ sprintf(buffer,"Fail with unexpected error %d",result.error_code);
|
|
|
+ TEST_ASSERT(result.error_code, ENXIO,
|
|
|
+ "write(2) fails with the error ENXIO",
|
|
|
+ buffer);
|
|
|
}
|
|
|
|
|
|
void test_case2(int nonblocking) {
|
|
|
- pid_t reader_pid;
|
|
|
-
|
|
|
- // Case 2: Reader exists but disconnects
|
|
|
- reader_pid = fork();
|
|
|
- if (reader_pid == 0) {
|
|
|
- // 子进程充当读端
|
|
|
- int reader_fd = open(FIFO_PATH, O_RDONLY);
|
|
|
- if (reader_fd == -1) {
|
|
|
- perror("Reader failed to open FIFO");
|
|
|
- exit(EXIT_FAILURE);
|
|
|
- }
|
|
|
- sleep(1); // 模拟读端短暂存在
|
|
|
- close(reader_fd);
|
|
|
- exit(EXIT_SUCCESS);
|
|
|
+ pid_t reader_pid;
|
|
|
+
|
|
|
+ // Case 2: Reader exists but disconnects
|
|
|
+ reader_pid = fork();
|
|
|
+ if (reader_pid == 0) {
|
|
|
+ // Child process acts as a reader
|
|
|
+ int reader_fd = open(FIFO_PATH, O_RDONLY);
|
|
|
+ if (reader_fd == -1) {
|
|
|
+ perror("Reader failed to open FIFO");
|
|
|
+ exit(EXIT_FAILURE);
|
|
|
}
|
|
|
-
|
|
|
- sleep(5); // 确保读端已打开
|
|
|
- test_fifo_write("Reader exists but disconnects", nonblocking);
|
|
|
- waitpid(reader_pid, NULL, 0); // 等待读端子进程退出
|
|
|
+ sleep(1); // Simulate a brief existence of the reader
|
|
|
+ close(reader_fd);
|
|
|
+ exit(EXIT_SUCCESS);
|
|
|
+ }
|
|
|
+
|
|
|
+ sleep(5); // Ensure the reader has opened the FIFO
|
|
|
+ FifoWriteResult result = test_fifo_write(1, nonblocking);
|
|
|
+ waitpid(reader_pid, NULL, 0); // Wait for the reader process to exit
|
|
|
+
|
|
|
+ if (nonblocking) {
|
|
|
+ TEST_ASSERT(result.fd != -1 && result.error_code == EPIPE, 1, "Non-Blocking Write failed with EPIPE", "Non-Blocking Write failed with wrong error type");
|
|
|
+ } else {
|
|
|
+ TEST_ASSERT(result.fd != -1 && result.error_code == EPIPE, 1, "Blocking Write failed with EPIPE", "Blocking Write failed with wrong error type");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void test_case3(int nonblocking) {
|
|
|
- pid_t reader_pid;
|
|
|
-
|
|
|
- // Case 3: Active reader exists
|
|
|
- reader_pid = fork();
|
|
|
- if (reader_pid == 0) {
|
|
|
- // 子进程充当读端
|
|
|
- int reader_fd = open(FIFO_PATH, O_RDONLY);
|
|
|
- if (reader_fd == -1) {
|
|
|
- perror("Reader failed to open FIFO");
|
|
|
- exit(EXIT_FAILURE);
|
|
|
- }
|
|
|
- sleep(5); // 保持读端存在
|
|
|
- close(reader_fd);
|
|
|
- exit(EXIT_SUCCESS);
|
|
|
+ pid_t reader_pid;
|
|
|
+
|
|
|
+ // Case 3: Active reader exists
|
|
|
+ reader_pid = fork();
|
|
|
+ if (reader_pid == 0) {
|
|
|
+ // Child process acts as a reader
|
|
|
+ int reader_fd = open(FIFO_PATH, O_RDONLY);
|
|
|
+ if (reader_fd == -1) {
|
|
|
+ perror("Reader failed to open FIFO");
|
|
|
+ exit(EXIT_FAILURE);
|
|
|
}
|
|
|
+ sleep(5); // Keep the reader active
|
|
|
+ close(reader_fd);
|
|
|
+ exit(EXIT_SUCCESS);
|
|
|
+ }
|
|
|
+
|
|
|
+ sleep(1); // Ensure the reader has opened the FIFO
|
|
|
+ FifoWriteResult result = test_fifo_write(2, nonblocking);
|
|
|
|
|
|
- sleep(1); // 确保读端已打开
|
|
|
- test_fifo_write("Active reader exists", nonblocking);
|
|
|
- waitpid(reader_pid, NULL, 0); // 等待读端子进程退出
|
|
|
+ waitpid(reader_pid, NULL, 0); // Wait for the reader process to exit
|
|
|
+
|
|
|
+ TEST_ASSERT(result.error_code, 0, "write succeed", "write failed");
|
|
|
+}
|
|
|
+
|
|
|
+void run_tests(int nonblocking) {
|
|
|
+ for (int i = 0; i < 3; i++) {
|
|
|
+ printf("\n--- Testing: %s (nonblocking=%d) ---\n", scenarios[i],
|
|
|
+ nonblocking);
|
|
|
+ switch (i) {
|
|
|
+ case 0:
|
|
|
+ test_case1(nonblocking);
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ test_case2(nonblocking);
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ test_case3(nonblocking);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
int main() {
|
|
|
- // 设置 SIGPIPE 信号处理
|
|
|
- signal(SIGPIPE, sigpipe_handler);
|
|
|
+ // 设置 SIGPIPE 信号处理
|
|
|
+ signal(SIGPIPE, sigpipe_handler);
|
|
|
|
|
|
- // 创建 FIFO
|
|
|
- if (mkfifo(FIFO_PATH, 0666) == -1 && errno != EEXIST) {
|
|
|
- perror("mkfifo failed");
|
|
|
- exit(EXIT_FAILURE);
|
|
|
- }
|
|
|
+ // 创建 FIFO
|
|
|
+ if (mkfifo(FIFO_PATH, 0666) == -1 && errno != EEXIST) {
|
|
|
+ perror("mkfifo failed");
|
|
|
+ exit(EXIT_FAILURE);
|
|
|
+ }
|
|
|
|
|
|
- // 测试阻塞模式下的三种情况
|
|
|
- // printf("========== Testing Blocking Mode ==========\n");
|
|
|
- // test_case1(0); // 阻塞模式下没有读端
|
|
|
- // test_case2(0); // 阻塞模式下读端断开
|
|
|
- // test_case3(0); // 阻塞模式下读端存在
|
|
|
+ // 测试阻塞模式下的三种情况
|
|
|
+// printf("========== Testing Blocking Mode ==========\n");
|
|
|
+// run_tests(0); // 阻塞模式
|
|
|
|
|
|
- // 测试非阻塞模式下的三种情况
|
|
|
- printf("\n========== Testing Nonblocking Mode ==========\n");
|
|
|
- test_case1(1); // 非阻塞模式下没有读端
|
|
|
- test_case2(1); // 非阻塞模式下读端断开
|
|
|
- test_case3(1); // 非阻塞模式下读端存在
|
|
|
+ // 测试非阻塞模式下的三种情况
|
|
|
+ printf("\n========== Testing Nonblocking Mode ==========\n");
|
|
|
+ run_tests(1); // 非阻塞模式
|
|
|
|
|
|
- // 删除 FIFO
|
|
|
- unlink(FIFO_PATH);
|
|
|
+ // 删除 FIFO
|
|
|
+ unlink(FIFO_PATH);
|
|
|
|
|
|
- printf("\nAll tests completed.\n");
|
|
|
- return 0;
|
|
|
+ printf("\nAll tests completed.\n");
|
|
|
+ return 0;
|
|
|
}
|