• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
sighdl(int sig)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 */
threaded(void * arg)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 */
rt_thread(void * arg)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 */
main(int argc,char * argv[])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