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