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., 59
15* Temple Place - Suite 330, Boston MA 02111-1307, USA.
16
17
18* This stress test aims to test the following assertion:
19
20*  pthread_getschedparam() always returns the scheduling parameters of
21* the queried thread.
22
23* The steps are:
24* -> Create several threads with different scheduling parameters.
25* -> create more threads which call continuously the routine, and check
26* -> that the correct parameters are always returned.
27
28*/
29
30
31/* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
32#define _POSIX_C_SOURCE 200112L
33
34/********************************************************************************************/
35/****************************** standard includes *****************************************/
36/********************************************************************************************/
37#include <pthread.h>
38#include <stdarg.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43
44#include <errno.h>
45#include <signal.h>
46#include <sched.h>
47
48/********************************************************************************************/
49/******************************   Test framework   *****************************************/
50/********************************************************************************************/
51#include "testfrmw.h"
52 #include "testfrmw.c"
53/* This header is responsible for defining the following macros:
54 * UNRESOLVED(ret, descr);
55 *    where descr is a description of the error and ret is an int (error code for example)
56 * FAILED(descr);
57 *    where descr is a short text saying why the test has failed.
58 * PASSED();
59 *    No parameter.
60 *
61 * Both three macros shall terminate the calling process.
62 * The testcase shall not terminate in any other maneer.
63 *
64 * The other file defines the functions
65 * void output_init()
66 * void output(char * string, ...)
67 *
68 * Those may be used to output information.
69 */
70
71/********************************************************************************************/
72/********************************** Configuration ******************************************/
73/********************************************************************************************/
74#ifndef VERBOSE
75#define VERBOSE 1
76#endif
77
78#define NTHREADS 30
79
80/********************************************************************************************/
81/***********************************    Test cases  *****************************************/
82/********************************************************************************************/
83
84char do_it = 1;
85long long iterations = 0;
86
87/* Handler for user request to terminate */
88void sighdl( int sig )
89{
90	do
91	{
92		do_it = 0;
93	}
94	while ( do_it );
95}
96
97typedef struct _tdata
98{
99	int policy;
100	int prio;
101	pthread_t thread;
102}
103
104testdata_t;
105
106testdata_t td[ 4 ];
107
108/* Thread function */
109void * threaded( void * arg )
110{
111	int ret = 0;
112	int i = 0;
113	int pol;
114
115	struct sched_param sp;
116
117	while ( do_it )
118	{
119		for ( i = 0; i < 4; i++ )
120		{
121			ret = pthread_getschedparam( td[ i ].thread, &pol, &sp );
122
123			if ( ret != 0 )
124			{
125				UNRESOLVED( ret, "Failed to get sched param" );
126			}
127
128			if ( pol != td[ i ].policy )
129			{
130				FAILED( "Wrong scheduling policy read" );
131			}
132
133			if ( sp.sched_priority != td[ i ].prio )
134			{
135				FAILED( "Wrong scheduling priority read" );
136			}
137
138		}
139
140		/* We don't really care about concurrent access for this data */
141		iterations++;
142	}
143
144	return NULL;
145}
146
147/* alternative policy threads */
148void * rt_thread( void * arg )
149{
150	int ret = 0;
151
152	/* This thread does almost nothing but wait... */
153	ret = pthread_barrier_wait( arg );
154
155	if ( ( ret != 0 ) && ( ret != PTHREAD_BARRIER_SERIAL_THREAD ) )
156	{
157		UNRESOLVED( ret, "Failed to wait for barrier" );
158	}
159
160	return NULL;
161}
162
163
164/* Main function */
165int main ( int argc, char * argv[] )
166{
167	int ret = 0, i;
168
169	struct sigaction sa;
170
171	pthread_barrier_t bar;
172
173	pthread_attr_t ta[ 4 ];
174
175	pthread_t th[ NTHREADS ];
176
177	struct sched_param sp;
178
179	/* Initialize output routine */
180	output_init();
181
182
183	/* Initialize barrier */
184	ret = pthread_barrier_init( &bar, NULL, 5 );
185
186	if ( ret != 0 )
187	{
188		UNRESOLVED( ret, "Failed to init barrier" );
189	}
190
191
192	/* Register the signal handler for SIGUSR1 */
193	sigemptyset ( &sa.sa_mask );
194
195	sa.sa_flags = 0;
196
197	sa.sa_handler = sighdl;
198
199	if ( ( ret = sigaction ( SIGUSR1, &sa, NULL ) ) )
200	{
201		UNRESOLVED( ret, "Unable to register signal handler" );
202	}
203
204	if ( ( ret = sigaction ( SIGALRM, &sa, NULL ) ) )
205	{
206		UNRESOLVED( ret, "Unable to register signal handler" );
207	}
208
209#if VERBOSE > 1
210	output( "[parent] Signal handler registered\n" );
211
212#endif
213
214	td[ 0 ].policy = td[ 1 ].policy = SCHED_FIFO;
215
216	td[ 2 ].policy = td[ 3 ].policy = SCHED_RR;
217
218	td[ 0 ].prio = sched_get_priority_min( SCHED_FIFO );
219
220	if ( td[ 0 ].prio == -1 )
221	{
222		UNRESOLVED( errno, "Failed to get scheduler range value" );
223	}
224
225	td[ 1 ].prio = sched_get_priority_max( SCHED_FIFO );
226
227	if ( td[ 1 ].prio == -1 )
228	{
229		UNRESOLVED( errno, "Failed to get scheduler range value" );
230	}
231
232	td[ 2 ].prio = sched_get_priority_min( SCHED_RR );
233
234	if ( td[ 2 ].prio == -1 )
235	{
236		UNRESOLVED( errno, "Failed to get scheduler range value" );
237	}
238
239	td[ 3 ].prio = sched_get_priority_max( SCHED_RR );
240
241	if ( td[ 3 ].prio == -1 )
242	{
243		UNRESOLVED( errno, "Failed to get scheduler range value" );
244	}
245
246	/* Initialize the threads attributes and create the RT threads */
247	for ( i = 0; i < 4; i++ )
248	{
249		ret = pthread_attr_init( &ta[ i ] );
250
251		if ( ret != 0 )
252		{
253			UNRESOLVED( ret, "Failed to initialize thread attribute" );
254		}
255
256		ret = pthread_attr_setinheritsched( &ta[ i ], PTHREAD_EXPLICIT_SCHED );
257
258		if ( ret != 0 )
259		{
260			UNRESOLVED( ret, "Failed to set explicit scheduling attribute" );
261		}
262
263		sp.sched_priority = td[ i ].prio;
264
265		ret = pthread_attr_setschedparam( &ta[ i ], &sp );
266
267		if ( ret != 0 )
268		{
269			UNRESOLVED( ret, "failed to set thread attribute sched param" );
270		}
271
272		ret = pthread_attr_setschedpolicy( &ta[ i ], td[ i ].policy );
273
274		if ( ret != 0 )
275		{
276			UNRESOLVED( ret, "failed to set thread attribute sched prio" );
277		}
278
279		ret = pthread_create( &td[ i ].thread, &ta[ i ], rt_thread, &bar );
280
281		if ( ret != 0 )
282		{
283			UNRESOLVED( ret, "Failed to create a RT thread -- need more privilege?" );
284		}
285
286	}
287
288	/* Create the worker threads */
289	for ( i = 0; i < NTHREADS; i++ )
290	{
291		ret = pthread_create( &th[ i ], NULL, threaded, NULL );
292
293		if ( ret != 0 )
294		{
295			UNRESOLVED( ret, "failed to create a worker thread" );
296		}
297	}
298
299	/* Wait for the worker threads to finish */
300	for ( i = 0; i < NTHREADS; i++ )
301	{
302		ret = pthread_join( th[ i ], NULL );
303
304		if ( ret != 0 )
305		{
306			UNRESOLVED( ret, "failed to join a worker thread" );
307		}
308	}
309
310	/* Join the barrier to terminate the RT threads */
311	ret = pthread_barrier_wait( &bar );
312
313	if ( ( ret != 0 ) && ( ret != PTHREAD_BARRIER_SERIAL_THREAD ) )
314	{
315		UNRESOLVED( ret, "Failed to wait for the barrier" );
316	}
317
318	/* Join the RT threads */
319	for ( i = 0; i < 4; i++ )
320	{
321		ret = pthread_join( td[ i ].thread, NULL );
322
323		if ( ret != 0 )
324		{
325			UNRESOLVED( ret, "Failed to join a thread" );
326		}
327	}
328
329	/* Done! */
330	output( "pthread_getschedparam stress test PASSED -- %llu iterations\n", iterations );
331
332	ret = pthread_barrier_destroy( &bar );
333
334	if ( ret != 0 )
335	{
336		UNRESOLVED( ret, "Failed to destroy the barrier" );
337	}
338
339	PASSED;
340}
341
342
343