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