1 /* 2 * Copyright (c) 2005, Bull S.A.. All rights reserved. 3 * Created by: Sebastien Decugis 4 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of version 2 of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it would be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 * 13 * You should have received a copy of the GNU General Public License along 14 * with this program; if not, write the Free Software Foundation, Inc., 15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 17 * This stress test aims to test the following assertion: 18 19 * pthread_getschedparam() always returns the scheduling parameters of 20 * the queried thread. 21 22 * The steps are: 23 * -> Create several threads with different scheduling parameters. 24 * -> create more threads which call continuously the routine, and check 25 * -> that the correct parameters are always returned. 26 27 */ 28 29 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 30 #define _POSIX_C_SOURCE 200112L 31 32 /********************************************************************************************/ 33 /****************************** standard includes *****************************************/ 34 /********************************************************************************************/ 35 #include <pthread.h> 36 #include <stdarg.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <unistd.h> 41 42 #include <errno.h> 43 #include <signal.h> 44 #include <sched.h> 45 46 /********************************************************************************************/ 47 /****************************** Test framework *****************************************/ 48 /********************************************************************************************/ 49 #include "testfrmw.h" 50 #include "testfrmw.c" 51 /* This header is responsible for defining the following macros: 52 * UNRESOLVED(ret, descr); 53 * where descr is a description of the error and ret is an int (error code for example) 54 * FAILED(descr); 55 * where descr is a short text saying why the test has failed. 56 * PASSED(); 57 * No parameter. 58 * 59 * Both three macros shall terminate the calling process. 60 * The testcase shall not terminate in any other maneer. 61 * 62 * The other file defines the functions 63 * void output_init() 64 * void output(char * string, ...) 65 * 66 * Those may be used to output information. 67 */ 68 69 /********************************************************************************************/ 70 /********************************** Configuration ******************************************/ 71 /********************************************************************************************/ 72 #ifndef VERBOSE 73 #define VERBOSE 1 74 #endif 75 76 #define NTHREADS 30 77 78 /********************************************************************************************/ 79 /*********************************** Test cases *****************************************/ 80 /********************************************************************************************/ 81 82 char do_it = 1; 83 long long iterations = 0; 84 85 /* Handler for user request to terminate */ 86 void sighdl(int sig) 87 { 88 do { 89 do_it = 0; 90 } 91 while (do_it); 92 } 93 94 typedef struct _tdata { 95 int policy; 96 int prio; 97 pthread_t thread; 98 } testdata_t; 99 100 testdata_t td[4]; 101 102 /* Thread function */ 103 void *threaded(void *arg) 104 { 105 int ret = 0; 106 int i = 0; 107 int pol; 108 109 struct sched_param sp; 110 111 while (do_it) { 112 for (i = 0; i < 4; i++) { 113 ret = pthread_getschedparam(td[i].thread, &pol, &sp); 114 115 if (ret != 0) { 116 UNRESOLVED(ret, "Failed to get sched param"); 117 } 118 119 if (pol != td[i].policy) { 120 FAILED("Wrong scheduling policy read"); 121 } 122 123 if (sp.sched_priority != td[i].prio) { 124 FAILED("Wrong scheduling priority read"); 125 } 126 127 } 128 129 /* We don't really care about concurrent access for this data */ 130 iterations++; 131 } 132 133 return NULL; 134 } 135 136 /* alternative policy threads */ 137 void *rt_thread(void *arg) 138 { 139 int ret = 0; 140 141 /* This thread does almost nothing but wait... */ 142 ret = pthread_barrier_wait(arg); 143 144 if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { 145 UNRESOLVED(ret, "Failed to wait for barrier"); 146 } 147 148 return NULL; 149 } 150 151 /* Main function */ 152 int main(int argc, char *argv[]) 153 { 154 int ret = 0, i; 155 156 struct sigaction sa; 157 158 pthread_barrier_t bar; 159 160 pthread_attr_t ta[4]; 161 162 pthread_t th[NTHREADS]; 163 164 struct sched_param sp; 165 166 /* Initialize output routine */ 167 output_init(); 168 169 /* Initialize barrier */ 170 ret = pthread_barrier_init(&bar, NULL, 5); 171 172 if (ret != 0) { 173 UNRESOLVED(ret, "Failed to init barrier"); 174 } 175 176 /* Register the signal handler for SIGUSR1 */ 177 sigemptyset(&sa.sa_mask); 178 179 sa.sa_flags = 0; 180 181 sa.sa_handler = sighdl; 182 183 if ((ret = sigaction(SIGUSR1, &sa, NULL))) { 184 UNRESOLVED(ret, "Unable to register signal handler"); 185 } 186 187 if ((ret = sigaction(SIGALRM, &sa, NULL))) { 188 UNRESOLVED(ret, "Unable to register signal handler"); 189 } 190 #if VERBOSE > 1 191 output("[parent] Signal handler registered\n"); 192 193 #endif 194 195 td[0].policy = td[1].policy = SCHED_FIFO; 196 197 td[2].policy = td[3].policy = SCHED_RR; 198 199 td[0].prio = sched_get_priority_min(SCHED_FIFO); 200 201 if (td[0].prio == -1) { 202 UNRESOLVED(errno, "Failed to get scheduler range value"); 203 } 204 205 td[1].prio = sched_get_priority_max(SCHED_FIFO); 206 207 if (td[1].prio == -1) { 208 UNRESOLVED(errno, "Failed to get scheduler range value"); 209 } 210 211 td[2].prio = sched_get_priority_min(SCHED_RR); 212 213 if (td[2].prio == -1) { 214 UNRESOLVED(errno, "Failed to get scheduler range value"); 215 } 216 217 td[3].prio = sched_get_priority_max(SCHED_RR); 218 219 if (td[3].prio == -1) { 220 UNRESOLVED(errno, "Failed to get scheduler range value"); 221 } 222 223 /* Initialize the threads attributes and create the RT threads */ 224 for (i = 0; i < 4; i++) { 225 ret = pthread_attr_init(&ta[i]); 226 227 if (ret != 0) { 228 UNRESOLVED(ret, 229 "Failed to initialize thread attribute"); 230 } 231 232 ret = 233 pthread_attr_setinheritsched(&ta[i], 234 PTHREAD_EXPLICIT_SCHED); 235 236 if (ret != 0) { 237 UNRESOLVED(ret, 238 "Failed to set explicit scheduling attribute"); 239 } 240 241 sp.sched_priority = td[i].prio; 242 243 ret = pthread_attr_setschedparam(&ta[i], &sp); 244 245 if (ret != 0) { 246 UNRESOLVED(ret, 247 "failed to set thread attribute sched param"); 248 } 249 250 ret = pthread_attr_setschedpolicy(&ta[i], td[i].policy); 251 252 if (ret != 0) { 253 UNRESOLVED(ret, 254 "failed to set thread attribute sched prio"); 255 } 256 257 ret = pthread_create(&td[i].thread, &ta[i], rt_thread, &bar); 258 259 if (ret != 0) { 260 UNRESOLVED(ret, 261 "Failed to create a RT thread -- need more privilege?"); 262 } 263 264 } 265 266 /* Create the worker threads */ 267 for (i = 0; i < NTHREADS; i++) { 268 ret = pthread_create(&th[i], NULL, threaded, NULL); 269 270 if (ret != 0) { 271 UNRESOLVED(ret, "failed to create a worker thread"); 272 } 273 } 274 275 /* Wait for the worker threads to finish */ 276 for (i = 0; i < NTHREADS; i++) { 277 ret = pthread_join(th[i], NULL); 278 279 if (ret != 0) { 280 UNRESOLVED(ret, "failed to join a worker thread"); 281 } 282 } 283 284 /* Join the barrier to terminate the RT threads */ 285 ret = pthread_barrier_wait(&bar); 286 287 if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { 288 UNRESOLVED(ret, "Failed to wait for the barrier"); 289 } 290 291 /* Join the RT threads */ 292 for (i = 0; i < 4; i++) { 293 ret = pthread_join(td[i].thread, NULL); 294 295 if (ret != 0) { 296 UNRESOLVED(ret, "Failed to join a thread"); 297 } 298 } 299 300 /* Done! */ 301 output("pthread_getschedparam stress test PASSED -- %llu iterations\n", 302 iterations); 303 304 ret = pthread_barrier_destroy(&bar); 305 306 if (ret != 0) { 307 UNRESOLVED(ret, "Failed to destroy the barrier"); 308 } 309 310 PASSED; 311 } 312