1/*
2 * Copyright (c) 2004, 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 sample test aims to check the following assertion:
19 *
20 * pthread_create creates a thread with attributes as specified in the attr parameter.
21
22 * The steps are:
23 *
24 * -> See test 1-5.c for details
25 * -> This one will test the scheduling behavior is correct.
26
27 */
28
29
30 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
31 #define _POSIX_C_SOURCE 200112L
32
33 /* Some routines are part of the XSI Extensions */
34#ifndef WITHOUT_XOPEN
35 #define _XOPEN_SOURCE	600
36#endif
37/********************************************************************************************/
38/****************************** standard includes *****************************************/
39/********************************************************************************************/
40 #include <pthread.h>
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46
47 #include <sched.h>
48 #include <semaphore.h>
49 #include <errno.h>
50 #include <assert.h>
51 #include <sys/wait.h>
52/********************************************************************************************/
53/******************************   Test framework   *****************************************/
54/********************************************************************************************/
55 #include "testfrmw.h"
56 #include "testfrmw.c"
57 /* This header is responsible for defining the following macros:
58  * UNRESOLVED(ret, descr);
59  *    where descr is a description of the error and ret is an int (error code for example)
60  * FAILED(descr);
61  *    where descr is a short text saying why the test has failed.
62  * PASSED();
63  *    No parameter.
64  *
65  * Both three macros shall terminate the calling process.
66  * The testcase shall not terminate in any other maneer.
67  *
68  * The other file defines the functions
69  * void output_init()
70  * void output(char * string, ...)
71  *
72  * Those may be used to output information.
73  */
74
75/********************************************************************************************/
76/********************************** Configuration ******************************************/
77/********************************************************************************************/
78#ifndef VERBOSE
79#define VERBOSE 1
80#endif
81
82/* The value below shall be >= to the # of CPU on the test architecture */
83#define NCPU 	(4)
84
85/********************************************************************************************/
86/***********************************    Test cases  *****************************************/
87/********************************************************************************************/
88#define STD_MAIN /* This allows main() to be defined in the included file */
89
90#include "threads_scenarii.c"
91
92/* This file will define the following objects:
93 * scenarii: array of struct __scenario type.
94 * NSCENAR : macro giving the total # of scenarii
95 * scenar_init(): function to call before use the scenarii array.
96 * scenar_fini(): function to call after end of use of the scenarii array.
97 */
98
99/********************************************************************************************/
100/***********************************    Real Test   *****************************************/
101/********************************************************************************************/
102
103
104/* The 2 following functions are used for the scheduling tests */
105void * lp_func(void * arg)
106{
107	int * ctrl = (int *) arg;
108	*ctrl=2;
109	return NULL;
110}
111
112void * hp_func(void * arg)
113{
114	int *ctrl = (int *) arg;
115	int dummy=0, i;
116	do
117	{
118		/* some dummy task */
119		dummy += 3;
120		dummy %= 17;
121		dummy *= 47;
122		for (i=0; i<1000000000; i++);
123		#if VERBOSE > 6
124		output("%p\n", pthread_self());
125		#endif
126	}
127	while (*ctrl == 0);
128	return NULL;
129}
130
131
132void * threaded (void * arg)
133{
134	int ret = 0;
135
136	#if VERBOSE > 4
137	output("Thread %i starting...\n", sc);
138	#endif
139
140   /* Scheduling (priority) tests */
141	if ((sysconf(_SC_THREAD_PRIORITY_SCHEDULING) > 0)
142		&& (scenarii[sc].explicitsched != 0)
143		&& (scenarii[sc].schedpolicy != 0)
144		&& (scenarii[sc].schedparam == 1))
145	{
146		/* We will create NCPU threads running with a high priority with the same sched policy policy
147		 and one with a low-priority.
148		  The low-priority thread should not run until the other threads stop running,
149		 unless the machine has more than NCPU processors... */
150
151		pthread_t hpth[NCPU]; 	/* High priority threads */
152		pthread_t lpth; 	/* Low Priority thread */
153		int ctrl;		/* Check value */
154		pthread_attr_t ta;
155		struct sched_param sp;
156		int policy;
157		int i=0;
158		struct timespec now, timeout;
159
160		/* Start with checking we are executing with the required parameters */
161		ret = pthread_getschedparam(pthread_self(), &policy, &sp);
162		if (ret != 0)  {  UNRESOLVED(ret , "Failed to get current thread policy");  }
163
164		if (((scenarii[sc].schedpolicy == 1) && (policy != SCHED_FIFO))
165		   || ((scenarii[sc].schedpolicy == 2) && (policy != SCHED_RR)))
166		{
167			FAILED("The thread is not using the scheduling policy that was required");
168		}
169		if (((scenarii[sc].schedparam == 1) && (sp.sched_priority != sched_get_priority_max(policy)))
170		   || ((scenarii[sc].schedparam ==-1) && (sp.sched_priority != sched_get_priority_min(policy))))
171		{
172
173			FAILED("The thread is not using the scheduling parameter that was required");
174		}
175
176		ctrl = 0; /* Initial state */
177
178		/* Get the policy information */
179		ret = pthread_attr_getschedpolicy(&scenarii[sc].ta, &policy);
180		if (ret != 0)  {  UNRESOLVED(ret, "Failed to read sched policy");  }
181
182		/* We put a timeout cause the test might lock the machine when it runs */
183		alarm(60);
184
185		/* Create the high priority threads */
186		ret = pthread_attr_init(&ta);
187		if (ret != 0)  {  UNRESOLVED(ret, "Failed to initialize a thread attribute object");  }
188
189		ret = pthread_attr_setinheritsched(&ta, PTHREAD_EXPLICIT_SCHED);
190		if (ret != 0)  {  UNRESOLVED(ret, "Unable to set inheritsched attribute");  }
191
192		ret = pthread_attr_setschedpolicy(&ta, policy);
193		if (ret != 0)  {  UNRESOLVED(ret, "Unable to set the sched policy");  }
194
195		sp.sched_priority = sched_get_priority_max(policy) - 1;
196
197		ret = pthread_attr_setschedparam(&ta, &sp);
198		if (ret != 0)  {  UNRESOLVED(ret, "Failed to set the sched param");  }
199
200		#if VERBOSE > 1
201		output("Starting %i high- and 1 low-priority threads.\n", NCPU);
202		#endif
203		for (i=0; i<NCPU; i++)
204		{
205			ret = pthread_create(&hpth[i], &ta, hp_func, &ctrl);
206			if (ret != 0)  {  UNRESOLVED(ret, "Failed to create enough threads");  }
207		}
208		#if VERBOSE > 5
209		output("The %i high-priority threads are running\n", NCPU);
210		#endif
211
212		/* Create the low-priority thread */
213		sp.sched_priority = sched_get_priority_min(policy);
214
215		ret = pthread_attr_setschedparam(&ta, &sp);
216		if (ret != 0)  {  UNRESOLVED(ret, "Failed to set the sched param");  }
217
218		ret = pthread_create(&lpth, &ta, lp_func, &ctrl);
219		if (ret != 0)  {  UNRESOLVED(ret, "Failed to create enough threads");  }
220
221		/* Keep going */
222		ret = clock_gettime(CLOCK_REALTIME, &now);
223		if (ret != 0)  {  UNRESOLVED(errno, "Failed to read current time");  }
224
225		timeout.tv_sec = now.tv_sec;
226		timeout.tv_nsec = now.tv_nsec + 500000000;
227		while (timeout.tv_nsec >= 1000000000)
228		{
229			timeout.tv_sec++;
230			timeout.tv_nsec -= 1000000000;
231		}
232
233		do
234		{
235			if (ctrl != 0)
236			{
237				output("The low priority thread executed. This might be normal if you have more than %i CPU.\n", NCPU + 1);
238				FAILED("Low priority thread executed -- the sched parameters are ignored?");
239			}
240			ret = clock_gettime(CLOCK_REALTIME, &now);
241			if (ret != 0)  {  UNRESOLVED(errno, "Failed to read current time");  }
242			#if VERBOSE > 5
243			output("Time: %d.%09d (to: %d.%09d)\n", now.tv_sec, now.tv_nsec, timeout.tv_sec, timeout.tv_nsec);
244			#endif
245		}
246		while ((now.tv_sec <= timeout.tv_sec) && (now.tv_nsec <= timeout.tv_nsec));
247
248		/* Ok the low priority thread did not execute :) */
249
250		/* tell the other high priority to terminate */
251		ctrl = 1;
252
253		for (i=0; i<NCPU; i++)
254		{
255			ret = pthread_join(hpth[i], NULL);
256			if (ret != 0)  {  UNRESOLVED(ret, "Failed to join a thread");  }
257		}
258
259		/* Ok so now the low priority should execute when we stop this one (or earlier). */
260		ret = pthread_join(lpth, NULL);
261		if (ret != 0)  {  UNRESOLVED(ret, "Failed to join the low priority thread");  }
262
263		/* We just check that it executed */
264		if (ctrl != 2)  {  FAILED("Joined the low-priority thread but it did not execute.");  }
265
266		#if VERBOSE > 1
267		output("The scheduling parameter was set accordingly to the thread attribute.\n");
268		#endif
269
270		/* We're done. */
271		ret = pthread_attr_destroy(&ta);
272		if (ret != 0)  {  UNRESOLVED(ret, "Failed to destroy a thread attribute object");  }
273	}
274
275	/* Post the semaphore to unlock the main thread in case of a detached thread */
276	do { ret = sem_post(&scenarii[sc].sem); }
277	while ((ret == -1) && (errno == EINTR));
278	if (ret == -1)  {  UNRESOLVED(errno, "Failed to post the semaphore");  }
279
280	return arg;
281}
282
283