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