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 /* 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