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 * lookup_pi_state.c 21 * 22 * DESCRIPTION 23 * A test to reproduce a bug in lookup_pi_state() 24 * 25 * USAGE: 26 * Use run_auto.sh script in current directory to build and run test. 27 * 28 * AUTHOR 29 * Darren Hart <dvhltc (at) us.ibm.com> 30 * 31 * HISTORY 32 * 2006-May-18: Initial version by Darren Hart <dvhltc (at) us.ibm.com> 33 * 34 *****************************************************************************/ 35 36 #include <stdio.h> 37 #include <librttest.h> 38 39 #define NUM_SLAVES 20 40 #define SLAVE_PRIO 89 41 42 pthread_mutex_t MM; 43 pthread_mutex_t MS; 44 pthread_mutex_t MT; 45 pthread_cond_t CM; 46 pthread_cond_t CS; 47 pthread_cond_t CT; 48 49 atomic_t slave_order_a = { 0 }; 50 atomic_t slave_order_b = { 0 }; 51 atomic_t slave_order_c = { 0 }; 52 53 void usage(void) 54 { 55 rt_help(); 56 printf("lookup_pi_state specific options:\n"); 57 } 58 59 int parse_args(int c, char *v) 60 { 61 62 int handled = 1; 63 switch (c) { 64 case 'h': 65 usage(); 66 exit(0); 67 default: 68 handled = 0; 69 break; 70 } 71 return handled; 72 } 73 74 void *slave_thread(void *arg) 75 { 76 struct thread *t = (struct thread *)arg; 77 int id = (intptr_t) t->arg; 78 // 3 79 pthread_mutex_lock(&MS); 80 // 4,5 81 if (atomic_inc(&slave_order_a) == NUM_SLAVES) { 82 printf("Slave thread %d notifying master\n", id); 83 pthread_mutex_lock(&MM); // make sure the master thread is waiting 84 pthread_cond_signal(&CM); 85 pthread_mutex_unlock(&MM); 86 } 87 printf("Slave thread %d waiting on CS,MS\n", id); 88 pthread_cond_wait(&CS, &MS); // docs are contradictory on if this 89 // should be MS or MM 90 91 if (atomic_inc(&slave_order_b) <= 6) { 92 // 10,11 93 ; 94 // do nothing, just terminate 95 } else { 96 // 12 97 pthread_cond_wait(&CS, &MS); 98 // 17 99 } 100 pthread_mutex_unlock(&MS); 101 atomic_inc(&slave_order_c); 102 printf("Slave thread %d terminating\n", id); 103 return NULL; 104 } 105 106 void *master_thread(void *arg) 107 { 108 int i; 109 struct timespec ts_abs_timeout; 110 struct thread *t = (struct thread *)arg; 111 // 1 112 pthread_mutex_lock(&MM); 113 for (i = 0; i < NUM_SLAVES; i++) { 114 create_fifo_thread(slave_thread, (void *)(intptr_t) i, 115 SLAVE_PRIO); 116 } 117 // 2 118 printf("Master waiting till slaves wait()\n"); 119 pthread_cond_wait(&CM, &MM); 120 printf("Master awoken\n"); 121 // 6 122 pthread_mutex_lock(&MS); 123 // 7 124 printf("Master doing 3 signals\n"); 125 pthread_cond_signal(&CS); 126 pthread_cond_signal(&CS); 127 pthread_cond_signal(&CS); 128 // 8 129 printf("Master doing 3 broadcasts\n"); 130 pthread_cond_broadcast(&CS); 131 pthread_cond_broadcast(&CS); 132 pthread_cond_broadcast(&CS); 133 134 /* if we should timedwait on MS, then we don't need to unlock it here */ 135 pthread_mutex_unlock(&MS); 136 137 printf("Master waiting 10 seconds\n"); 138 clock_gettime(CLOCK_REALTIME, &ts_abs_timeout); 139 ts_abs_timeout.tv_sec += 10; 140 /* 141 * docs say CS and MS, but that doesn't seem correct 142 * 143 * XXX (garrcoop): then that's a documentation or implementation bug. 144 * Duh... FIX IT! 145 */ 146 pthread_cond_timedwait(&CM, &MM, &ts_abs_timeout); 147 // 13 148 pthread_mutex_unlock(&MM); 149 // 14 150 printf("Master doing notify of all remaining slaves\n"); 151 pthread_mutex_lock(&MS); 152 pthread_cond_broadcast(&CS); 153 // 15 154 /* 155 * docs say MM, but that doesn't make sense.. 156 * 157 * XXX (garrcoop): comments above apply here too 158 */ 159 pthread_mutex_unlock(&MS); 160 // 16 161 pthread_mutex_lock(&MT); 162 clock_gettime(CLOCK_REALTIME, &ts_abs_timeout); 163 ts_abs_timeout.tv_sec += 2; 164 pthread_cond_timedwait(&CT, &MT, &ts_abs_timeout); 165 // 18 166 while (!thread_quit(t)) 167 usleep(10); 168 169 printf("All slaves have terminated\n"); 170 171 return NULL; 172 } 173 174 int main(int argc, char *argv[]) 175 { 176 init_pi_mutex(&MM); 177 init_pi_mutex(&MS); 178 init_pi_mutex(&MT); 179 setup(); 180 181 pthread_cond_init(&CM, NULL); 182 pthread_cond_init(&CS, NULL); 183 pthread_cond_init(&CT, NULL); 184 185 rt_init("h", parse_args, argc, argv); 186 187 create_other_thread(master_thread, NULL); 188 189 /* wait for the slaves to quit */ 190 while (atomic_get(&slave_order_c) < NUM_SLAVES) 191 usleep(10); 192 193 join_threads(); 194 195 return 0; 196 } 197