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 * 11 * Test that the process specified by the pid argument preempt a lowest 12 * priority running process, if the priority of the process specified by the 13 * pid argument is set higher than that of the lowest priority running process 14 * and if the specified process is ready to run. 15 * 16 * NO OTHER REALTIME PROCESS SHOULD RUN WHEN RUNNING THIS TEST. 17 * 18 * There is no portable way to get the number of CPUs but the test should work 19 * for most of UNIX system (including but not limited to: Linux, Solaris, AIX, 20 * HPUX, *BSD). 21 * This test used shared memory. 22 * Steps: 23 * 1. Create a share memory segment. 24 * 2. Change the policy to SCHED_FIFO and set minimum priority. 25 * 3. Create NB_CPU-1 children processes which set their own priority to the 26 * higher value and use all but one processor. 27 * 4. Create a child with the same priority. 28 * 4. Call sched_setparam with an mean priority and the pid value of the 29 * last children. 30 * 5. Check if the shared value has been changed by the child process. If 31 * not, the test fail. 32 */ 33 #include "affinity.h" 34 35 #include <errno.h> 36 #include <sched.h> 37 #include <stdio.h> 38 #include <signal.h> 39 #include <stdlib.h> 40 #include <sys/ipc.h> 41 #include <sys/shm.h> 42 #include <time.h> 43 #include <unistd.h> 44 #include "posixtest.h" 45 #include "ncpu.h" 46 47 static int nb_cpu; 48 static int *shmptr; 49 static int mean_prio; 50 51 static void child_process(void) 52 { 53 struct sched_param param; 54 time_t t1, t2; 55 56 param.sched_priority = sched_get_priority_max(SCHED_FIFO); 57 if (sched_setparam(getpid(), ¶m) != 0) { 58 perror("An error occurs when calling sched_setparam()"); 59 return; 60 } 61 62 t1 = time(NULL); 63 do { 64 t2 = time(NULL); 65 } while (difftime(t2, t1) <= 2); 66 } 67 68 static void test_process(void) 69 { 70 struct sched_param param; 71 time_t t1, t2; 72 73 t1 = time(NULL); 74 do { 75 sched_getparam(getpid(), ¶m); 76 (*shmptr) = param.sched_priority; 77 /* if we can see that our priority has changed 78 * that means we preempted parent, so we are done */ 79 if ((*shmptr) == mean_prio) 80 break; 81 82 t2 = time(NULL); 83 /* OS-es supporting set_affinity(), like Linux, will 84 * have only one parent and child process competing 85 * for same CPU. Since code path in parent does not 86 * block between fork() and sched_setparam(), child 87 * should run only after parent boosted its priority. 88 * Situation on other OS-es is a bit less predictable, 89 * as these will spawn ncpu-1 children, which run at max 90 * priority and could (though unlikely) preempt parent. 91 * Rather than risking deadlock, keep the sched_yield() 92 * call in loop as it is harmless. */ 93 sched_yield(); 94 } while (difftime(t2, t1) <= 2); 95 pause(); 96 } 97 98 static void kill_children(int *child_pid, int count) 99 { 100 int i; 101 102 for (i = 0; i < count; i++) 103 kill(child_pid[i], SIGTERM); 104 free(child_pid); 105 } 106 107 int main(void) 108 { 109 int *child_pid, oldcount, newcount, shm_id, i; 110 struct sched_param param; 111 key_t key; 112 int rc = set_affinity_single(); 113 if (rc) { 114 nb_cpu = get_ncpu(); 115 if (nb_cpu == -1) { 116 printf("Can not get the number of" 117 " CPUs of the machine.\n"); 118 return PTS_UNRESOLVED; 119 } 120 } else { 121 nb_cpu = 1; 122 } 123 124 mean_prio = (sched_get_priority_min(SCHED_FIFO) + 125 sched_get_priority_max(SCHED_FIFO)) / 2; 126 child_pid = malloc(nb_cpu * sizeof(int)); 127 128 key = ftok("conformance/interfaces/sched_setparam/9-1.c", 1234); 129 shm_id = shmget(key, sizeof(int), IPC_CREAT | 0600); 130 if (shm_id < 0) { 131 perror("An error occurs when calling shmget()"); 132 return PTS_UNRESOLVED; 133 } 134 135 shmptr = shmat(shm_id, 0, 0); 136 if (shmptr == (void *)-1) { 137 perror("An error occurs when calling shmat()"); 138 return PTS_UNRESOLVED; 139 } 140 *shmptr = 0; 141 142 param.sched_priority = sched_get_priority_min(SCHED_FIFO); 143 if (sched_setscheduler(getpid(), SCHED_FIFO, ¶m) == -1) { 144 if (errno == EPERM) { 145 printf("This process does not have the permission" 146 " to set its own scheduling parameter.\n" 147 "Try to launch this test as root\n"); 148 } else { 149 perror("An error occurs when calling" 150 " sched_setscheduler()"); 151 } 152 return PTS_UNRESOLVED; 153 } 154 155 for (i = 0; i < (nb_cpu - 1); i++) { 156 child_pid[i] = fork(); 157 if (child_pid[i] == -1) { 158 perror("An error occurs when calling fork()"); 159 kill_children(child_pid, i); 160 return PTS_UNRESOLVED; 161 } else if (child_pid[i] == 0) { 162 163 child_process(); 164 165 printf("This code should not be executed.\n"); 166 return PTS_UNRESOLVED; 167 } 168 } 169 170 child_pid[i] = fork(); 171 if (child_pid[i] == -1) { 172 perror("An error occurs when calling fork()"); 173 kill_children(child_pid, i); 174 return PTS_UNRESOLVED; 175 } else if (child_pid[i] == 0) { 176 177 test_process(); 178 179 printf("This code should not be executed.\n"); 180 return PTS_UNRESOLVED; 181 } 182 183 param.sched_priority = mean_prio; 184 oldcount = *shmptr; 185 if (sched_setparam(child_pid[i], ¶m) != 0) { 186 perror("An error occurs when calling sched_setparam()"); 187 kill_children(child_pid, nb_cpu); 188 return PTS_UNRESOLVED; 189 } 190 newcount = *shmptr; 191 192 if (newcount == oldcount) { 193 printf("The target process does not preempt" 194 " the calling process\n"); 195 kill_children(child_pid, nb_cpu); 196 return PTS_FAIL; 197 } 198 199 printf("Test PASSED\n"); 200 kill_children(child_pid, nb_cpu); 201 return PTS_PASS; 202 } 203