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-2.c
21 *
22 * DESCRIPTION
23 * This testcase verifies if the low priority SCHED_RR thread can preempt
24 * the high priority SCHED_RR thread multiple times via priority
25 * inheritance.
26 *
27 * USAGE:
28 * Use run_auto.sh script in current directory to build and run test.
29 *
30 * AUTHOR
31 *
32 *
33 * HISTORY
34 * 2010-04-22 Code cleanup and thread synchronization changes by using
35 * conditional variables,
36 * by Gowrishankar(gowrishankar.m@in.ibm.com).
37 *
38 *****************************************************************************/
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <sched.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-2 specific options:\n");
56 }
57
parse_args(int c,char * v)58 int parse_args(int c, char *v)
59 {
60
61 int handled = 1;
62 switch (c) {
63 case 'h':
64 usage();
65 exit(0);
66 default:
67 handled = 0;
68 break;
69 }
70 return handled;
71 }
72
gettid(void)73 int gettid(void)
74 {
75 return syscall(__NR_gettid);
76 }
77
78 typedef void *(*entrypoint_t) (void *);
79 pthread_mutex_t glob_mutex;
80 static pthread_mutex_t cond_mutex = PTHREAD_MUTEX_INITIALIZER;
81 static pthread_cond_t cond_var = PTHREAD_COND_INITIALIZER;
82
func_lowrt(void * arg)83 void *func_lowrt(void *arg)
84 {
85 struct thread *pthr = (struct thread *)arg;
86 int i, tid = gettid();
87
88 printf("Thread %d started running with priority %d\n", tid,
89 pthr->priority);
90 pthread_mutex_lock(&glob_mutex);
91 printf("Thread %d at start pthread pol %d pri %d - Got global lock\n",
92 tid, pthr->policy, pthr->priority);
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 %d started running with prio %d\n", tid,
147 pthr->priority);
148 pthread_barrier_wait(&barrier);
149
150 /* Let others wait at conditional variable */
151 usleep(1000);
152
153 /* Noise thread begins the test */
154 pthread_mutex_lock(&cond_mutex);
155 pthread_cond_broadcast(&cond_var);
156 pthread_mutex_unlock(&cond_mutex);
157
158 for (i = 0; i < 10000; i++) {
159 if (i % 100 == 0) {
160 printf("Noise Thread %d loop %d pthread pol %d "
161 "pri %d\n", tid, i, pthr->policy,
162 pthr->priority);
163 fflush(NULL);
164 }
165 busy_work_ms(1);
166 }
167 return NULL;
168 }
169
170 /*
171 * Test pthread creation at different thread priorities.
172 */
main(int argc,char * argv[])173 int main(int argc, char *argv[])
174 {
175 int i, retc, nopi = 0;
176 cpu_set_t mask;
177 CPU_ZERO(&mask);
178 CPU_SET(0, &mask);
179 setup();
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
195 for (i = 0; i < argc; i++) {
196 if (strcmp(argv[i], "nopi") == 0)
197 nopi = 1;
198 }
199
200 printf("Start %s\n", argv[0]);
201
202 if (!nopi)
203 init_pi_mutex(&glob_mutex);
204
205 create_rr_thread(func_lowrt, NULL, 10);
206 create_rr_thread(func_rt, NULL, 20);
207 create_fifo_thread(func_rt, NULL, 30);
208 create_fifo_thread(func_rt, NULL, 40);
209 create_rr_thread(func_noise, NULL, 40);
210
211 printf("Joining threads\n");
212 join_threads();
213 printf("Done\n");
214 printf("Criteria: Low Priority Thread and High Priority Thread "
215 "should prempt each other multiple times\n");
216
217 pthread_mutex_destroy(&glob_mutex);
218 pthread_mutex_destroy(&cond_mutex);
219 pthread_cond_destroy(&cond_var);
220
221 return 0;
222 }
223