| // SPDX-License-Identifier: GPL-2.0 | |
| #include <linux/compiler.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <sys/prctl.h> | |
| #include <sys/wait.h> | |
| #include <unistd.h> | |
| #include "../tests.h" | |
| static int loops = 100; | |
| static char buf; | |
| int context_switch_loop_work = 1234; | |
| #define write_block(fd) \ | |
| do { \ | |
| if (write(fd, &buf, 1) <= 0) \ | |
| return 1; \ | |
| } while (0) | |
| #define read_block(fd) \ | |
| do { \ | |
| if (read(fd, &buf, 1) <= 0) \ | |
| return 1; \ | |
| } while (0) | |
| /* Not static to avoid LTO clobbering the function name */ | |
| int context_switch_loop_proc1(int in_fd, int out_fd); | |
| int context_switch_loop_proc1(int in_fd, int out_fd) | |
| { | |
| for (int i = 0; i < loops; i++) { | |
| read_block(in_fd); | |
| context_switch_loop_work += i * 3; | |
| write_block(out_fd); | |
| } | |
| return 0; | |
| } | |
| int context_switch_loop_proc2(int in_fd, int out_fd); | |
| int context_switch_loop_proc2(int in_fd, int out_fd) | |
| { | |
| for (int i = 0; i < loops; i++) { | |
| write_block(out_fd); | |
| context_switch_loop_work += i * 7; | |
| read_block(in_fd); | |
| } | |
| return 0; | |
| } | |
| /* | |
| * Launches two processes that take turns to execute a multiplication N times | |
| */ | |
| static int context_switch_loop(int argc, const char **argv) | |
| { | |
| int a_to_b[2], b_to_a[2]; | |
| pid_t proc1_pid; | |
| int status; | |
| int ret; | |
| if (argc > 0) { | |
| loops = atoi(argv[0]); | |
| if (loops < 0) { | |
| fprintf(stderr, "Invalid number of loops: %s\n", argv[0]); | |
| return 1; | |
| } | |
| } | |
| if (pipe(a_to_b) || pipe(b_to_a)) { | |
| perror("Pipe error"); | |
| return 1; | |
| } | |
| proc1_pid = fork(); | |
| if (proc1_pid < 0) { | |
| perror("Fork error"); | |
| return 1; | |
| } | |
| if (!proc1_pid) { | |
| close(a_to_b[0]); | |
| close(b_to_a[1]); | |
| prctl(PR_SET_NAME, "proc1", 0, 0, 0); | |
| ret = context_switch_loop_proc1(b_to_a[0], a_to_b[1]); | |
| close(a_to_b[1]); | |
| close(b_to_a[0]); | |
| exit(ret); | |
| } | |
| close(a_to_b[1]); | |
| close(b_to_a[0]); | |
| prctl(PR_SET_NAME, "proc2", 0, 0, 0); | |
| ret = context_switch_loop_proc2(a_to_b[0], b_to_a[1]); | |
| close(a_to_b[0]); | |
| close(b_to_a[1]); | |
| if (ret) { | |
| kill(proc1_pid, SIGKILL); | |
| return ret; | |
| } | |
| if (waitpid(proc1_pid, &status, 0) != proc1_pid || !WIFEXITED(status) || | |
| WEXITSTATUS(status)) | |
| return 1; | |
| return 0; | |
| } | |
| DEFINE_WORKLOAD(context_switch_loop); |