Home | History | Annotate | Download | only in pi-tests
      1 /******************************************************************************
      2  *
      3  *   Copyright  International Business Machines  Corp., 2005, 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  *      testpi-1.c
     21  *
     22  * DESCRIPTION
     23  *     This testcase verifies if the low priority SCHED_OTHER thread can preempt
     24  *     the high priority SCHED_RR thread via priority inheritance.
     25  *
     26  * USAGE:
     27  *      Use run_auto.sh script in current directory to build and run test.
     28  *
     29  * AUTHOR
     30  *
     31  *
     32  * HISTORY
     33  *      2010-04-22 Code cleanup and thread synchronization changes by using
     34  *		 conditional variables,
     35  *		 by Gowrishankar(gowrishankar.m (at) in.ibm.com).
     36  *
     37  *****************************************************************************/
     38 
     39 #include <stdio.h>
     40 #include <stdlib.h>
     41 #include <string.h>
     42 #include <sched.h>
     43 #include <pthread.h>
     44 #include <sys/types.h>
     45 #include <sys/syscall.h>
     46 #include <unistd.h>
     47 #include <librttest.h>
     48 
     49 pthread_barrier_t barrier;
     50 
     51 void usage(void)
     52 {
     53 	rt_help();
     54 	printf("testpi-1 specific options:\n");
     55 }
     56 
     57 int parse_args(int c, char *v)
     58 {
     59 	int handled = 1;
     60 	switch (c) {
     61 	case 'h':
     62 		usage();
     63 		exit(0);
     64 	default:
     65 		handled = 0;
     66 		break;
     67 	}
     68 	return handled;
     69 }
     70 
     71 int gettid(void)
     72 {
     73 	return syscall(__NR_gettid);
     74 }
     75 
     76 typedef void *(*entrypoint_t) (void *);
     77 pthread_mutex_t glob_mutex;
     78 static pthread_mutex_t cond_mutex = PTHREAD_MUTEX_INITIALIZER;
     79 static pthread_cond_t cond_var = PTHREAD_COND_INITIALIZER;
     80 
     81 void *func_nonrt(void *arg)
     82 {
     83 	struct thread *pthr = (struct thread *)arg;
     84 	int i, tid = gettid();
     85 
     86 	printf("Thread %d started running with priority %d\n", tid,
     87 	       pthr->priority);
     88 	pthread_mutex_lock(&glob_mutex);
     89 	printf("Thread %d at start pthread pol %d pri %d - Got global lock\n",
     90 	       tid, pthr->policy, pthr->priority);
     91 	/* Wait for other RT threads to start up */
     92 	pthread_barrier_wait(&barrier);
     93 
     94 	/* Wait for the high priority noise thread to start and signal us */
     95 	pthread_mutex_lock(&cond_mutex);
     96 	pthread_cond_wait(&cond_var, &cond_mutex);
     97 	pthread_mutex_unlock(&cond_mutex);
     98 
     99 	for (i = 0; i < 10000; i++) {
    100 		if (i % 100 == 0) {
    101 			printf("Thread %d loop %d pthread pol %d pri %d\n",
    102 			       tid, i, pthr->policy, pthr->priority);
    103 			fflush(NULL);
    104 		}
    105 		busy_work_ms(1);
    106 	}
    107 	pthread_mutex_unlock(&glob_mutex);
    108 	return NULL;
    109 }
    110 
    111 void *func_rt(void *arg)
    112 {
    113 	struct thread *pthr = (struct thread *)arg;
    114 	int i, tid = gettid();
    115 
    116 	printf("Thread %d started running with prio %d\n", tid, pthr->priority);
    117 	pthread_barrier_wait(&barrier);
    118 	pthread_mutex_lock(&glob_mutex);
    119 	printf("Thread %d at start pthread pol %d pri %d - Got global lock\n",
    120 	       tid, pthr->policy, pthr->priority);
    121 
    122 	/* We just use the mutex as something to slow things down,
    123 	 * say who we are and then do nothing for a while.  The aim
    124 	 * of this is to show that high priority threads make more
    125 	 * progress than lower priority threads..
    126 	 */
    127 	for (i = 0; i < 1000; i++) {
    128 		if (i % 100 == 0) {
    129 			printf("Thread %d loop %d pthread pol %d pri %d\n",
    130 			       tid, i, pthr->policy, pthr->priority);
    131 			fflush(NULL);
    132 		}
    133 		busy_work_ms(1);
    134 	}
    135 	pthread_mutex_unlock(&glob_mutex);
    136 	return NULL;
    137 }
    138 
    139 void *func_noise(void *arg)
    140 {
    141 	struct thread *pthr = (struct thread *)arg;
    142 	int i, tid = gettid();
    143 
    144 	printf("Noise Thread %d started running with prio %d\n", tid,
    145 	       pthr->priority);
    146 	pthread_barrier_wait(&barrier);
    147 
    148 	/* Let others wait at conditional variable */
    149 	usleep(1000);
    150 
    151 	/* Noise thread begins the test */
    152 	pthread_mutex_lock(&cond_mutex);
    153 	pthread_cond_broadcast(&cond_var);
    154 	pthread_mutex_unlock(&cond_mutex);
    155 
    156 	for (i = 0; i < 10000; i++) {
    157 		if (i % 100 == 0) {
    158 			printf("Noise Thread %d loop %d pthread pol %d "
    159 			       "pri %d\n", tid, i, pthr->policy,
    160 			       pthr->priority);
    161 			fflush(NULL);
    162 		}
    163 		busy_work_ms(1);
    164 	}
    165 	return NULL;
    166 }
    167 
    168 /*
    169  * Test pthread creation at different thread priorities.
    170  */
    171 int main(int argc, char *argv[])
    172 {
    173 	int i, retc, nopi = 0;
    174 	cpu_set_t mask;
    175 	CPU_ZERO(&mask);
    176 	CPU_SET(0, &mask);
    177 	setup();
    178 
    179 	rt_init("h", parse_args, argc, argv);
    180 
    181 	retc = pthread_barrier_init(&barrier, NULL, 5);
    182 	if (retc) {
    183 		printf("pthread_barrier_init failed: %s\n", strerror(retc));
    184 		exit(retc);
    185 	}
    186 
    187 	retc = sched_setaffinity(0, sizeof(mask), &mask);
    188 	if (retc < 0) {
    189 		printf("Main Thread: Can't set affinity: %d %s\n", retc,
    190 		       strerror(retc));
    191 		exit(-1);
    192 	}
    193 
    194 	for (i = 0; i < argc; i++) {
    195 		if (strcmp(argv[i], "nopi") == 0)
    196 			nopi = 1;
    197 	}
    198 
    199 	printf("Start %s\n", argv[0]);
    200 
    201 	if (!nopi)
    202 		init_pi_mutex(&glob_mutex);
    203 
    204 	create_other_thread(func_nonrt, NULL);
    205 	create_rr_thread(func_rt, NULL, 20);
    206 	create_rr_thread(func_rt, NULL, 30);
    207 	create_rr_thread(func_rt, NULL, 40);
    208 	create_rr_thread(func_noise, NULL, 40);
    209 
    210 	printf("Joining threads\n");
    211 	join_threads();
    212 	printf("Done\n");
    213 	printf("Criteria:Low Priority Thread should Preempt Higher Priority "
    214 	       "Noise Thread\n");
    215 
    216 	pthread_mutex_destroy(&glob_mutex);
    217 	pthread_mutex_destroy(&cond_mutex);
    218 	pthread_cond_destroy(&cond_var);
    219 
    220 	return 0;
    221 }
    222