---
.../testing/selftests/xcall_prefetch/Makefile | 37 ++++
.../selftests/xcall_prefetch/echo_client.c | 119 +++++++++++++
.../xcall_prefetch/echo_client_multi | Bin 0 -> 21896 bytes
.../selftests/xcall_prefetch/echo_server.c | 110 ++++++++++++
.../selftests/xcall_prefetch/echo_test.c | 52 ++++++
.../xcall_prefetch/mulit_close_test.c | 48 +++++
.../xcall_prefetch/multi_write_test.c | 77 ++++++++
.../xcall_prefetch/signal_recovery_test.c | 164 ++++++++++++++++++
.../xcall_prefetch/thundering_herd_test.c | 119 +++++++++++++
.../testing/selftests/xcall_prefetch/utils.h | 54 ++++++
.../xcall_prefetch/xcall_prefetch_test.sh | 39 +++++
11 files changed, 819 insertions(+)
create mode 100644 tools/testing/selftests/xcall_prefetch/Makefile
create mode 100644 tools/testing/selftests/xcall_prefetch/echo_client.c
create mode 100755 tools/testing/selftests/xcall_prefetch/echo_client_multi
create mode 100644 tools/testing/selftests/xcall_prefetch/echo_server.c
create mode 100644 tools/testing/selftests/xcall_prefetch/echo_test.c
create mode 100644 tools/testing/selftests/xcall_prefetch/mulit_close_test.c
create mode 100644 tools/testing/selftests/xcall_prefetch/multi_write_test.c
create mode 100644 tools/testing/selftests/xcall_prefetch/signal_recovery_test.c
create mode 100644 tools/testing/selftests/xcall_prefetch/thundering_herd_test.c
create mode 100644 tools/testing/selftests/xcall_prefetch/utils.h
create mode 100755 tools/testing/selftests/xcall_prefetch/xcall_prefetch_test.sh
diff --git a/tools/testing/selftests/xcall_prefetch/Makefile b/tools/testing/selftests/xcall_prefetch/Makefile
new file mode 100644
index 000000000000..5bd509df66e0
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/Makefile
@@ -0,0 +1,37 @@
+CFLAGS += -Wall -Wextra -g
+TEST_GEN_FILES := echo_server echo_client echo_test multi_write_test thundering_herd_test mulit_close_test signal_recovery_test
+
+# enable debug
+# echo_client: CFLAGS += -DDEBUG=1
+# echo_server: CFLAGS += -DDEBUG=1
+# multi_write_test: CFLAGS += -DDEBUG=1
+# thundering_herd_test: CFLAGS += -DDEBUG=1
+# mulit_close_test: CFLAGS += -DDEBUG=1
+# signal_recovery_test: CFLAGS += -DDEBUG=1
+
+all: $(TEST_GEN_FILES)
+
+echo_server: echo_server.c
+ $(CC) $(CFLAGS) $< -o $@
+
+echo_client: echo_client.c
+ $(CC) $(CFLAGS) $< -o $@
+
+echo_test: echo_test.c
+ $(CC) $(CFLAGS) $< -o $@
+
+multi_write_test: multi_write_test.c
+ $(CC) $(CFLAGS) $< -o $@
+
+thundering_herd_test: thundering_herd_test.c
+ $(CC) $(CFLAGS) $< -o $@
+
+mulit_close_test: mulit_close_test.c
+ $(CC) $(CFLAGS) $< -o $@
+
+signal_recovery_test: signal_recovery_test.c
+ $(CC) $(CFLAGS) $< -o $@
+
+.PHONY: all
+
+include ../lib.mk
diff --git a/tools/testing/selftests/xcall_prefetch/echo_client.c b/tools/testing/selftests/xcall_prefetch/echo_client.c
new file mode 100644
index 000000000000..2e3c41b2b14e
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/echo_client.c
@@ -0,0 +1,119 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+#include <errno.h>
+
+#include "./utils.h"
+
+#define DEBUG
+
+void *client(void *arg)
+{
+ int thread_id = *(int *)arg;
+ int sock = 0;
+ struct sockaddr_in serv_addr;
+ struct epoll_event ev, events[MAX_EVENTS];
+ const char* test_messages[MAX_MSGS];
+
+ if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ handle_error("client:%d create socket failed\n", thread_id);
+ }
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_port = htons(PORT);
+
+ if (inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr) <= 0) {
+ close(sock);
+ handle_error("client:%d invalid address\n", thread_id);
+ }
+ if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr))) {
+ close(sock);
+ handle_error("client:%d connection failed\n", thread_id);
+ }
+
+ debug_printf("Thread %d connected\n", thread_id);
+
+ int epoll_fd = epoll_create1(0);
+ if (epoll_fd == -1) {
+ handle_error("client:%d epoll_create1 failed\n", thread_id);
+ }
+
+ ev.events = EPOLLIN;
+ ev.data.fd = sock;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sock, &ev) == -1) {
+ handle_error("client:%d epoll_ctl add sock failed\n", thread_id);
+ }
+
+ test_messages[0] = "hello world.";
+ test_messages[1] = generate_number_string(100);
+ test_messages[2] = generate_number_string(1024);
+ test_messages[3] = generate_number_string(4096);
+
+
+ for (int i = 0; i < MAX_MSGS; i++) {
+ const char* msg = test_messages[i];
+ ssize_t msg_len = strlen(msg);
+ if (send(sock, msg, msg_len, 0) != msg_len) {
+ handle_error("client:%d send failed\n", thread_id);
+ }
+
+ debug_printf("Client:%d send %s\n", thread_id, msg);
+
+ int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
+ if (nfds == -1) {
+ handle_error("client:%d epoll_wait failed\n", thread_id);
+ }
+
+ for (int n = 0; n < nfds; ++n) {
+ if (events[n].data.fd == sock) {
+ char buffer[BUFFER_SIZE] = {0};
+ ssize_t read_bytes = read(sock, buffer, BUFFER_SIZE);
+
+ if (read_bytes <= 0) {
+ close(sock);
+ if (read_bytes == 0) {
+ handle_error("client:%d server disconnected\n", thread_id);
+ } else {
+ handle_error("client:%d read failed\n", thread_id);
+ }
+ } else {
+ debug_printf("Client:%d received %s\n", thread_id, buffer);
+ if (strncmp(msg, buffer, msg_len) != 0) {
+ handle_error("client:%d error: response does not match sent message\n", thread_id);
+ }
+ }
+ }
+ }
+ }
+
+ close(sock);
+ pthread_exit(NULL);
+}
+
+int main()
+{
+ pthread_t threads[NUM_THREADS];
+ int ret;
+
+ for (int i = 0; i < NUM_THREADS; i++) {
+ ret = pthread_create(&threads[i], NULL, client, &i);
+ if (ret != 0) {
+ perror("pthread_create failed");
+ continue;
+ }
+ }
+
+ for (int i = 0; i < NUM_THREADS; i++) {
+ if (threads[i] != 0) {
+ pthread_join(threads[i], NULL);
+ }
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/echo_client_multi b/tools/testing/selftests/xcall_prefetch/echo_client_multi
new file mode 100755
index 0000000000000000000000000000000000000000..36aa08d6e12f6e8ec73b2a7f8eb567225eb0b2f8
GIT binary patch
literal 21896
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
awoFy7Ql!(JO@(L8TPHL=YcsHk?7sjWb7VRI
literal 0
HcmV?d00001
diff --git a/tools/testing/selftests/xcall_prefetch/echo_server.c b/tools/testing/selftests/xcall_prefetch/echo_server.c
new file mode 100644
index 000000000000..49c1ea035788
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/echo_server.c
@@ -0,0 +1,110 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/epoll.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "./utils.h"
+
+static int client_id_counter = 0;
+char buffers[NUM_THREADS][BUFFER_SIZE];
+
+int main() {
+ int server_fd, epoll_fd;
+ struct sockaddr_in address;
+ struct epoll_event ev, events[MAX_EVENTS];
+ struct client_info *clients[MAX_EVENTS] = {0};
+
+ if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
+ handle_error("socket failed\n");
+ }
+
+ address.sin_family = AF_INET;
+ address.sin_addr.s_addr = INADDR_ANY;
+ address.sin_port = htons(PORT);
+
+ if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
+ handle_error("bind failed\n");
+ }
+
+ if (listen(server_fd, 100) < 0) {
+ handle_error("listen failed\n");
+ }
+
+ debug_printf("Server listening on port %d...\n", PORT);
+
+ epoll_fd = epoll_create1(0);
+ if (epoll_fd == -1) {
+ handle_error("epoll_create1\n");
+ }
+
+ ev.events = EPOLLIN;
+ ev.data.fd = server_fd;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev) == -1) {
+ handle_error("epoll_ctl: server_fd\n");
+ }
+
+ while (1) {
+ int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
+ if (nfds == -1) {
+ handle_error("epoll_wait failed\n");
+ }
+
+ for (int n = 0; n < nfds; ++n) {
+ if (events[n].data.fd == server_fd) {
+ int client_fd;
+ socklen_t addr_len = sizeof(address);
+ if ((client_fd = accept(server_fd, (struct sockaddr *)&address, &addr_len)) < 0) {
+ debug_printf("accept failed\n");
+ goto fail;
+ }
+
+ struct client_info *info = malloc(sizeof(struct client_info));
+ info->fd = client_fd;
+ info->id = client_id_counter++;
+ info->addr = address;
+
+ clients[client_fd] = info;
+ debug_printf("new connection accepted client:%d\n", info->id);
+
+ int flags = fcntl(client_fd, F_GETFL, 0);
+ fcntl(client_fd, F_SETFL, flags | O_NONBLOCK);
+
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = client_fd;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &ev) == -1) {
+ debug_printf("epoll_ctl: client_fd\n");
+ goto fail;
+ }
+ } else {
+ int client_fd = events[n].data.fd;
+ // char buffer[BUFFER_SIZE] = {0};
+ struct client_info *info = clients[client_fd];
+ char *buffer = buffers[info->id];
+ memset(buffers[info->id], 0, BUFFER_SIZE);
+ ssize_t read_bytes = read(client_fd, buffer, BUFFER_SIZE);
+
+ if (read_bytes <= 0) {
+ if (read_bytes == 0) {
+ debug_printf("client:%d disconnected\n", info->id);
+ continue;
+ } else {
+ debug_printf("read failed\n");
+ }
+ goto fail;
+ } else {
+ debug_printf("Server received client:%d %s\n", info->id, buffer);
+ write(client_fd, buffer, read_bytes);
+ }
+ }
+ }
+ }
+
+fail:
+ close(server_fd);
+ return -1;
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/echo_test.c b/tools/testing/selftests/xcall_prefetch/echo_test.c
new file mode 100644
index 000000000000..fc7180869f3c
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/echo_test.c
@@ -0,0 +1,52 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include "./utils.h"
+
+int main() {
+ pid_t server_pid, client_pid;
+ int server_status, client_status;
+
+ server_pid = fork();
+ if (server_pid == 0) {
+ execl("./echo_server", "./echo_server", NULL);
+ printf("execl echo_server failed\n");
+ exit(EXIT_FAILURE);
+ } else if (server_pid < 0) {
+ printf("fork echo_server failed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ sleep(1);
+
+ client_pid = fork();
+ if (client_pid == 0) {
+ execl("./echo_client", "./echo_client", NULL);
+ printf("execl client failed\n");
+ exit(EXIT_FAILURE);
+ } else if (client_pid < 0) {
+ printf("fork echo_client failed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ waitpid(client_pid, &client_status, 0);
+
+ kill(server_pid, SIGTERM);
+ waitpid(server_pid, &server_status, 0);
+
+ if (WIFEXITED(client_status)) {
+ int exit_code = WEXITSTATUS(client_status);
+ if (exit_code == 0) {
+ printf("echo test %sok%s.\n", ANSI_COLOR_GREEN, ANSI_COLOR_RESET);
+ exit(EXIT_SUCCESS);
+ } else {
+ printf("echo test %sfailed%s.\n", ANSI_COLOR_RED, ANSI_COLOR_RESET);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ printf("echo test %sfailed%s.\n", ANSI_COLOR_RED, ANSI_COLOR_RESET);
+ exit(EXIT_FAILURE);
+ }
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/mulit_close_test.c b/tools/testing/selftests/xcall_prefetch/mulit_close_test.c
new file mode 100644
index 000000000000..fae0407e8473
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/mulit_close_test.c
@@ -0,0 +1,48 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+
+#include "./utils.h"
+
+int main() {
+ int epoll_fd;
+ struct epoll_event ev, events[1];
+ int ret = -1;
+
+ int fds[2];
+ socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
+
+ epoll_fd = epoll_create1(0);
+ ev.events = EPOLLIN | EPOLLHUP;
+ ev.data.fd = fds[0];
+ epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fds[0], &ev);
+
+ if (fork() == 0) {
+ close(fds[1]);
+ exit(0);
+ }
+
+ close(fds[1]);
+
+ int nfds = epoll_wait(epoll_fd, events, 1, 1000);
+
+ if (nfds == 1) {
+ if (events[0].events & EPOLLHUP) {
+ ret = 0;
+ }
+ }
+
+ close(fds[0]);
+ close(epoll_fd);
+ if (!ret) {
+ debug_printf("epoll_wait detected EPOLLHUP!\n");
+ printf("multi close test %sok%s.\n", ANSI_COLOR_GREEN, ANSI_COLOR_RESET);
+ return 0;
+ }
+
+ printf("multi close test %sfailed%s.\n", ANSI_COLOR_RED, ANSI_COLOR_RESET);
+
+ return -1;
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/multi_write_test.c b/tools/testing/selftests/xcall_prefetch/multi_write_test.c
new file mode 100644
index 000000000000..0af07b742e73
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/multi_write_test.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <sys/wait.h>
+
+#include "./utils.h"
+
+#define NUM_CHILDREN 3
+
+int main() {
+ int epoll_fd, pipe_fd[2];
+ struct epoll_event ev, events[MAX_EVENTS];
+ char buffer[BUFFER_SIZE];
+
+ if (pipe(pipe_fd) == -1) {
+ handle_error("pipe failed\n");
+ }
+
+ epoll_fd = epoll_create1(0);
+ if (epoll_fd == -1) {
+ handle_error("epoll_create1 failed\n");
+ }
+
+ ev.events = EPOLLIN;
+ ev.data.fd = pipe_fd[0];
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, pipe_fd[0], &ev) == -1) {
+ handle_error("epoll_ctl failed\n");
+ }
+
+ for (int i = 0; i < NUM_CHILDREN; i++) {
+ sleep(1);
+ pid_t pid = fork();
+ if (pid == 0) {
+ close(pipe_fd[0]);
+ char msg[10];
+ sprintf(msg, "%d %d\n", 2*i, 2*i+1);
+ write(pipe_fd[1], msg, strlen(msg));
+ exit(0);
+ } else if (pid < 0) {
+ handle_error("fork failed\n");
+ }
+ }
+
+ sleep(1);
+
+ int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
+ if (nfds == -1) {
+ handle_error("epoll_wait failed\n");
+ }
+
+ debug_printf("epoll_wait returned %d events\n", nfds);
+
+ for (int i = 0; i < nfds; i++) {
+ if (events[i].data.fd == pipe_fd[0]) {
+ ssize_t n = read(pipe_fd[0], buffer, BUFFER_SIZE);
+ if (n > 0) {
+ debug_printf("Received: %.*s", (int)n, buffer);
+ }
+ char *expected_msg = "0 1\n2 3\n4 5\n";
+ if (strncmp(expected_msg, buffer, strlen(expected_msg)) != 0) {
+ printf("multi write test %sfailed%s.\n", ANSI_COLOR_RED, ANSI_COLOR_RESET);
+ handle_error("expected msg: %s, buffer: %s", expected_msg, buffer);
+ }
+ }
+ }
+
+ for (int i = 0; i < NUM_CHILDREN; i++) {
+ wait(NULL);
+ }
+
+ close(pipe_fd[0]);
+ close(pipe_fd[1]);
+ close(epoll_fd);
+ printf("multi write test %sok%s.\n", ANSI_COLOR_GREEN, ANSI_COLOR_RESET);
+ return 0;
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/signal_recovery_test.c b/tools/testing/selftests/xcall_prefetch/signal_recovery_test.c
new file mode 100644
index 000000000000..9645f8ffec1b
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/signal_recovery_test.c
@@ -0,0 +1,164 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+
+#include "./utils.h"
+
+
+int epoll_fd;
+int server_fd;
+volatile sig_atomic_t signal_received = 0;
+
+void signal_handler() {
+ signal_received = 1;
+}
+
+void* worker_thread() {
+ struct epoll_event events[MAX_EVENTS];
+
+ while (!signal_received) {
+ int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
+ if (nfds == -1) {
+ if (errno == EINTR) {
+ debug_printf("epoll_wait interrupted by signal! re-waiting...\n");
+ continue;
+ } else {
+ handle_error("epoll_wait failed\n");
+ }
+ }
+
+ for (int i = 0; i < nfds; i++) {
+ if (events[i].data.fd == server_fd) {
+ struct sockaddr_in address;
+ socklen_t addr_len = sizeof(address);
+ int client_fd = accept(server_fd, (struct sockaddr*)&address, &addr_len);
+ if (client_fd < 0) {
+ handle_error("accept failed\n");
+ }
+
+ struct epoll_event ev;
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = client_fd;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &ev) < 0) {
+ close(client_fd);
+ handle_error("epoll_ctl failed\n");
+ }
+ } else {
+ char buffer[1024];
+ ssize_t n = read(events[i].data.fd, buffer, sizeof(buffer));
+ if (n <= 0) {
+ if (n < 0) {
+ handle_error("read failed\n");
+ }
+ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
+ close(events[i].data.fd);
+ debug_printf("closing fd %d\n", events[i].data.fd);
+ } else {
+ buffer[n] = '\0';
+ debug_printf("receive: %s\n", buffer);
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void* client_thread() {
+ sleep(1);
+
+ int client_fd = socket(AF_INET, SOCK_STREAM, 0);
+ struct sockaddr_in server_addr = {
+ .sin_family = AF_INET,
+ .sin_port = htons(8082),
+ .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
+ };
+
+ if (connect(client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
+ debug_printf("connect failed\n");
+ goto fail;
+ }
+
+ const char *msg = "hello world.";
+ write(client_fd, msg, strlen(msg));
+ close(client_fd);
+
+ sleep(1);
+
+ debug_printf("Sending SIGUSR1 to interrupt epoll_wait...\n");
+ kill(getpid(), SIGUSR1);
+
+ sleep(1);
+ debug_printf("Testing if epoll_wait can still work after signal...\n");
+
+ client_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (connect(client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
+ debug_printf("connect failed\n");
+ goto fail;
+ }
+
+ const char *msg2 = "hello world again.";
+ if (write(client_fd, msg2, strlen(msg2)) < 0) {
+ goto fail;
+ }
+
+ close(client_fd);
+ return NULL;
+
+fail:
+ close(client_fd);
+ pthread_exit((void *)42);
+}
+
+int main() {
+ pthread_t worker, client;
+
+ signal(SIGUSR1, signal_handler);
+
+ server_fd = socket(AF_INET, SOCK_STREAM, 0);
+ struct sockaddr_in addr = {
+ .sin_family = AF_INET,
+ .sin_port = htons(8082),
+ .sin_addr.s_addr = INADDR_ANY,
+ };
+ bind(server_fd, (struct sockaddr*)&addr, sizeof(addr));
+ listen(server_fd, SOMAXCONN);
+
+ epoll_fd = epoll_create1(0);
+ if (epoll_fd < 0) {
+ handle_error("epoll_create1 failed\n");
+ }
+
+ struct epoll_event ev;
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = server_fd;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev) < 0) {
+ handle_error("epoll_ctl failed\n");
+ }
+
+ pthread_create(&worker, NULL, worker_thread, NULL);
+ pthread_create(&client, NULL, client_thread, NULL);
+
+ void *retval;
+ pthread_join(worker, NULL);
+ pthread_join(client, &retval);
+
+ close(server_fd);
+ close(epoll_fd);
+
+ if (retval != NULL) {
+ printf("signal recovery test %sfailed%s.\n", ANSI_COLOR_RED, ANSI_COLOR_RESET);
+ return -1;
+ }
+
+ printf("signal recovery test %sok%s.\n", ANSI_COLOR_GREEN, ANSI_COLOR_RESET);
+
+ return 0;
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/thundering_herd_test.c b/tools/testing/selftests/xcall_prefetch/thundering_herd_test.c
new file mode 100644
index 000000000000..bf98fcf94b6a
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/thundering_herd_test.c
@@ -0,0 +1,119 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/wait.h>
+#include <string.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "./utils.h"
+
+#define TIMEOUT_MS 1000
+
+int create_client_connection() {
+ struct sockaddr_in addr = {
+ .sin_family = AF_INET,
+ .sin_port = htons(8081),
+ .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
+ };
+
+ int fd = socket(AF_INET, SOCK_STREAM, 0);
+ connect(fd, (struct sockaddr *)&addr, sizeof(addr));
+ return fd;
+}
+
+void set_nonblocking(int fd) {
+ int flags = fcntl(fd, F_GETFL, 0);
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+}
+
+int main() {
+ int listen_fd, epoll_fd;
+ struct sockaddr_in addr = {
+ .sin_family = AF_INET,
+ .sin_port = htons(8081),
+ .sin_addr.s_addr = INADDR_ANY,
+ };
+
+ int shm_id = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT | 0666);
+ int tmp_cnt;
+ int *accept_count = (int *)shmat(shm_id, NULL, 0);
+ *accept_count = 0;
+
+ listen_fd = socket(AF_INET, SOCK_STREAM, 0);
+ set_nonblocking(listen_fd);
+ int reuse = 1;
+ setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
+ bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr));
+ listen(listen_fd, SOMAXCONN);
+
+ for (int i = 0; i < NUM_THREADS; i++) {
+ if (fork() == 0) {
+ usleep(1000 * i);
+ epoll_fd = epoll_create1(0);
+ struct epoll_event ev = {
+ .events = EPOLLIN | EPOLLET,
+ .data.fd = listen_fd,
+ };
+ epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &ev);
+
+ debug_printf("Worker %d waiting...\n", getpid());
+
+ struct epoll_event events[MAX_EVENTS];
+ int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, TIMEOUT_MS);
+
+ if (nfds == -1) {
+ handle_error("epoll_wait failed\n");
+ }
+
+ debug_printf("Worker %d: epoll_wait returned %d events\n", getpid(), nfds);
+
+ int client_fd = accept(listen_fd, NULL, NULL);
+ if (client_fd >= 0) {
+ debug_printf("Worker %d accepted a connection!\n", getpid());
+ __sync_fetch_and_add(accept_count, 1);
+ close(client_fd);
+ } else if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ debug_printf("accept failed\n");
+ }
+
+ close(epoll_fd);
+ exit(0);
+ }
+ }
+
+ sleep(1);
+
+ debug_printf("Parent creating client connection...\n");
+ int client_fd = create_client_connection();
+ sleep(1);
+ close(client_fd);
+
+ int waited = 0;
+ for (int i = 0; i < NUM_THREADS; i++) {
+ if (wait(NULL) < 0 && errno == ECHILD) {
+ break;
+ }
+ waited++;
+ }
+
+ tmp_cnt = *accept_count;
+ debug_printf("Total successful accepts: %d\n", tmp_cnt);
+
+ shmdt(accept_count);
+ shmctl(shm_id, IPC_RMID, NULL);
+ close(listen_fd);
+
+ if (tmp_cnt == 1) {
+ printf("thundering herd test %sok%s.\n", ANSI_COLOR_GREEN, ANSI_COLOR_RESET);
+ return 0;
+ } else {
+ printf("thundering herd test %sfailed%s.\n", ANSI_COLOR_RED, ANSI_COLOR_RESET);
+ return -1;
+ }
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/utils.h b/tools/testing/selftests/xcall_prefetch/utils.h
new file mode 100644
index 000000000000..58959c564119
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/utils.h
@@ -0,0 +1,54 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#define ANSI_COLOR_GREEN "\x1b[32m"
+#define ANSI_COLOR_RED "\x1b[31m"
+#define ANSI_COLOR_RESET "\x1b[0m"
+
+#define PORT 8080
+#define BUFFER_SIZE 4097
+#define MAX_EVENTS 100
+#define MAX_MSGS 4
+#define NUM_THREADS 4
+
+#ifdef DEBUG
+#define debug_printf(fmt, ...) (printf(fmt, ##__VA_ARGS__))
+#else
+#define debug_printf(fmt, ...) (void)fmt
+#endif
+
+struct client_info {
+ int fd;
+ int id;
+ struct sockaddr_in addr;
+};
+
+void handle_error(const char *format, ...)
+{
+ printf("%s", format);
+ exit(EXIT_FAILURE);
+}
+
+char* generate_number_string(int length)
+{
+ if (length <= 0) {
+ printf("\nnumber string length invalid\n");
+ return NULL;
+ }
+
+ char* result = (char*)malloc((length + 1) * sizeof(char));
+ if (result == NULL) {
+ printf("\nnumber string malloc failed\n");
+ return NULL;
+ }
+
+ for (int i = 0; i < length; i++) {
+ result[i] = '0' + (i % 10);
+ }
+
+ result[length] = '\0';
+
+ return result;
+}
\ No newline at end of file
diff --git a/tools/testing/selftests/xcall_prefetch/xcall_prefetch_test.sh b/tools/testing/selftests/xcall_prefetch/xcall_prefetch_test.sh
new file mode 100755
index 000000000000..e9a990dac69a
--- /dev/null
+++ b/tools/testing/selftests/xcall_prefetch/xcall_prefetch_test.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+RED="\033[31m"
+GREEN="\033[32m"
+RESET="\033[0m"
+
+make clean
+make
+
+if [ -e "/proc/$$/xcall" ]; then
+ echo 22 > "/proc/$$/xcall"
+ echo @22 > "/proc/$$/xcall"
+ echo "enable xcall epoll prefetch, pid is $$."
+else
+ echo "Warnning: not enable xcall."
+fi
+
+./echo_test
+sleep 1
+
+./multi_write_test
+sleep 1
+
+./thundering_herd_test
+sleep 1
+
+./mulit_close_test
+sleep 1
+
+./signal_recovery_test
+sleep 1
+
+if [ $? -eq 0 ]; then
+ echo -e "${GREEN}tests passed successfully.${RESET}"
+ exit 0
+else
+ echo -e "${RED}tests failed.${RESET}"
+ exit 1
+fi
\ No newline at end of file
--
2.34.1