1 /* 2 * Copyright (c) 2015, Cyril Hrubis <chrubis (at) suse.cz> 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of version 2 of the GNU General Public License as 6 * published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it would be useful, but 9 * WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 11 * 12 * You should have received a copy of the GNU General Public License along 13 * with this program; if not, write the Free Software Foundation, Inc., 14 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 15 * 16 * This sample test aims to check the following assertion: 17 * 18 * pthread_create creates a thread with attributes as specified in the attr parameter. 19 * 20 * This test tests scheduller attributes are set correctly and schedulling works. 21 * 22 * The steps are: 23 * 24 * - create thread with given scheduler policy and minimal priority for the 25 * scheduling policy 26 * 27 * - get the scheduler attributes of the running thread and check 28 * that they are set as requested 29 * 30 * - start a thread(s) with higher priority and check that the thread with 31 * lower priority does not finish until the high priority threads finished 32 */ 33 34 35 /* Must be included first */ 36 #include "affinity.h" 37 38 #include <pthread.h> 39 #include <stdio.h> 40 #include <string.h> 41 #include <unistd.h> 42 #include <signal.h> 43 #include <unistd.h> 44 #include <stdlib.h> 45 #include <sys/time.h> 46 #include "posixtest.h" 47 #include "ncpu.h" 48 49 static volatile sig_atomic_t flag; 50 static int n_threads; 51 52 static void alarm_handler() 53 { 54 flag = 0; 55 } 56 57 void *do_work(void *arg) 58 { 59 (void) arg; 60 61 while (flag) 62 sched_yield(); 63 64 return NULL; 65 } 66 67 static void init_attr(pthread_attr_t *attr, int sched_policy, int prio) 68 { 69 struct sched_param sched_param = {.sched_priority = prio}; 70 int ret; 71 72 ret = pthread_attr_init(attr); 73 if (ret) { 74 fprintf(stderr, "pthread_attr_init(): %s\n", strerror(ret)); 75 exit(PTS_UNRESOLVED); 76 } 77 78 ret = pthread_attr_setschedpolicy(attr, sched_policy); 79 if (ret) { 80 fprintf(stderr, "pthread_setschedpolicy(): %s\n", strerror(ret)); 81 exit(PTS_UNRESOLVED); 82 } 83 84 ret = pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED); 85 if (ret) { 86 fprintf(stderr, "pthread_attr_setinheritsched(): %s\n", strerror(ret)); 87 exit(PTS_UNRESOLVED); 88 } 89 90 ret = pthread_attr_setschedparam(attr, &sched_param); 91 if (ret) { 92 fprintf(stderr, "pthread_attr_setschedparam(): %s\n", strerror(ret)); 93 exit(PTS_UNRESOLVED); 94 } 95 } 96 97 static void run_hp_threads(int sched_policy, int sched_prio) 98 { 99 struct itimerval it; 100 pthread_t threads[n_threads]; 101 pthread_attr_t attr; 102 int i, ret; 103 104 flag = 1; 105 106 it.it_interval.tv_sec = 0; 107 it.it_interval.tv_usec = 0; 108 it.it_value.tv_sec = n_threads / 20; 109 it.it_value.tv_usec = (n_threads % 20) * 50000; 110 111 init_attr(&attr, sched_policy, sched_prio); 112 113 if (signal(SIGPROF, alarm_handler) == SIG_ERR) { 114 perror("signal()"); 115 exit(PTS_UNRESOLVED); 116 } 117 118 if (setitimer(ITIMER_PROF, &it, NULL)) { 119 perror("setitimer(ITIMER_VIRTUAL, ...)"); 120 exit(PTS_UNRESOLVED); 121 } 122 123 for (i = 0; i < n_threads; i++) { 124 ret = pthread_create(&threads[i], &attr, do_work, NULL); 125 if (ret) { 126 fprintf(stderr, "pthread_create(): %s\n", 127 strerror(ret)); 128 exit(PTS_UNRESOLVED); 129 } 130 } 131 132 if (flag) { 133 printf("FAILED: low priority thread scheduled\n"); 134 exit(PTS_FAIL); 135 } 136 137 pthread_attr_destroy(&attr); 138 139 for (i = 0; i < n_threads; i++) 140 pthread_join(threads[i], NULL); 141 142 } 143 144 struct params { 145 int sched_policy; 146 int sched_priority; 147 }; 148 149 static void *do_test(void *arg) 150 { 151 int ret, sched_policy; 152 struct sched_param param; 153 struct params *p = arg; 154 155 /* First check that the scheduler parameters are set correctly */ 156 ret = pthread_getschedparam(pthread_self(), &sched_policy, ¶m); 157 if (ret) { 158 fprintf(stderr, "pthread_getschedparam(): %s\n", strerror(ret)); 159 exit(PTS_UNRESOLVED); 160 } 161 162 if (p->sched_policy != sched_policy) { 163 printf("FAILED: have scheduler policy %i expected %i\n", 164 sched_policy, p->sched_policy); 165 exit(PTS_FAIL); 166 } 167 168 if (p->sched_priority != param.sched_priority) { 169 printf("FAILED: have scheduler priority %i expected %i\n", 170 p->sched_priority, param.sched_priority); 171 exit(PTS_FAIL); 172 } 173 174 /* Now check that priorities actually work */ 175 run_hp_threads(p->sched_policy, p->sched_priority + 1); 176 177 return NULL; 178 } 179 180 struct tcase { 181 int sched_policy; 182 int prio; 183 }; 184 185 enum tprio { 186 MIN, 187 HALF, 188 MAX_1, 189 }; 190 191 struct tcase tcases[] = { 192 {SCHED_FIFO, MIN}, 193 {SCHED_FIFO, HALF}, 194 {SCHED_FIFO, MAX_1}, 195 {SCHED_RR, MIN}, 196 {SCHED_RR, HALF}, 197 {SCHED_RR, MAX_1}, 198 }; 199 200 static int get_prio(struct tcase *self) 201 { 202 switch (self->prio) { 203 case MIN: 204 return sched_get_priority_min(self->sched_policy); 205 break; 206 case HALF: 207 return (sched_get_priority_min(self->sched_policy) + 208 sched_get_priority_max(self->sched_policy)) / 2; 209 break; 210 case MAX_1: 211 return sched_get_priority_max(self->sched_policy) - 1; 212 break; 213 } 214 215 printf("Wrong self->prio %i\n", self->prio); 216 exit(PTS_UNRESOLVED); 217 } 218 219 static const char *sched_policy_name(int policy) 220 { 221 switch (policy) { 222 case SCHED_FIFO: 223 return "SCHED_FIFO"; 224 case SCHED_RR: 225 return "SCHED_RR"; 226 default: 227 return "UNKNOWN"; 228 } 229 } 230 231 int main(void) 232 { 233 pthread_attr_t attr; 234 pthread_t th; 235 struct params p; 236 int ret; 237 unsigned int i; 238 239 ret = set_affinity_single(); 240 if (ret) { 241 n_threads = get_ncpu(); 242 if (n_threads == -1) { 243 printf("Cannot get number of CPUs\n"); 244 return PTS_UNRESOLVED; 245 } 246 printf("INFO: Affinity not supported, running %i threads.\n", 247 n_threads); 248 } else { 249 printf("INFO: Affinity works, will use only one thread.\n"); 250 n_threads = 1; 251 } 252 253 for (i = 0; i < ARRAY_SIZE(tcases); i++) { 254 p.sched_policy = tcases[i].sched_policy; 255 p.sched_priority = get_prio(&tcases[i]); 256 257 init_attr(&attr, p.sched_policy, p.sched_priority); 258 259 printf("INFO: Testing %s prio %i\n", 260 sched_policy_name(p.sched_policy), p.sched_priority); 261 262 ret = pthread_create(&th, &attr, do_test, &p); 263 if (ret) { 264 fprintf(stderr, "pthread_create(): %s\n", strerror(ret)); 265 return PTS_UNRESOLVED; 266 } 267 268 pthread_join(th, NULL); 269 270 pthread_attr_destroy(&attr); 271 } 272 273 printf("Test PASSED\n"); 274 return 0; 275 } 276