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, ¶m);
78 if(rc != 0) {
79 printf(ERROR_PREFIX "pthread_setschedparam\n");
80 exit(PTS_UNRESOLVED);
81 }
82 rc = pthread_getschedparam(pthread_self(), &policy, ¶m);
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, ¶m);
126 if(rc != 0) {
127 printf(ERROR_PREFIX "pthread_setschedparam\n");
128 exit(PTS_UNRESOLVED);
129 }
130 rc = pthread_getschedparam(pthread_self(), &policy, ¶m);
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, ¤t_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, ¶m);
165 if(rc != 0) {
166 printf(ERROR_PREFIX "pthread_setschedparam\n");
167 exit(PTS_UNRESOLVED);
168 }
169 rc = pthread_getschedparam(pthread_self(), &policy, ¶m);
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, ¶m);
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, ¶m);
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