]> git.saurik.com Git - apple/xnu.git/blob - tools/tests/xnu_quick_test/sched_tests.c
xnu-2422.90.20.tar.gz
[apple/xnu.git] / tools / tests / xnu_quick_test / sched_tests.c
1 /*
2 * sched_tests.c
3 * xnu_quick_test
4 *
5 * Copyright 2011 Apple Inc. All rights reserved.
6 *
7 */
8
9 #include "tests.h"
10 #include <mach/mach.h>
11 #include <mach/mach_time.h>
12 #include <mach/semaphore.h>
13 #include <unistd.h>
14 #include <err.h>
15 #include <sys/param.h>
16 #include <pthread.h>
17
18 #define DEBUG 0
19
20 #if DEBUG
21 #define dprintf(...) printf(__VA_ARGS__)
22 #else
23 #define dprintf(...) do { } while(0)
24 #endif
25
26 static uint64_t
27 nanos_to_abs(uint64_t ns, uint32_t numer, uint32_t denom)
28 {
29 return (uint64_t)(ns * (((double)denom) / ((double)numer)));
30 }
31
32 static void set_realtime(void) {
33 struct mach_timebase_info mti;
34 thread_time_constraint_policy_data_t pol;
35 kern_return_t kret;
36
37 kret = mach_timebase_info(&mti);
38 if (kret != KERN_SUCCESS) {
39 warnx("Could not get timebase info %d", kret);
40 return;
41 }
42
43 /* 1s 100ms 10ms */
44 pol.period = nanos_to_abs(1000000000, mti.numer, mti.denom);
45 pol.constraint = nanos_to_abs(100000000, mti.numer, mti.denom);
46 pol.computation = nanos_to_abs(10000000, mti.numer, mti.denom);
47 pol.preemptible = 0; /* Ignored by OS */
48
49 kret = thread_policy_set(mach_thread_self(), THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t) &pol, THREAD_TIME_CONSTRAINT_POLICY_COUNT);
50 if (kret != KERN_SUCCESS) {
51 warnx("Failed to set realtime %d", kret);
52 }
53 }
54
55 struct t1_ctx {
56 pthread_t __p;
57 int currentThread;
58 int totalThreads;
59 boolean_t useRealtime;
60 semaphore_t wait_to_start;
61 semaphore_t next_waiter;
62
63 semaphore_t common_sema; /* main thing everyone blocks on */
64 uint64_t wakeup_time; /* out parameter */
65 };
66
67 void *t1(void *arg) {
68 struct t1_ctx *ctx = (struct t1_ctx *)arg;
69 kern_return_t kret;
70
71 dprintf("thread %d (pthread %p) started\n", ctx->currentThread, pthread_self());
72
73 /* Wait to allow previous thread to block on common semaphore */
74 kret = semaphore_wait(ctx->wait_to_start);
75 if (kret != KERN_SUCCESS) {
76 warnx("semaphore_wait(wait_to_start) thread %d failed %d",
77 ctx->currentThread, kret);
78 }
79
80 sleep(1);
81
82 if (ctx->useRealtime) {
83 dprintf("thread %d going realtime\n", ctx->currentThread);
84 set_realtime();
85 }
86
87 kret = semaphore_signal(ctx->next_waiter);
88 if (kret != KERN_SUCCESS) {
89 warnx("semaphore_signal(next_waiter) thread %d failed %d",
90 ctx->currentThread, kret);
91 }
92
93 /*
94 * We have 1 second to block on the common semaphore before
95 * the next thread does.
96 */
97 dprintf("thread %d blocking on common semaphore\n", ctx->currentThread);
98
99 kret = semaphore_wait(ctx->common_sema);
100 if (kret != KERN_SUCCESS) {
101 warnx("semaphore_wait(common_sema) thread %d failed %d",
102 ctx->currentThread, kret);
103 }
104
105 /* Save our time for analysis */
106 ctx->wakeup_time = mach_absolute_time();
107 dprintf("thread %d woke up at %llu\n", ctx->currentThread, ctx->wakeup_time);
108
109 kret = semaphore_signal(ctx->common_sema);
110 if (kret != KERN_SUCCESS) {
111 warnx("semaphore_signal(common_sema) thread %d failed %d",
112 ctx->currentThread, kret);
113 }
114
115 return NULL;
116 }
117
118
119
120
121 int sched_tests( void * the_argp )
122 {
123 kern_return_t kret;
124 int ret;
125 int i;
126 semaphore_t common_sema;
127 semaphore_t all_checked_in;
128
129 struct t1_ctx ctxs[3];
130
131 /*
132 * Test 8979062. Ensure that a realtime thread that
133 * blocks on a semaphore after a non-realtime thread
134 * gets woken up first.
135 */
136
137 kret = semaphore_create(mach_task_self(), &common_sema, SYNC_POLICY_FIFO /* not really, in this case */, 0);
138 if (kret != KERN_SUCCESS) {
139 warnx("semaphore_create failed: %d", kret);
140 return -1;
141 }
142
143 kret = semaphore_create(mach_task_self(), &all_checked_in, SYNC_POLICY_FIFO, 0);
144 if (kret != KERN_SUCCESS) {
145 warnx("semaphore_create failed: %d", kret);
146 return -1;
147 }
148
149 memset(&ctxs, 0x00, sizeof(ctxs));
150 for (i=0; i < sizeof(ctxs)/sizeof(ctxs[0]); i++) {
151 ctxs[i].__p = NULL; /* set later */
152 ctxs[i].currentThread = i;
153 ctxs[i].totalThreads = sizeof(ctxs)/sizeof(ctxs[0]);
154 ctxs[i].useRealtime = FALSE;
155
156 kret = semaphore_create(mach_task_self(), &ctxs[i].wait_to_start, SYNC_POLICY_FIFO /* not really, in this case */, 0);
157 if (kret != KERN_SUCCESS) {
158 warnx("semaphore_create failed: %d", kret);
159 return -1;
160 }
161 ctxs[i].next_waiter = MACH_PORT_NULL; /* set later */
162 ctxs[i].common_sema = common_sema;
163 ctxs[i].wakeup_time = 0;
164 }
165
166 ctxs[1].useRealtime = TRUE;
167
168 for (i=1; i < sizeof(ctxs)/sizeof(ctxs[0]); i++) {
169 ctxs[i-1].next_waiter = ctxs[i].wait_to_start;
170 }
171 ctxs[i-1].next_waiter = all_checked_in;
172
173
174 for (i=0; i < sizeof(ctxs)/sizeof(ctxs[0]); i++) {
175 ret = pthread_create(&ctxs[i].__p, NULL, t1, &ctxs[i]);
176 if (ret != 0) {
177 warn("pthread_create failed");
178 return -1;
179 }
180 }
181
182 /* wake up first thread */
183 kret = semaphore_signal(ctxs[0].wait_to_start);
184 if (kret != KERN_SUCCESS) {
185 warnx("semaphore_signal(initial wait_to_start) failed %d", kret);
186 return -1;
187 }
188
189 /* Wait for everyone to have blocked */
190 kret = semaphore_wait(all_checked_in);
191 if (kret != KERN_SUCCESS) {
192 warnx("semaphore_wait(all_checked_in) failed %d", kret);
193 return -1;
194 }
195
196 /* Give some slack for last guy */
197 sleep(1);
198
199 kret = semaphore_signal(common_sema);
200 if (kret != KERN_SUCCESS) {
201 warnx("semaphore_signal(initial common_sema) failed %d", kret);
202 return -1;
203 }
204
205 for (i=0; i < sizeof(ctxs)/sizeof(ctxs[0]); i++) {
206 ret = pthread_join(ctxs[i].__p, NULL);
207 if (ret != 0) {
208 warn("pthread_join failed");
209 return -1;
210 }
211 }
212
213 dprintf("All threads joined\n");
214
215 /*
216 * Our expectation is that thread 1 was realtime and
217 * finished first, followed by 0 and then 2
218 */
219 if ((ctxs[1].wakeup_time < ctxs[0].wakeup_time)
220 && (ctxs[0].wakeup_time < ctxs[2].wakeup_time)) {
221 /* success */
222 } else {
223 warnx("Threads woken out of order %llu %llu %llu",
224 ctxs[0].wakeup_time, ctxs[1].wakeup_time,
225 ctxs[2].wakeup_time);
226 return -1;
227 }
228
229 return 0;
230 }
231