testpi-1.c revision 1e6f5a673655551de5734ff31ef48cd63b604e6d
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 * NAME
20 *      testpi-1.c
21 *
22 * DESCRIPTION
23 *     This testcase verifies if the low priority SCHED_OTHER thread can preempt
24 *     the high priority SCHED_RR thread via priority inheritance.
25 *
26 * USAGE:
27 *      Use run_auto.sh script in current directory to build and run test.
28 *
29 * AUTHOR
30 *
31 *
32 * HISTORY
33 *      2010-04-22 Code cleanup and thread synchronization changes by using
34 *		 conditional variables,
35 *		 by Gowrishankar(gowrishankar.m@in.ibm.com).
36 *
37 *****************************************************************************/
38
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <sched.h>
43#include <pthread.h>
44#include <sys/types.h>
45#include <sys/syscall.h>
46#include <unistd.h>
47#include <librttest.h>
48
49pthread_barrier_t barrier;
50
51void usage(void)
52{
53	rt_help();
54	printf("testpi-1 specific options:\n");
55}
56
57int parse_args(int c, char *v)
58{
59	int handled = 1;
60	switch (c) {
61	case 'h':
62		usage();
63		exit(0);
64	default:
65		handled = 0;
66		break;
67	}
68	return handled;
69}
70
71int gettid(void)
72{
73	return syscall(__NR_gettid);
74}
75
76typedef void *(*entrypoint_t)(void *);
77pthread_mutex_t glob_mutex;
78static pthread_mutex_t cond_mutex = PTHREAD_MUTEX_INITIALIZER;
79static pthread_cond_t cond_var = PTHREAD_COND_INITIALIZER;
80
81void *func_nonrt(void *arg)
82{
83	struct thread *pthr = (struct thread *)arg;
84	int i, tid = gettid();
85
86	printf("Thread %d started running with priority %d\n", tid,\
87		pthr->priority);
88	pthread_mutex_lock(&glob_mutex);
89	printf("Thread %d at start pthread pol %d pri %d - Got global lock\n",\
90		tid, pthr->policy, pthr->priority);
91	/* Wait for other RT threads to start up */
92	pthread_barrier_wait(&barrier);
93
94	/* Wait for the high priority noise thread to start and signal us */
95	pthread_mutex_lock(&cond_mutex);
96	pthread_cond_wait(&cond_var, &cond_mutex);
97	pthread_mutex_unlock(&cond_mutex);
98
99	for (i = 0; i < 10000; i++) {
100		if (i%100 == 0) {
101			printf("Thread %d loop %d pthread pol %d pri %d\n",\
102				tid, i,  pthr->policy, pthr->priority);
103			fflush(NULL);
104		}
105		busy_work_ms(1);
106	}
107	pthread_mutex_unlock(&glob_mutex);
108	return NULL;
109}
110
111void *func_rt(void *arg)
112{
113	struct thread *pthr = (struct thread *)arg;
114	int i, tid = gettid();
115
116	printf("Thread %d started running with prio %d\n", tid, pthr->priority);
117	pthread_barrier_wait(&barrier);
118	pthread_mutex_lock(&glob_mutex);
119	printf("Thread %d at start pthread pol %d pri %d - Got global lock\n",
120		tid, pthr->policy, pthr->priority);
121
122	/* We just use the mutex as something to slow things down,
123	 * say who we are and then do nothing for a while.  The aim
124	 * of this is to show that high priority threads make more
125	 * progress than lower priority threads..
126	 */
127	for (i = 0; i < 1000; i++) {
128		if (i%100 == 0) {
129			printf("Thread %d loop %d pthread pol %d pri %d\n",\
130				tid, i, pthr->policy, pthr->priority);
131			fflush(NULL);
132		}
133		busy_work_ms(1);
134	}
135	pthread_mutex_unlock(&glob_mutex);
136	return NULL;
137}
138
139void *func_noise(void *arg)
140{
141	struct thread *pthr = (struct thread *)arg;
142	int i, tid = gettid();
143
144	printf("Noise Thread %d started running with prio %d\n", tid,
145		pthr->priority);
146	pthread_barrier_wait(&barrier);
147
148	/* Let others wait at conditional variable */
149	usleep(1000);
150
151	/* Noise thread begins the test */
152	pthread_mutex_lock(&cond_mutex);
153	pthread_cond_broadcast(&cond_var);
154	pthread_mutex_unlock(&cond_mutex);
155
156	for (i = 0; i < 10000; i++) {
157		if (i%100 == 0) {
158			printf("Noise Thread %d loop %d pthread pol %d "\
159				"pri %d\n", tid, i, pthr->policy,\
160				pthr->priority);
161			fflush(NULL);
162		}
163		busy_work_ms(1);
164	}
165	return NULL;
166}
167
168/*
169 * Test pthread creation at different thread priorities.
170 */
171int main(int argc, char *argv[])
172{
173	int i, retc, nopi = 0;
174	cpu_set_t mask;
175	CPU_ZERO(&mask);
176	CPU_SET(0, &mask);
177	setup();
178
179	rt_init("h", parse_args, argc, argv);
180
181	retc = pthread_barrier_init(&barrier, NULL, 5);
182	if (retc) {
183		printf("pthread_barrier_init failed: %s\n", strerror(retc));
184		exit(retc);
185	}
186
187	retc = sched_setaffinity(0, sizeof(mask), &mask);
188	if (retc < 0) {
189		printf("Main Thread: Can't set affinity: %d %s\n", retc,\
190			strerror(retc));
191		exit(-1);
192	}
193
194	for (i = 0; i < argc; i++) {
195		if (strcmp(argv[i], "nopi") == 0)
196			nopi = 1;
197	}
198
199	printf("Start %s\n", argv[0]);
200
201	if (!nopi)
202		init_pi_mutex(&glob_mutex);
203
204	create_other_thread(func_nonrt, NULL);
205	create_rr_thread(func_rt, NULL, 20);
206	create_rr_thread(func_rt, NULL, 30);
207	create_rr_thread(func_rt, NULL, 40);
208	create_rr_thread(func_noise, NULL, 40);
209
210	printf("Joining threads\n");
211	join_threads();
212	printf("Done\n");
213	printf("Criteria:Low Priority Thread should Preempt Higher Priority "\
214		"Noise Thread\n");
215
216	pthread_mutex_destroy(&glob_mutex);
217	pthread_mutex_destroy(&cond_mutex);
218	pthread_cond_destroy(&cond_var);
219	tst_exit();
220}