1 /****************************************************************************** 2 * 3 * Copyright International Business Machines Corp., 2006, 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 * prio-wake.c 21 * 22 * DESCRIPTION 23 * Test priority ordered wakeup with pthread_cond_* 24 * * Steps: 25 * - Creates a number of worker threads with increasing FIFO priorities 26 * (by default, num worker threads = num cpus) 27 * - Create a master thread 28 * - The time the worker thread starts running is noted. Each of the 29 * worker threads then waits on the same _condvar_. The time it 30 * wakes up also noted. 31 * - Once all the threads finish execution, the start and wakeup times 32 * of all the threads is displayed. 33 * - The output must indicate that the thread wakeup happened in a 34 * priority order. 35 * 36 * USAGE: 37 * 38 * 39 * AUTHOR 40 * Darren Hart <dvhltc (at) us.ibm.com> 41 * 42 * HISTORY 43 * 2006-Apr-26: Initial version by Darren Hart 44 * 2006-May-25: Updated to use new librt.h features 45 * 46 *****************************************************************************/ 47 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <signal.h> 51 #include <time.h> 52 #include <pthread.h> 53 #include <sched.h> 54 #include <errno.h> 55 #include <sys/syscall.h> 56 #include <librttest.h> 57 #include <libstats.h> 58 59 volatile int running_threads = 0; 60 static int rt_threads = 0; 61 static int locked_broadcast = 1; 62 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 63 static pthread_mutex_t mutex; 64 static volatile nsec_t beginrun; 65 66 static int ret = 0; 67 68 void usage(void) 69 { 70 rt_help(); 71 printf("prio-wake specific options:\n"); 72 printf(" -n# #: number of worker threads\n"); 73 printf(" -l# 1:lock the mutex before broadcast, 0:don't\n"); 74 printf(" defaults to 1\n"); 75 } 76 77 int parse_args(int c, char *v) 78 { 79 80 int handled = 1; 81 switch (c) { 82 case 'h': 83 usage(); 84 exit(0); 85 case 'n': 86 rt_threads = atoi(v); 87 break; 88 case 'l': 89 locked_broadcast = atoi(v); 90 break; 91 default: 92 handled = 0; 93 break; 94 } 95 return handled; 96 } 97 98 struct array { 99 int *arr; 100 int counter; 101 }; 102 struct array wakeup = { NULL, 0 }; 103 104 void *master_thread(void *arg) 105 { 106 int rc; 107 nsec_t start; 108 109 /* make sure children are started */ 110 while (running_threads < rt_threads) 111 usleep(1000); 112 /* give the worker threads a chance to get to sleep in the kernel 113 * in the unlocked broadcast case. */ 114 usleep(1000); 115 116 start = rt_gettime() - beginrun; 117 118 printf("%08lld us: Master thread about to wake the workers\n", 119 start / NS_PER_US); 120 /* start the children threads */ 121 if (locked_broadcast) 122 rc = pthread_mutex_lock(&mutex); 123 rc = pthread_cond_broadcast(&cond); 124 if (locked_broadcast) 125 rc = pthread_mutex_unlock(&mutex); 126 127 return NULL; 128 } 129 130 void *worker_thread(void *arg) 131 { 132 struct sched_param sched_param; 133 int policy; 134 int rc; 135 int mypri; 136 int j; 137 nsec_t start, wake; 138 j = (intptr_t) arg; 139 140 if (pthread_getschedparam(pthread_self(), &policy, &sched_param) != 0) { 141 printf 142 ("ERR: Couldn't get pthread info. Priority value wrong\n"); 143 mypri = -1; 144 } else { 145 mypri = sched_param.sched_priority; 146 } 147 148 start = rt_gettime() - beginrun; 149 debug(0, "%08lld us: RealtimeThread-%03d pri %03d started\n", 150 start / NS_PER_US, j, mypri); 151 152 rc = pthread_mutex_lock(&mutex); 153 running_threads++; 154 rc = pthread_cond_wait(&cond, &mutex); 155 156 wake = rt_gettime() - beginrun; 157 running_threads--; 158 wakeup.arr[wakeup.counter++] = mypri; 159 debug(0, "%08lld us: RealtimeThread-%03d pri %03d awake\n", 160 wake / NS_PER_US, j, mypri); 161 162 rc = pthread_mutex_unlock(&mutex); 163 164 return NULL; 165 } 166 167 int main(int argc, char *argv[]) 168 { 169 int threads_per_prio; 170 int numcpus; 171 int numprios; 172 int prio; 173 int i; 174 setup(); 175 176 rt_init("hn:l:", parse_args, argc, argv); 177 178 if (rt_threads == 0) { 179 numcpus = sysconf(_SC_NPROCESSORS_ONLN); 180 rt_threads = numcpus; 181 } 182 wakeup.arr = malloc(rt_threads * sizeof(int)); 183 wakeup.counter = 0; 184 printf("\n-----------------------\n"); 185 printf("Priority Ordered Wakeup\n"); 186 printf("-----------------------\n"); 187 printf("Worker Threads: %d\n", rt_threads); 188 printf("Calling pthread_cond_broadcast() with mutex: %s\n\n", 189 locked_broadcast ? "LOCKED" : "UNLOCKED"); 190 191 beginrun = rt_gettime(); 192 193 init_pi_mutex(&mutex); 194 195 /* calculate the number of threads per priority */ 196 /* we get num numprios -1 for the workers, leaving one for the master */ 197 numprios = sched_get_priority_max(SCHED_FIFO) - 198 sched_get_priority_min(SCHED_FIFO); 199 200 threads_per_prio = rt_threads / numprios; 201 if (rt_threads % numprios) 202 threads_per_prio++; 203 204 /* start the worker threads */ 205 prio = sched_get_priority_min(SCHED_FIFO); 206 for (i = rt_threads; i > 0; i--) { 207 if ((i != rt_threads && (i % threads_per_prio) == 0)) 208 prio++; 209 create_fifo_thread(worker_thread, (void *)(intptr_t) i, prio); 210 } 211 212 /* start the master thread */ 213 create_fifo_thread(master_thread, (void *)(intptr_t) i, ++prio); 214 215 /* wait for threads to complete */ 216 join_threads(); 217 218 pthread_mutex_destroy(&mutex); 219 220 printf("\nCriteria: Threads should be woken up in priority order\n"); 221 222 for (i = 0; i < (wakeup.counter - 1); i++) { 223 if (wakeup.arr[i] < wakeup.arr[i + 1]) { 224 printf("FAIL: Thread %d woken before %d\n", 225 wakeup.arr[i], wakeup.arr[i + 1]); 226 ret++; 227 } 228 } 229 printf("Result: %s\n", ret ? "FAIL" : "PASS"); 230 return ret; 231 } 232