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