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