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