• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  *	 Copyright © International Business Machines	Corp., 2005, 2008
4  *
5  *	 This program is free software;	you can redistribute it and/or modify
6  *	 it under the terms of the GNU General Public License as published by
7  *	 the Free Software Foundation; either version 2 of the License, or
8  *	 (at your option) any later version.
9  *
10  *	 This program is distributed in the hope that it will be useful,
11  *	 but WITHOUT ANY WARRANTY;	without even the implied warranty of
12  *	 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See
13  *	 the GNU General Public License for more details.
14  *
15  *	 You should have received a copy of the GNU General Public License
16  *	 along with this program;	if not, write to the Free Software
17  *	 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  *
19  * NAME
20  *	testpi-3.c
21  *
22  * DESCRIPTION
23  *
24  *
25  * USAGE:
26  *	Use run_auto.sh script in current directory to build and run test.
27  *
28  * AUTHOR
29  *
30  *
31  * HISTORY
32  *
33  *
34  *****************************************************************************/
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sched.h>
40 #include <pthread.h>
41 #include <sys/types.h>
42 #include <sys/syscall.h>
43 #include <unistd.h>
44 #include <librttest.h>
45 
usage(void)46 void usage(void)
47 {
48 	rt_help();
49 	printf("testpi-3 specific options:\n");
50 }
51 
parse_args(int c,char * v)52 int parse_args(int c, char *v)
53 {
54 
55 	int handled = 1;
56 	switch (c) {
57 	case 'h':
58 		usage();
59 		exit(0);
60 	default:
61 		handled = 0;
62 		break;
63 	}
64 	return handled;
65 }
66 
gettid(void)67 int gettid(void)
68 {
69 	return syscall(__NR_gettid);
70 }
71 
72 typedef void *(*entrypoint_t) (void *);
73 
74 #define THREAD_STOP		1
75 
76 pthread_mutex_t glob_mutex;
77 
78 /*typedef struct thread {
79 	int priority;
80 	int policy;
81 	entrypoint_t func;
82 	pthread_attr_t attr;
83 	pthread_t handle;
84 	pthread_mutex_t mutex;
85 	pthread_cond_t cond;
86 	int flags;
87 	int count;
88 } Thread;*/
89 
90 typedef struct thread Thread;
91 
92 Thread arg1, arg2, arg3, arg4, arg5;
93 
94 int strartThread(Thread * thr);
95 void stopThread(Thread * thr);
96 void joinThread(Thread * thr);
97 
func_nonrt(void * arg)98 void *func_nonrt(void *arg)
99 {
100 	Thread *pthr = (Thread *) arg;
101 	int rc, i, j, policy, tid = gettid();
102 	struct sched_param schedp;
103 	cpu_set_t mask;
104 	CPU_ZERO(&mask);
105 	CPU_SET(0, &mask);
106 
107 	rc = sched_setaffinity(0, sizeof(mask), &mask);
108 	if (rc < 0) {
109 		printf("Thread %d: Can't set affinity: %d %s\n", tid, rc,
110 		       strerror(rc));
111 		exit(-1);
112 	}
113 	rc = sched_getaffinity(0, sizeof(mask), &mask);
114 
115 	printf("Thread started %d on CPU %ld\n", pthr->priority,
116 	       (long)mask.__bits[0]);
117 	pthread_getschedparam(pthr->pthread, &policy, &schedp);
118 	printf("Thread running %d\n", pthr->priority);
119 
120 	while (1) {
121 		pthread_mutex_lock(&glob_mutex);
122 		printf
123 		    ("Thread %d at start pthread pol %d pri %d - Got global lock\n",
124 		     pthr->priority, policy, schedp.sched_priority);
125 		sleep(2);
126 		for (i = 0; i < 10000; i++) {
127 			if ((i % 100) == 0) {
128 				sched_getparam(tid, &schedp);
129 				policy = sched_getscheduler(tid);
130 				printf("Thread %d(%d) loop %d pthread pol %d "
131 				       "pri %d\n", tid, pthr->priority, i,
132 				       policy, schedp.sched_priority);
133 				fflush(NULL);
134 			}
135 			pthr->id++;
136 			for (j = 0; j < 5000; j++) {
137 				pthread_mutex_lock(&(pthr->mutex));
138 				pthread_mutex_unlock(&(pthr->mutex));
139 			}
140 		}
141 		pthread_mutex_unlock(&glob_mutex);
142 		sched_yield();
143 	}
144 	return NULL;
145 }
146 
func_rt(void * arg)147 void *func_rt(void *arg)
148 {
149 	Thread *pthr = (Thread *) arg;
150 	int rc, i, j, policy, tid = gettid();
151 	struct sched_param schedp;
152 	cpu_set_t mask;
153 	CPU_ZERO(&mask);
154 	CPU_SET(0, &mask);
155 
156 	rc = sched_setaffinity(0, sizeof(mask), &mask);
157 	if (rc < 0) {
158 		printf("Thread %d: Can't set affinity: %d %s\n", tid, rc,
159 		       strerror(rc));
160 		exit(-1);
161 	}
162 	rc = sched_getaffinity(0, sizeof(mask), &mask);
163 
164 	printf("Thread started %d on CPU %ld\n", pthr->priority,
165 	       (long)mask.__bits[0]);
166 	pthread_getschedparam(pthr->pthread, &policy, &schedp);
167 
168 	while (1) {
169 		sleep(2);
170 		printf("Thread running %d\n", pthr->priority);
171 		pthread_mutex_lock(&glob_mutex);
172 		printf
173 		    ("Thread %d at start pthread pol %d pri %d - Got global lock\n",
174 		     pthr->priority, policy, schedp.sched_priority);
175 
176 		/* we just use the mutex as something to slow things down */
177 		/* say who we are and then do nothing for a while.      The aim
178 		 * of this is to show that high priority threads make more
179 		 * progress than lower priority threads..
180 		 */
181 		for (i = 0; i < 1000; i++) {
182 			if (i % 100 == 0) {
183 				sched_getparam(tid, &schedp);
184 				policy = sched_getscheduler(tid);
185 				printf
186 				    ("Thread %d(%d) loop %d pthread pol %d pri %d\n",
187 				     tid, pthr->priority, i, policy,
188 				     schedp.sched_priority);
189 				fflush(NULL);
190 			}
191 			pthr->id++;
192 			for (j = 0; j < 5000; j++) {
193 				pthread_mutex_lock(&(pthr->mutex));
194 				pthread_mutex_unlock(&(pthr->mutex));
195 			}
196 		}
197 		pthread_mutex_unlock(&glob_mutex);
198 		sleep(2);
199 	}
200 	return NULL;
201 }
202 
func_noise(void * arg)203 void *func_noise(void *arg)
204 {
205 	Thread *pthr = (Thread *) arg;
206 	int rc, i, j, policy, tid = gettid();
207 	struct sched_param schedp;
208 	cpu_set_t mask;
209 	CPU_ZERO(&mask);
210 	CPU_SET(0, &mask);
211 
212 	rc = sched_setaffinity(0, sizeof(mask), &mask);
213 	if (rc < 0) {
214 		printf("Thread %d: Can't set affinity: %d %s\n", tid, rc,
215 		       strerror(rc));
216 		exit(-1);
217 	}
218 	rc = sched_getaffinity(0, sizeof(mask), &mask);
219 
220 	printf("Noise Thread started %d on CPU %ld\n", pthr->priority,
221 	       (long)mask.__bits[0]);
222 	pthread_getschedparam(pthr->pthread, &policy, &schedp);
223 
224 	while (1) {
225 		sleep(1);
226 		printf("Noise Thread running %d\n", pthr->priority);
227 
228 		for (i = 0; i < 10000; i++) {
229 			if ((i % 100) == 0) {
230 				sched_getparam(tid, &schedp);
231 				policy = sched_getscheduler(tid);
232 				printf
233 				    ("Noise Thread %d(%d) loop %d pthread pol %d pri %d\n",
234 				     tid, pthr->priority, i, policy,
235 				     schedp.sched_priority);
236 				fflush(NULL);
237 			}
238 			pthr->id++;
239 			for (j = 0; j < 5000; j++) {
240 				pthread_mutex_lock(&(pthr->mutex));
241 				pthread_mutex_unlock(&(pthr->mutex));
242 			}
243 		}
244 		sched_yield();
245 	}
246 	return NULL;
247 }
248 
startThread(Thread * thrd)249 int startThread(Thread * thrd)
250 {
251 	struct sched_param schedp;
252 	pthread_condattr_t condattr;
253 	int retc, policy, inherit;
254 
255 	printf("Start thread priority %d\n", thrd->priority);
256 	if (pthread_attr_init(&(thrd->attr)) != 0) {
257 		printf("Attr init failed");
258 		exit(2);
259 	}
260 	thrd->flags = 0;
261 	memset(&schedp, 0, sizeof(schedp));
262 	schedp.sched_priority = thrd->priority;
263 	policy = thrd->policy;
264 
265 	if (pthread_attr_setschedpolicy(&(thrd->attr), policy) != 0) {
266 		printf("Can't set policy %d\n", policy);
267 	}
268 	if (pthread_attr_getschedpolicy(&(thrd->attr), &policy) != 0) {
269 		printf("Can't get policy\n");
270 	} else {
271 		printf("Policy in attribs is %d\n", policy);
272 	}
273 	if (pthread_attr_setschedparam(&(thrd->attr), &schedp) != 0) {
274 		printf("Can't set params");
275 	}
276 	if (pthread_attr_getschedparam(&(thrd->attr), &schedp) != 0) {
277 		printf("Can't get params");
278 	} else {
279 		printf("Priority in attribs is %d\n", schedp.sched_priority);
280 	}
281 	if (pthread_attr_setinheritsched(&(thrd->attr), PTHREAD_EXPLICIT_SCHED)
282 	    != 0) {
283 		printf("Can't set inheritsched\n");
284 	}
285 	if (pthread_attr_getinheritsched(&(thrd->attr), &inherit) != 0) {
286 		printf("Can't get inheritsched\n");
287 	} else {
288 		printf("inherit sched in attribs is %d\n", inherit);
289 	}
290 	if ((retc = pthread_mutex_init(&(thrd->mutex), NULL)) != 0) {
291 		printf("Failed to init mutex: %d\n", retc);
292 	}
293 	if (pthread_condattr_init(&condattr) != 0) {
294 		printf("Failed to init condattr\n");
295 	}
296 	if (pthread_cond_init(&(thrd->cond), &condattr) != 0) {
297 		printf("Failed to init cond\n");
298 	}
299 	retc =
300 	    pthread_create(&(thrd->pthread), &(thrd->attr), thrd->func, thrd);
301 	printf("Create returns %d\n\n", retc);
302 	return retc;
303 }
304 
stopThread(Thread * thr)305 void stopThread(Thread * thr)
306 {
307 	thr->flags += THREAD_STOP;
308 	joinThread(thr);
309 }
310 
joinThread(Thread * thr)311 void joinThread(Thread * thr)
312 {
313 	void *ret = NULL;
314 	if (pthread_join(thr->pthread, &ret) != 0) {
315 		printf("Join failed\n");
316 	}
317 	printf("Join gave %p\n", ret);
318 }
319 
320 /*
321  * Test pthread creation at different thread priorities.
322  */
main(int argc,char * argv[])323 int main(int argc, char *argv[])
324 {
325 	int i, retc, nopi = 0;
326 	cpu_set_t mask;
327 	CPU_ZERO(&mask);
328 	CPU_SET(0, &mask);
329 	setup();
330 
331 	rt_init("h", parse_args, argc, argv);
332 
333 	retc = sched_setaffinity(0, sizeof(mask), &mask);
334 	if (retc < 0) {
335 		printf("Main Thread: Can't set affinity: %d %s\n", retc,
336 		       strerror(retc));
337 		exit(1);
338 	}
339 	retc = sched_getaffinity(0, sizeof(mask), &mask);
340 
341 	/*
342 	 * XXX: Have you ever heard of structures with c89/c99?
343 	 * Inline assignment is a beautiful thing.
344 	 */
345 	arg1.policy = SCHED_OTHER;
346 	arg1.priority = 0;
347 	arg1.func = func_nonrt;
348 	arg2.policy = SCHED_RR;
349 	arg2.priority = 20;
350 	arg2.func = func_rt;
351 	arg3.policy = SCHED_RR;
352 	arg3.priority = 30;
353 	arg3.func = func_rt;
354 	arg4.policy = SCHED_RR;
355 	arg4.priority = 40;
356 	arg4.func = func_rt;
357 	arg5.policy = SCHED_RR;
358 	arg5.priority = 40;
359 	arg5.func = func_noise;
360 
361 	for (i = 0; i < argc; i++) {
362 		if (strcmp(argv[i], "nopi") == 0)
363 			nopi = 1;
364 	}
365 
366 	printf("Start %s\n", argv[0]);
367 
368 #if HAS_PRIORITY_INHERIT
369 	if (!nopi) {
370 		pthread_mutexattr_t mutexattr;
371 		int protocol;
372 
373 		if (pthread_mutexattr_init(&mutexattr) != 0) {
374 			printf("Failed to init mutexattr\n");
375 		};
376 		if (pthread_mutexattr_setprotocol
377 		    (&mutexattr, PTHREAD_PRIO_INHERIT) != 0) {
378 			printf("Can't set protocol prio inherit\n");
379 		}
380 		if (pthread_mutexattr_getprotocol(&mutexattr, &protocol) != 0) {
381 			printf("Can't get mutexattr protocol\n");
382 		} else {
383 			printf("protocol in mutexattr is %d\n", protocol);
384 		}
385 		if ((retc = pthread_mutex_init(&glob_mutex, &mutexattr)) != 0) {
386 			printf("Failed to init mutex: %d\n", retc);
387 		}
388 	}
389 #endif
390 
391 	startThread(&arg1);
392 	startThread(&arg2);
393 	startThread(&arg3);
394 	startThread(&arg4);
395 	startThread(&arg5);
396 
397 	sleep(10);
398 
399 	printf("Stopping threads\n");
400 	stopThread(&arg1);
401 	stopThread(&arg2);
402 	stopThread(&arg3);
403 	stopThread(&arg4);
404 	stopThread(&arg5);
405 
406 	printf("Thread counts %d %d %d %d %d\n", arg1.id, arg2.id, arg3.id,
407 	       arg4.id, arg5.id);
408 	printf("Done\n");
409 
410 	return 0;
411 }
412