1/* 2 * This program is free software; you can redistribute it and/or modify 3 * it under the terms of the GNU General Public License version 2. 4 * 5 * This program is distributed in the hope that it will be useful, 6 * but WITHOUT ANY WARRANTY; without even the implied warranty of 7 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 8 * GNU General Public License for more details. 9 * 10 * Test that the higher numerical values for the priority represent the higher 11 * priorities for the SCHED_RR policy. 12 * 13 * NO OTHER REALTIME PROCESS SHOULD RUN WHEN RUNNING THIS TEST. 14 * 15 * There is no portable way to get the number of CPUs but the test should work 16 * for most of UNIX system (including but not limited to: Linux, Solaris, AIX, 17 * HPUX, *BSD). 18 * Steps: 19 * 1. Get the number of CPUs. 20 * 2. Set the scheduling policy to SCHED_RR with a mean priority. 21 * 3. Lauch as many processes than CPU. The last process set its own priority 22 * to the min value. 23 * 4. Father process set its own priority to the max value. 24 * 5. Both children and father increment a counter in a basic loop. 25 * 6. The father send SIGTERM to the last child and get its counter. If child 26 * counter is reasonably lower than the fathers one, the test is 27 * succesfull. 28 * 7. The father kill all other children. 29 * 30 */ 31 32#include "affinity.h" 33 34#include <sched.h> 35#include <stdio.h> 36#include <signal.h> 37#include <unistd.h> 38#include <stdlib.h> 39#include <errno.h> 40#include "posixtest.h" 41#include "ncpu.h" 42 43#define NB_LOOP 20000000 44#define NB_LOOP_CHILD 200000000 /* shall be much greater than NB_LOOP */ 45 46#define ACCEPTABLE_RATIO 2.0 47 48#define STDIN 0 49#define STDOUT 1 50#define STDERR 2 51 52int nb_child; /* Number of child processes == number of CPUs */ 53int count = 0; 54int the_pipe[2]; 55 56void child_process(int id) 57{ 58 int i; 59 struct sched_param param; 60 61 if (id == nb_child - 1) { 62 param.sched_priority = sched_get_priority_min(SCHED_RR); 63 sched_setparam(getpid(), ¶m); 64 } 65 66 for (i = 0; i < NB_LOOP_CHILD; i++) { 67 count++; 68 } 69} 70 71void sigterm_handler(int signum) 72{ 73 close(STDOUT); 74 close(the_pipe[0]); 75 dup2(the_pipe[1], STDOUT); 76 close(the_pipe[1]); 77 78 printf("*%i*", count); 79 fflush(stdout); 80 81 exit(0); 82} 83 84int main(void) 85{ 86 int child_count, i; 87 struct sched_param param; 88 int *child_pid; 89 float ratio; 90 91 /* Only use a single CPU and one child process 92 when set_affinity is availaible.It's because 93 no matter what value of the counter is set to, 94 There is no guarantee that the LOOP of the child 95 can be certainly big enough on any device at any time. 96 */ 97 int rc = set_affinity_single(); 98 if (rc) { 99 nb_child = get_ncpu(); 100 if (nb_child == -1) { 101 printf("Can not get the number of" 102 "CPUs of your machine.\n"); 103 return PTS_UNRESOLVED; 104 } 105 } else { 106 nb_child = 1; 107 } 108 109 child_pid = malloc(nb_child * sizeof(int)); 110 if (child_pid == NULL) { 111 printf("malloc failed\n"); 112 return PTS_UNRESOLVED; 113 } 114 param.sched_priority = (sched_get_priority_min(SCHED_RR) + 115 sched_get_priority_max(SCHED_RR)) / 2; 116 117 if (sched_setscheduler(getpid(), SCHED_RR, ¶m) == -1) { 118 if (errno == EPERM) { 119 printf 120 ("This process does not have the permission to set its own scheduling policy.\nTry to launch this test as root\n"); 121 } else { 122 perror 123 ("An error occurs when calling sched_setscheduler()"); 124 } 125 return PTS_UNRESOLVED; 126 } 127 128 if (signal(SIGTERM, sigterm_handler) == SIG_ERR) { 129 perror("An error occurs when calling signal()"); 130 return PTS_UNRESOLVED; 131 } 132 133 pipe(the_pipe); 134 135 for (i = 0; i < nb_child; i++) { 136 child_pid[i] = fork(); 137 if (child_pid[i] == -1) { 138 perror("An error occurs when calling fork()"); 139 return PTS_UNRESOLVED; 140 } else if (child_pid[i] == 0) { 141 child_process(i); 142 143 printf("This code should not be executed.\n"); 144 return PTS_UNRESOLVED; 145 } 146 } 147 148 param.sched_priority = sched_get_priority_max(SCHED_RR); 149 if (sched_setparam(0, ¶m) != 0) { 150 perror("An error occurs when calling sched_setparam()"); 151 return PTS_UNRESOLVED; 152 } 153 154 close(STDIN); 155 close(the_pipe[1]); 156 dup2(the_pipe[0], STDIN); 157 close(the_pipe[0]); 158 159 for (i = 0; i < NB_LOOP; i++) { 160 count++; 161 } 162 163 if (kill(child_pid[nb_child - 1], SIGTERM) != 0) { 164 perror("An error occurs when calling kill()"); 165 return PTS_UNRESOLVED; 166 } 167 168 param.sched_priority = sched_get_priority_min(SCHED_RR); 169 if (sched_setparam(0, ¶m) != 0) { 170 perror("An error occurs when calling sched_setparam()"); 171 return PTS_UNRESOLVED; 172 } 173 174 while (scanf("*%i*", &child_count) == 0) 175 sched_yield(); 176 177 for (i = 0; i < (nb_child - 1); i++) { 178 if (kill(child_pid[i], SIGKILL) != 0) { 179 perror("An error occurs when calling kill()"); 180 return PTS_UNRESOLVED; 181 } 182 } 183 184 if (child_count) 185 ratio = (float)count / (float)child_count; 186 187 if (child_count == 0 || ratio >= ACCEPTABLE_RATIO) { 188 printf("Test PASSED\n"); 189 return PTS_PASS; 190 } else if (ratio <= (1 / ACCEPTABLE_RATIO)) { 191 printf 192 ("Higher numerical values for the priority represent the lower priorities.\n"); 193 return PTS_FAIL; 194 } else { 195 printf 196 ("The difference between the processes is not representative.\n"); 197 return PTS_UNRESOLVED; 198 } 199 200} 201