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