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*/ 39pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 40/* mutex required by the cond variable */ 41pthread_mutex_t cond_mutex = PTHREAD_MUTEX_INITIALIZER; 42/* condition variable that threads block on*/ 43pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 44 45volatile int woken_up = -1; 46volatile int low_done = -1; 47 48/* Utility function to find difference between two time values */ 49float 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 */ 59void 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 70void *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 117void *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 155int 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