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-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 
49 pthread_barrier_t barrier;
50 
usage(void)51 void usage(void)
52 {
53 	rt_help();
54 	printf("testpi-1 specific options:\n");
55 }
56 
parse_args(int c,char * v)57 int 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 
gettid(void)71 int gettid(void)
72 {
73 	return syscall(__NR_gettid);
74 }
75 
76 typedef void *(*entrypoint_t) (void *);
77 pthread_mutex_t glob_mutex;
78 static pthread_mutex_t cond_mutex = PTHREAD_MUTEX_INITIALIZER;
79 static pthread_cond_t cond_var = PTHREAD_COND_INITIALIZER;
80 
func_nonrt(void * arg)81 void *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 
func_rt(void * arg)111 void *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 
func_noise(void * arg)139 void *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  */
main(int argc,char * argv[])171 int 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 
220 	return 0;
221 }
222