Home | History | Annotate | Download | only in schedule
      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. Both low and high prio threads run on same CPU
     17  * 5. Unlock the mutex and make sure that the higher priority thread
     18  *    got woken up and preempted low priority thread
     19  */
     20 
     21 #include "affinity.h"
     22 #include <pthread.h>
     23 #include <stdio.h>
     24 #include <stdlib.h>
     25 #include <unistd.h>
     26 #include <sys/time.h>
     27 #include "posixtest.h"
     28 #include "safe_helpers.h"
     29 
     30 #define TEST "5-5"
     31 #define AREA "scheduler"
     32 #define ERROR_PREFIX "unexpected error: " AREA " " TEST ": "
     33 
     34 #define HIGH_PRIORITY 10
     35 #define MID_PRIORITY 7
     36 #define LOW_PRIORITY 5
     37 #define RUNTIME 5
     38 
     39 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
     40 
     41 static volatile int woken_up;
     42 static volatile int low_done;
     43 
     44 float timediff(struct timespec t2, struct timespec t1)
     45 {
     46 	float diff = t2.tv_sec - t1.tv_sec;
     47 	diff += (t2.tv_nsec - t1.tv_nsec) / 1000000000.0;
     48 	return diff;
     49 }
     50 
     51 void *hi_prio_thread(void *tmp)
     52 {
     53 	struct sched_param param;
     54 	int policy;
     55 
     56 	(void) tmp;
     57 	set_affinity_single();
     58 
     59 	SAFE_PFUNC(pthread_getschedparam(pthread_self(), &policy, &param));
     60 	if (policy != SCHED_RR) {
     61 		printf(ERROR_PREFIX "The policy is not correct\n");
     62 		exit(PTS_UNRESOLVED);
     63 	}
     64 	if (param.sched_priority != HIGH_PRIORITY) {
     65 		printf(ERROR_PREFIX "The priority is not correct\n");
     66 		exit(PTS_UNRESOLVED);
     67 	}
     68 
     69 	SAFE_PFUNC(pthread_mutex_lock(&mutex));
     70 
     71 	/* This variable is unprotected because the scheduling removes
     72 	 * the contention
     73 	 */
     74 	if (!low_done)
     75 		woken_up = 1;
     76 
     77 	SAFE_PFUNC(pthread_mutex_unlock(&mutex));
     78 	pthread_exit(NULL);
     79 }
     80 
     81 void *low_prio_thread(void *tmp)
     82 {
     83 	struct timespec current_time, start_time;
     84 	struct sched_param param;
     85 	int policy;
     86 
     87 	(void) tmp;
     88 	set_affinity_single();
     89 
     90 	SAFE_PFUNC(pthread_getschedparam(pthread_self(), &policy, &param));
     91 	if (policy != SCHED_RR) {
     92 		printf(ERROR_PREFIX "Policy not correct\n");
     93 		exit(PTS_UNRESOLVED);
     94 	}
     95 	if (param.sched_priority != LOW_PRIORITY) {
     96 		printf(ERROR_PREFIX "Priority not correct\n");
     97 		exit(PTS_UNRESOLVED);
     98 	}
     99 
    100 	clock_gettime(CLOCK_REALTIME, &start_time);
    101 	while (!woken_up) {
    102 		clock_gettime(CLOCK_REALTIME, &current_time);
    103 		if (timediff(current_time, start_time) > RUNTIME)
    104 			break;
    105 	}
    106 	low_done = 1;
    107 	pthread_exit(NULL);
    108 }
    109 
    110 int main()
    111 {
    112 	pthread_t high_id, low_id;
    113 	pthread_attr_t low_attr, high_attr;
    114 	struct sched_param param;
    115 	int policy;
    116 
    117 	param.sched_priority = MID_PRIORITY;
    118 	SAFE_PFUNC(pthread_setschedparam(pthread_self(), SCHED_RR, &param));
    119 	SAFE_PFUNC(pthread_getschedparam(pthread_self(), &policy, &param));
    120 	if (policy != SCHED_RR) {
    121 		printf(ERROR_PREFIX "The policy is not correct\n");
    122 		exit(PTS_UNRESOLVED);
    123 	}
    124 	if (param.sched_priority != MID_PRIORITY) {
    125 		printf(ERROR_PREFIX "The priority is not correct\n");
    126 		exit(PTS_UNRESOLVED);
    127 	}
    128 
    129 	SAFE_PFUNC(pthread_mutex_lock(&mutex));
    130 
    131 	/* create the higher priority */
    132 	SAFE_PFUNC(pthread_attr_init(&high_attr));
    133 	SAFE_PFUNC(pthread_attr_setinheritsched(&high_attr, PTHREAD_EXPLICIT_SCHED));
    134 	SAFE_PFUNC(pthread_attr_setschedpolicy(&high_attr, SCHED_RR));
    135 	param.sched_priority = HIGH_PRIORITY;
    136 	SAFE_PFUNC(pthread_attr_setschedparam(&high_attr, &param));
    137 	SAFE_PFUNC(pthread_create(&high_id, &high_attr, hi_prio_thread, NULL));
    138 
    139 	/* Create the low priority thread */
    140 	SAFE_PFUNC(pthread_attr_init(&low_attr));
    141 	SAFE_PFUNC(pthread_attr_setinheritsched(&low_attr, PTHREAD_EXPLICIT_SCHED));
    142 	SAFE_PFUNC(pthread_attr_setschedpolicy(&low_attr, SCHED_RR));
    143 	param.sched_priority = LOW_PRIORITY;
    144 	SAFE_PFUNC(pthread_attr_setschedparam(&low_attr, &param));
    145 	SAFE_PFUNC(pthread_create(&low_id, &low_attr, low_prio_thread, NULL));
    146 
    147 	sleep(1);
    148 
    149 	/* Wake the other high priority thread up */
    150 	SAFE_PFUNC(pthread_mutex_unlock(&mutex));
    151 
    152 	/* Wait for the threads to exit */
    153 	SAFE_PFUNC(pthread_join(low_id, NULL));
    154 	if (!woken_up) {
    155 		printf("High priority was not woken up. Test FAILED.\n");
    156 		exit(PTS_FAIL);
    157 	}
    158 	SAFE_PFUNC(pthread_join(high_id, NULL));
    159 
    160 	printf("Test PASSED\n");
    161 	exit(PTS_PASS);
    162 }
    163