Home | History | Annotate | Download | only in pi-tests
      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