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_barrier_wait()
9  * shall wakeup a high priority thread even when a low priority thread
10  * is running
11  *
12  * Steps:
13  * 1. Create a barrier object
14  * 2. Create a high priority thread and make it wait on the barrier
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. Call the final barrier_wait from main
18  * 6. Check that the higher priority thread got woken up
19  *    and preempted low priority thread
20  */
21 
22 #include "affinity.h"
23 #include <pthread.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <sys/time.h>
28 #include "posixtest.h"
29 #include "safe_helpers.h"
30 
31 #define TEST "5-4"
32 #define AREA "scheduler"
33 #define ERROR_PREFIX "unexpected error: " AREA " " TEST ": "
34 
35 #define HIGH_PRIORITY 10
36 #define LOW_PRIORITY 5
37 #define RUNTIME 5
38 
39 pthread_barrier_t barrier;
40 static volatile int woken_up;
41 static volatile int low_done;
42 
timediff(struct timespec t2,struct timespec t1)43 float timediff(struct timespec t2, struct timespec t1)
44 {
45 	float diff = t2.tv_sec - t1.tv_sec;
46 	diff += (t2.tv_nsec - t1.tv_nsec) / 1000000000.0;
47 	return diff;
48 }
49 
my_pthread_barrier_wait(pthread_barrier_t * p)50 int my_pthread_barrier_wait(pthread_barrier_t *p)
51 {
52 	int rc;
53 
54 	rc = pthread_barrier_wait(p);
55 	if (rc == PTHREAD_BARRIER_SERIAL_THREAD)
56 		rc = 0;
57 	return rc;
58 }
59 
hi_prio_thread(void * tmp)60 void *hi_prio_thread(void *tmp)
61 {
62 	struct sched_param param;
63 	int policy;
64 
65 	(void) tmp;
66 	set_affinity_single();
67 
68 	SAFE_PFUNC(pthread_getschedparam(pthread_self(), &policy, &param));
69 	if (policy != SCHED_RR || param.sched_priority != HIGH_PRIORITY) {
70 		printf("Error: the policy or priority not correct\n");
71 		exit(PTS_UNRESOLVED);
72 	}
73 
74 	SAFE_PFUNC(my_pthread_barrier_wait(&barrier));
75 
76 	/* This variable is unprotected because the scheduling removes
77 	 * the contention
78 	 */
79 	if (!low_done)
80 		woken_up = 1;
81 
82 	pthread_exit(NULL);
83 }
84 
low_prio_thread(void * tmp)85 void *low_prio_thread(void *tmp)
86 {
87 	struct timespec start_timespec, current_timespec;
88 	struct sched_param param;
89 	int policy;
90 
91 	(void) tmp;
92 	set_affinity_single();
93 
94 	SAFE_PFUNC(pthread_getschedparam(pthread_self(), &policy, &param));
95 	if (policy != SCHED_RR || param.sched_priority != LOW_PRIORITY) {
96 		printf("Error: the policy or priority not correct\n");
97 		exit(PTS_UNRESOLVED);
98 	}
99 
100 	clock_gettime(CLOCK_REALTIME, &start_timespec);
101 	while (!woken_up) {
102 		clock_gettime(CLOCK_REALTIME, &current_timespec);
103 		if (timediff(current_timespec, start_timespec) > RUNTIME)
104 			break;
105 	}
106 	low_done = 1;
107 
108 	pthread_exit(NULL);
109 }
110 
main()111 int main()
112 {
113 	pthread_t high_id, low_id;
114 	pthread_attr_t high_attr;
115 	struct sched_param param;
116 
117 	SAFE_PFUNC(pthread_barrier_init(&barrier, NULL, 2));
118 
119 	/* Create the higher priority */
120 	SAFE_PFUNC(pthread_attr_init(&high_attr));
121 	SAFE_PFUNC(pthread_attr_setinheritsched(&high_attr, PTHREAD_EXPLICIT_SCHED));
122 	SAFE_PFUNC(pthread_attr_setschedpolicy(&high_attr, SCHED_RR));
123 	param.sched_priority = HIGH_PRIORITY;
124 	SAFE_PFUNC(pthread_attr_setschedparam(&high_attr, &param));
125 	SAFE_PFUNC(pthread_create(&high_id, &high_attr, hi_prio_thread, NULL));
126 
127 	/* run main with same priority as low prio thread */
128 	param.sched_priority = LOW_PRIORITY;
129 	SAFE_PFUNC(pthread_setschedparam(pthread_self(), SCHED_RR, &param));
130 
131 	/* Create the low priority thread (inherits sched policy from main) */
132 	SAFE_PFUNC(pthread_create(&low_id, NULL, low_prio_thread, NULL));
133 
134 	sleep(1);
135 	SAFE_PFUNC(my_pthread_barrier_wait(&barrier));
136 
137 	/* Wait for the threads to exit */
138 	SAFE_PFUNC(pthread_join(low_id, NULL));
139 	if (!woken_up) {
140 		printf("High priority was not woken up. Test FAILED\n");
141 		exit(PTS_FAIL);
142 	}
143 	SAFE_PFUNC(pthread_join(high_id, NULL));
144 
145 	printf("Test PASSED\n");
146 	exit(PTS_PASS);
147 }
148