• 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 /********************************************************************************************/
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 */
sighdl(int sig)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 */
threaded(void * arg)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 */
rt_thread(void * arg)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 */
main(int argc,char * argv[])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