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@us.ibm.com>
30 *
31 * HISTORY
32 * 2006-May-18: Initial version by Darren Hart <dvhltc@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
usage(void)53 void usage(void)
54 {
55 rt_help();
56 printf("lookup_pi_state specific options:\n");
57 }
58
parse_args(int c,char * v)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
slave_thread(void * arg)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
master_thread(void * arg)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
main(int argc,char * argv[])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