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_FIFO 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_FIFO 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#include "affinity.h" 32 33#include <sched.h> 34#include <stdio.h> 35#include <signal.h> 36#include <unistd.h> 37#include <stdlib.h> 38#include <errno.h> 39#include "posixtest.h" 40#include "ncpu.h" 41 42#define NB_LOOP 20000000 43#define NB_LOOP_CHILD 200000000 /* shall be much greater than NB_LOOP */ 44 45#define ACCEPTABLE_RATIO 2.0 46 47#define STDIN 0 48#define STDOUT 1 49#define STDERR 2 50 51int nb_child; /* Number of child processes == number of CPUs */ 52int count = 0; 53int the_pipe[2]; 54 55void child_process(int id) 56{ 57 int i; 58 struct sched_param param; 59 60 if (id == nb_child - 1) { 61 param.sched_priority = sched_get_priority_min(SCHED_FIFO); 62 sched_setparam(getpid(), ¶m); 63 } 64 65 for (i = 0; i < NB_LOOP_CHILD; i++) { 66 count++; 67 } 68} 69 70void sigterm_handler(int signum) 71{ 72 close(STDOUT); 73 close(the_pipe[0]); 74 dup2(the_pipe[1], STDOUT); 75 close(the_pipe[1]); 76 77 printf("*%i*", count); 78 fflush(stdout); 79 80 exit(0); 81} 82 83int main(void) 84{ 85 int child_count, i; 86 struct sched_param param; 87 int *child_pid; 88 float ratio; 89 90 /* Only use a single CPU and one child process 91 when set_affinity is availaible.It's because 92 no matter what value of the counter is set to, 93 There is no guarantee that the LOOP of the child 94 can be certainly big enough on any device at any time. 95 */ 96 int rc = set_affinity_single(); 97 if (rc) { 98 nb_child = get_ncpu(); 99 if (nb_child == -1) { 100 printf("Can not get the number of" 101 "CPUs of your machine.\n"); 102 return PTS_UNRESOLVED; 103 } 104 } else { 105 nb_child = 1; 106 } 107 108 child_pid = malloc(nb_child * sizeof(int)); 109 110 param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + 111 sched_get_priority_max(SCHED_FIFO)) / 2; 112 113 if (sched_setscheduler(getpid(), SCHED_FIFO, ¶m) == -1) { 114 if (errno == EPERM) { 115 printf 116 ("This process does not have the permission to set its own scheduling policy.\nTry to launch this test as root\n"); 117 } else { 118 perror 119 ("An error occurs when calling sched_setscheduler()"); 120 } 121 return PTS_UNRESOLVED; 122 } 123 124 if (signal(SIGTERM, sigterm_handler) == SIG_ERR) { 125 perror("An error occurs when calling signal()"); 126 return PTS_UNRESOLVED; 127 } 128 129 pipe(the_pipe); 130 131 for (i = 0; i < nb_child; i++) { 132 child_pid[i] = fork(); 133 if (child_pid[i] == -1) { 134 perror("An error occurs when calling fork()"); 135 return PTS_UNRESOLVED; 136 } else if (child_pid[i] == 0) { 137 child_process(i); 138 139 printf("This code should not be executed.\n"); 140 return PTS_UNRESOLVED; 141 } 142 } 143 144 param.sched_priority = sched_get_priority_max(SCHED_FIFO); 145 if (sched_setparam(0, ¶m) != 0) { 146 perror("An error occurs when calling sched_setparam()"); 147 return PTS_UNRESOLVED; 148 } 149 150 close(STDIN); 151 close(the_pipe[1]); 152 dup2(the_pipe[0], STDIN); 153 close(the_pipe[0]); 154 155 for (i = 0; i < NB_LOOP; i++) { 156 count++; 157 } 158 159 if (kill(child_pid[nb_child - 1], SIGTERM) != 0) { 160 perror("An error occurs when calling kill()"); 161 return PTS_UNRESOLVED; 162 } 163 164 param.sched_priority = sched_get_priority_min(SCHED_FIFO); 165 if (sched_setparam(0, ¶m) != 0) { 166 perror("An error occurs when calling sched_setparam()"); 167 return PTS_UNRESOLVED; 168 } 169 170 while (scanf("*%i*", &child_count) == 0) 171 sched_yield(); 172 173 for (i = 0; i < nb_child - 1; i++) { 174 if (kill(child_pid[i], SIGKILL) != 0) { 175 perror("An error occurs when calling kill()"); 176 return PTS_UNRESOLVED; 177 } 178 } 179 180 if (child_count) 181 ratio = (float)count / (float)child_count; 182 183 if (child_count == 0 || ratio >= ACCEPTABLE_RATIO) { 184 printf("Test PASSED\n"); 185 return PTS_PASS; 186 } else if (ratio <= (1 / ACCEPTABLE_RATIO)) { 187 printf 188 ("Higher numerical values for the priority represent the lower priorities.\n"); 189 return PTS_FAIL; 190 } else { 191 printf 192 ("The difference between the processes is not representative.\n"); 193 return PTS_UNRESOLVED; 194 } 195 196} 197