1 /*
2  * Copyright (c) 2004, QUALCOMM Inc. All rights reserved.
3  * Created by:  abisain REMOVE-THIS AT qualcomm DOT com
4  * This file is licensed under the GPL license.  For the full content
5  * of this license, see the COPYING file at the top level of this
6  * source tree.
7  *
8  * Test that pthread_mutex_unlock()
9  * shall wakeup a high priority thread even when a low priority thread
10  * is running
11  *
12  * Steps:
13  * 1. Create a mutex and lock
14  * 2. Create a high priority thread and make it wait on the mutex
15  * 3. Create a low priority thread and let it busy-loop
16  * 4. Unlock the mutex and make sure that the higher priority thread
17  *    got woken up
18  *
19  */
20 
21 #include <pthread.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <signal.h>
25 #include <unistd.h>
26 #include <sys/time.h>
27 #include "posixtest.h"
28 
29 #define TEST "5-5"
30 #define AREA "scheduler"
31 #define ERROR_PREFIX "unexpected error: " AREA " " TEST ": "
32 
33 #define HIGH_PRIORITY 10
34 #define MID_PRIORITY 7
35 #define LOW_PRIORITY 5
36 #define RUNTIME 5
37 
38 /* mutex  high priority thread will wait on*/
39 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
40 /* mutex required by the cond variable */
41 pthread_mutex_t cond_mutex = PTHREAD_MUTEX_INITIALIZER;
42 /* condition variable that threads block on*/
43 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
44 
45 volatile int woken_up = -1;
46 volatile int low_done = -1;
47 
48 /* Utility function to find difference between two time values */
timediff(struct timespec t2,struct timespec t1)49 float timediff(struct timespec t2, struct timespec t1)
50 {
51 	float diff = t2.tv_sec - t1.tv_sec;
52 	diff += (t2.tv_nsec - t1.tv_nsec)/1000000000.0;
53 	return diff;
54 }
55 
56 /* This signal handler will wakeup the main thread by sending a signal
57  * to a condition variable that the main thread is waiting on.
58  */
signal_handler(int sig)59 void signal_handler(int sig)
60 {
61 	int	 rc = 0;
62 
63 	rc = pthread_cond_signal(&cond);
64 	if(rc != 0) {
65 		printf(ERROR_PREFIX "pthread_cond_signal\n");
66 		exit(PTS_UNRESOLVED);
67 	}
68 }
69 
hi_priority_thread(void * tmp)70 void *hi_priority_thread(void *tmp)
71 {
72 	struct sched_param        param;
73 	int                       policy;
74 	int                       rc = 0;
75 
76 	param.sched_priority = HIGH_PRIORITY;
77 	rc = pthread_setschedparam(pthread_self(), SCHED_RR, &param);
78 	if(rc != 0) {
79 		printf(ERROR_PREFIX "pthread_setschedparam\n");
80 		exit(PTS_UNRESOLVED);
81 	}
82 	rc = pthread_getschedparam(pthread_self(), &policy, &param);
83 	if(rc != 0) {
84 		printf(ERROR_PREFIX "pthread_getschedparam\n");
85 		exit(PTS_UNRESOLVED);
86 	}
87 	if(policy != SCHED_RR) {
88 		printf(ERROR_PREFIX "The policy is not correct\n");
89 		exit(PTS_UNRESOLVED);
90 	}
91 	if(param.sched_priority != HIGH_PRIORITY) {
92 		printf(ERROR_PREFIX "The priority is not correct\n");
93 		exit(PTS_UNRESOLVED);
94 	}
95 
96 	/* acquire the mutex */
97 	rc = pthread_mutex_lock(&mutex);
98 	if(rc != 0) {
99 		printf(ERROR_PREFIX "pthread_mutex_lock\n");
100 		exit(PTS_UNRESOLVED);
101 	}
102 
103 	/* This variable is unprotected because the scheduling removes
104 	 * the contention
105 	 */
106 	if(low_done != 1)
107 		woken_up = 1;
108 
109 	rc = pthread_mutex_unlock(&mutex);
110 	if(rc != 0) {
111 		printf(ERROR_PREFIX "pthread_mutex_unlock\n");
112 		exit(PTS_UNRESOLVED);
113 	}
114 	pthread_exit((void *) 0);
115 }
116 
low_priority_thread(void * tmp)117 void *low_priority_thread(void *tmp)
118 {
119 	struct timespec           current_time, start_time;
120 	struct sched_param        param;
121 	int                       rc = 0;
122 	int                       policy;
123 
124 	param.sched_priority = LOW_PRIORITY;
125 	rc = pthread_setschedparam(pthread_self(), SCHED_RR, &param);
126 	if(rc != 0) {
127 		printf(ERROR_PREFIX "pthread_setschedparam\n");
128 		exit(PTS_UNRESOLVED);
129 	}
130 	rc = pthread_getschedparam(pthread_self(), &policy, &param);
131 	if(rc != 0) {
132 		printf(ERROR_PREFIX "pthread_getschedparam\n");
133 		exit(PTS_UNRESOLVED);
134 	}
135 	if(policy != SCHED_RR) {
136 		printf(ERROR_PREFIX "Policy not correct\n");
137 		exit(PTS_UNRESOLVED);
138 	}
139 	if(param.sched_priority != LOW_PRIORITY) {
140 		printf(ERROR_PREFIX "Priority not correct\n");
141 		exit(PTS_UNRESOLVED);
142 	}
143 
144 	/* Grab the start time and busy loop for 5 seconds */
145 	clock_gettime(CLOCK_REALTIME, &start_time);
146 	while(1) {
147 		clock_gettime(CLOCK_REALTIME, &current_time);
148 		if(timediff(current_time, start_time) > RUNTIME)
149 			break;
150 	}
151 	low_done = 1;
152 	pthread_exit((void *) 0);
153 }
154 
main()155 int main()
156 {
157 	pthread_t                high_id, low_id;
158 	pthread_attr_t           low_attr, high_attr;
159 	struct sched_param       param;
160 	int                      rc = 0;
161 	int                      policy;
162 
163 	param.sched_priority = MID_PRIORITY;
164 	rc =  pthread_setschedparam(pthread_self(), SCHED_RR, &param);
165 	if(rc != 0) {
166 		printf(ERROR_PREFIX "pthread_setschedparam\n");
167 		exit(PTS_UNRESOLVED);
168 	}
169 	rc = pthread_getschedparam(pthread_self(), &policy, &param);
170 	if(rc != 0) {
171 		printf(ERROR_PREFIX "pthread_getschedparam\n");
172 		exit(PTS_UNRESOLVED);
173 	}
174 	if(policy != SCHED_RR) {
175 		printf(ERROR_PREFIX "The policy is not correct\n");
176 		exit(PTS_UNRESOLVED);
177 	}
178 	if(param.sched_priority != MID_PRIORITY) {
179 		printf(ERROR_PREFIX "The priority is not correct\n");
180 		exit(PTS_UNRESOLVED);
181 	}
182 
183 	rc = pthread_mutex_lock(&mutex);
184 	if(rc != 0) {
185 		printf(ERROR_PREFIX "pthread_mutex_lock\n");
186 		exit(PTS_UNRESOLVED);
187 	}
188 
189 	/* create the higher priority */
190 	rc = pthread_attr_init(&high_attr);
191 	if(rc != 0) {
192 		printf(ERROR_PREFIX "pthread_attr_init\n");
193 		exit(PTS_UNRESOLVED);
194 	}
195 	rc = pthread_attr_setschedpolicy(&high_attr, SCHED_RR);
196 	if(rc != 0) {
197 		printf(ERROR_PREFIX "pthread_attr_setschedpolicy\n");
198 		exit(PTS_UNRESOLVED);
199 	}
200 	param.sched_priority = HIGH_PRIORITY;
201 	rc = pthread_attr_setschedparam(&high_attr, &param);
202 	if(rc != 0) {
203 		printf(ERROR_PREFIX "pthread_attr_setschedparam\n");
204 		exit(PTS_UNRESOLVED);
205 	}
206 	rc = pthread_create(&high_id, &high_attr, hi_priority_thread, NULL);
207 	if(rc != 0) {
208 		printf(ERROR_PREFIX "pthread_create\n");
209 		exit(PTS_UNRESOLVED);
210 	}
211 
212 	/* Create the low priority thread */
213 	rc = pthread_attr_init(&low_attr);
214 	if(rc != 0) {
215 		printf(ERROR_PREFIX "pthread_attr_init\n");
216 		exit(PTS_UNRESOLVED);
217 	}
218 	rc = pthread_attr_setschedpolicy(&low_attr, SCHED_RR);
219 	if(rc != 0) {
220 		printf(ERROR_PREFIX "pthread_attr_setschedpolicy\n");
221 		exit(PTS_UNRESOLVED);
222 	}
223 	param.sched_priority = LOW_PRIORITY;
224 	rc = pthread_attr_setschedparam(&low_attr, &param);
225 	if(rc != 0) {
226 		printf(ERROR_PREFIX "pthread_attr_setschedparam\n");
227 		exit(PTS_UNRESOLVED);
228 	}
229 	rc = pthread_create(&low_id, &low_attr, low_priority_thread, NULL);
230 	if(rc != 0) {
231 		printf(ERROR_PREFIX "pthread_create\n");
232 		exit(PTS_UNRESOLVED);
233 	}
234 
235 	/* setup a signal handler which will wakeup main later */
236 	if(signal(SIGALRM, signal_handler) == SIG_ERR) {
237 		perror(ERROR_PREFIX "signal");
238 		exit(PTS_UNRESOLVED);
239 	}
240 
241 	rc = pthread_mutex_lock(&cond_mutex);
242 	if(rc != 0) {
243 		printf(ERROR_PREFIX "pthread_mutex_lock\n");
244 		exit(PTS_UNRESOLVED);
245 	}
246 
247 	alarm(2);
248 	rc = pthread_cond_wait(&cond, &cond_mutex);
249 	if(rc != 0) {
250 		printf(ERROR_PREFIX "pthread_cond_wait\n");
251 		exit(PTS_UNRESOLVED);
252 	}
253 	rc = pthread_mutex_unlock(&cond_mutex);
254 	if(rc != 0) {
255 		printf(ERROR_PREFIX "pthread_mutex_unlock\n");
256 		exit(PTS_UNRESOLVED);
257 	}
258 
259 	/* Wake the other high priority thread up */
260 	rc = pthread_mutex_unlock(&mutex);
261 	if(rc != 0) {
262 		printf(ERROR_PREFIX "pthread_mutex_unlock\n");
263 		exit(PTS_UNRESOLVED);
264 	}
265 
266 	/* Wait for the threads to exit */
267 	rc = pthread_join(high_id, NULL);
268 	if(rc != 0) {
269 		printf(ERROR_PREFIX "pthread_join\n");
270 		exit(PTS_UNRESOLVED);
271 	}
272 
273 	rc = pthread_join(low_id, NULL);
274 	if(rc != 0) {
275 		printf(ERROR_PREFIX "pthread_join\n");
276 		exit(PTS_UNRESOLVED);
277 	}
278 
279 	/* Check the result */
280 	if(woken_up == -1) {
281 		printf("High priority was not woken up. Test FAILED.\n");
282 		exit(PTS_FAIL);
283 	}
284 	printf("Test PASS\n");
285 	exit(PTS_PASS);
286 }
287