1/* 2 * Copyright (c) 2015, Cyril Hrubis <chrubis@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 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 35#define _POSIX_C_SOURCE 200112L 36 37/* Must be included first */ 38#include "affinity.h" 39 40#include <pthread.h> 41#include <stdio.h> 42#include <string.h> 43#include <unistd.h> 44#include <signal.h> 45#include <unistd.h> 46#include <stdlib.h> 47#include <sys/time.h> 48#include "posixtest.h" 49#include "ncpu.h" 50 51static volatile sig_atomic_t flag; 52static int n_threads; 53 54static void alarm_handler() 55{ 56 flag = 0; 57} 58 59void *do_work(void *arg) 60{ 61 (void) arg; 62 63 while (flag) 64 sched_yield(); 65 66 return NULL; 67} 68 69static void init_attr(pthread_attr_t *attr, int sched_policy, int prio) 70{ 71 struct sched_param sched_param = {.sched_priority = prio}; 72 int ret; 73 74 ret = pthread_attr_init(attr); 75 if (ret) { 76 fprintf(stderr, "pthread_attr_init(): %s\n", strerror(ret)); 77 exit(PTS_UNRESOLVED); 78 } 79 80 ret = pthread_attr_setschedpolicy(attr, sched_policy); 81 if (ret) { 82 fprintf(stderr, "pthread_setschedpolicy(): %s\n", strerror(ret)); 83 exit(PTS_UNRESOLVED); 84 } 85 86 ret = pthread_attr_setinheritsched(attr, PTHREAD_EXPLICIT_SCHED); 87 if (ret) { 88 fprintf(stderr, "pthread_attr_setinheritsched(): %s\n", strerror(ret)); 89 exit(PTS_UNRESOLVED); 90 } 91 92 ret = pthread_attr_setschedparam(attr, &sched_param); 93 if (ret) { 94 fprintf(stderr, "pthread_attr_setschedparam(): %s\n", strerror(ret)); 95 exit(PTS_UNRESOLVED); 96 } 97} 98 99static void run_hp_threads(int sched_policy, int sched_prio) 100{ 101 struct itimerval it; 102 pthread_t threads[n_threads]; 103 pthread_attr_t attr; 104 int i, ret; 105 106 flag = 1; 107 108 it.it_interval.tv_sec = 0; 109 it.it_interval.tv_usec = 0; 110 it.it_value.tv_sec = n_threads / 20; 111 it.it_value.tv_usec = (n_threads % 20) * 50000; 112 113 init_attr(&attr, sched_policy, sched_prio); 114 115 if (signal(SIGPROF, alarm_handler) == SIG_ERR) { 116 perror("signal()"); 117 exit(PTS_UNRESOLVED); 118 } 119 120 if (setitimer(ITIMER_PROF, &it, NULL)) { 121 perror("setitimer(ITIMER_VIRTUAL, ...)"); 122 exit(PTS_UNRESOLVED); 123 } 124 125 for (i = 0; i < n_threads; i++) { 126 ret = pthread_create(&threads[i], &attr, do_work, NULL); 127 if (ret) { 128 fprintf(stderr, "pthread_create(): %s\n", 129 strerror(ret)); 130 exit(PTS_UNRESOLVED); 131 } 132 } 133 134 if (flag) { 135 printf("FAILED: low priority thread scheduled\n"); 136 exit(PTS_FAIL); 137 } 138 139 pthread_attr_destroy(&attr); 140 141 for (i = 0; i < n_threads; i++) 142 pthread_join(threads[i], NULL); 143 144} 145 146struct params { 147 int sched_policy; 148 int sched_priority; 149}; 150 151static void *do_test(void *arg) 152{ 153 int ret, sched_policy; 154 struct sched_param param; 155 struct params *p = arg; 156 157 /* First check that the scheduler parameters are set correctly */ 158 ret = pthread_getschedparam(pthread_self(), &sched_policy, ¶m); 159 if (ret) { 160 fprintf(stderr, "pthread_getschedparam(): %s\n", strerror(ret)); 161 exit(PTS_UNRESOLVED); 162 } 163 164 if (p->sched_policy != sched_policy) { 165 printf("FAILED: have scheduler policy %i expected %i\n", 166 sched_policy, p->sched_policy); 167 exit(PTS_FAIL); 168 } 169 170 if (p->sched_priority != param.sched_priority) { 171 printf("FAILED: have scheduler priority %i expected %i\n", 172 p->sched_priority, param.sched_priority); 173 exit(PTS_FAIL); 174 } 175 176 /* Now check that priorities actually work */ 177 run_hp_threads(p->sched_policy, p->sched_priority + 1); 178 179 return NULL; 180} 181 182struct tcase { 183 int sched_policy; 184 int prio; 185}; 186 187enum tprio { 188 MIN, 189 HALF, 190 MAX_1, 191}; 192 193struct tcase tcases[] = { 194 {SCHED_FIFO, MIN}, 195 {SCHED_FIFO, HALF}, 196 {SCHED_FIFO, MAX_1}, 197 {SCHED_RR, MIN}, 198 {SCHED_RR, HALF}, 199 {SCHED_RR, MAX_1}, 200}; 201 202static int get_prio(struct tcase *self) 203{ 204 switch (self->prio) { 205 case MIN: 206 return sched_get_priority_min(self->sched_policy); 207 break; 208 case HALF: 209 return (sched_get_priority_min(self->sched_policy) + 210 sched_get_priority_max(self->sched_policy)) / 2; 211 break; 212 case MAX_1: 213 return sched_get_priority_max(self->sched_policy) - 1; 214 break; 215 } 216 217 printf("Wrong self->prio %i\n", self->prio); 218 exit(PTS_UNRESOLVED); 219} 220 221static const char *sched_policy_name(int policy) 222{ 223 switch (policy) { 224 case SCHED_FIFO: 225 return "SCHED_FIFO"; 226 case SCHED_RR: 227 return "SCHED_RR"; 228 default: 229 return "UNKNOWN"; 230 } 231} 232 233int main(void) 234{ 235 pthread_attr_t attr; 236 pthread_t th; 237 struct params p; 238 int ret; 239 unsigned int i; 240 241 ret = set_affinity_single(); 242 if (ret) { 243 n_threads = get_ncpu(); 244 if (n_threads == -1) { 245 printf("Cannot get number of CPUs\n"); 246 return PTS_UNRESOLVED; 247 } 248 printf("INFO: Affinity not supported, running %i threads.\n", 249 n_threads); 250 } else { 251 printf("INFO: Affinity works, will use only one thread.\n"); 252 n_threads = 1; 253 } 254 255 for (i = 0; i < ARRAY_SIZE(tcases); i++) { 256 p.sched_policy = tcases[i].sched_policy; 257 p.sched_priority = get_prio(&tcases[i]); 258 259 init_attr(&attr, p.sched_policy, p.sched_priority); 260 261 printf("INFO: Testing %s prio %i\n", 262 sched_policy_name(p.sched_policy), p.sched_priority); 263 264 ret = pthread_create(&th, &attr, do_test, &p); 265 if (ret) { 266 fprintf(stderr, "pthread_create(): %s\n", strerror(ret)); 267 return PTS_UNRESOLVED; 268 } 269 270 pthread_join(th, NULL); 271 272 pthread_attr_destroy(&attr); 273 } 274 275 printf("Test PASSED\n"); 276 return 0; 277} 278