1 2 // SPDX-License-Identifier: GPL-2.0 3 4 #include <linux/compiler.h> 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <sys/prctl.h> 8 #include <sys/wait.h> 9 #include <unistd.h> 10 11 #include "../tests.h" 12 13 static int loops = 100; 14 static char buf; 15 int context_switch_loop_work = 1234; 16 17 #define write_block(fd) \ 18 do { \ 19 if (write(fd, &buf, 1) <= 0) \ 20 return 1; \ 21 } while (0) 22 23 #define read_block(fd) \ 24 do { \ 25 if (read(fd, &buf, 1) <= 0) \ 26 return 1; \ 27 } while (0) 28 29 /* Not static to avoid LTO clobbering the function name */ 30 int context_switch_loop_proc1(int in_fd, int out_fd); 31 int context_switch_loop_proc1(int in_fd, int out_fd) 32 { 33 for (int i = 0; i < loops; i++) { 34 read_block(in_fd); 35 context_switch_loop_work += i * 3; 36 write_block(out_fd); 37 } 38 return 0; 39 } 40 41 int context_switch_loop_proc2(int in_fd, int out_fd); 42 int context_switch_loop_proc2(int in_fd, int out_fd) 43 { 44 for (int i = 0; i < loops; i++) { 45 write_block(out_fd); 46 context_switch_loop_work += i * 7; 47 read_block(in_fd); 48 } 49 return 0; 50 } 51 52 /* 53 * Launches two processes that take turns to execute a multiplication N times 54 */ 55 static int context_switch_loop(int argc, const char **argv) 56 { 57 int a_to_b[2], b_to_a[2]; 58 pid_t proc1_pid; 59 int status; 60 int ret; 61 62 if (argc > 0) { 63 loops = atoi(argv[0]); 64 if (loops < 0) { 65 fprintf(stderr, "Invalid number of loops: %s\n", argv[0]); 66 return 1; 67 } 68 } 69 70 if (pipe(a_to_b) || pipe(b_to_a)) { 71 perror("Pipe error"); 72 return 1; 73 } 74 75 proc1_pid = fork(); 76 if (proc1_pid < 0) { 77 perror("Fork error"); 78 return 1; 79 } 80 81 if (!proc1_pid) { 82 close(a_to_b[0]); 83 close(b_to_a[1]); 84 prctl(PR_SET_NAME, "proc1", 0, 0, 0); 85 ret = context_switch_loop_proc1(b_to_a[0], a_to_b[1]); 86 close(a_to_b[1]); 87 close(b_to_a[0]); 88 exit(ret); 89 } 90 91 close(a_to_b[1]); 92 close(b_to_a[0]); 93 prctl(PR_SET_NAME, "proc2", 0, 0, 0); 94 ret = context_switch_loop_proc2(a_to_b[0], b_to_a[1]); 95 close(a_to_b[0]); 96 close(b_to_a[1]); 97 98 if (ret) { 99 kill(proc1_pid, SIGKILL); 100 return ret; 101 } 102 103 if (waitpid(proc1_pid, &status, 0) != proc1_pid || !WIFEXITED(status) || 104 WEXITSTATUS(status)) 105 return 1; 106 107 return 0; 108 } 109 110 DEFINE_WORKLOAD(context_switch_loop); 111