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