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