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