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