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 (at) 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 52 void usage(void) 53 { 54 rt_help(); 55 printf("testpi-2 specific options:\n"); 56 } 57 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 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 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 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 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 */ 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