5 * Copyright 2011 Apple Inc. All rights reserved.
10 #include <mach/mach.h>
11 #include <mach/mach_time.h>
12 #include <mach/semaphore.h>
15 #include <sys/param.h>
21 #define dprintf(...) printf(__VA_ARGS__)
23 #define dprintf(...) do { } while(0)
27 nanos_to_abs(uint64_t ns
, uint32_t numer
, uint32_t denom
)
29 return (uint64_t)(ns
* (((double)denom
) / ((double)numer
)));
32 static void set_realtime(void) {
33 struct mach_timebase_info mti
;
34 thread_time_constraint_policy_data_t pol
;
37 kret
= mach_timebase_info(&mti
);
38 if (kret
!= KERN_SUCCESS
) {
39 warnx("Could not get timebase info %d", kret
);
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 */
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
);
59 boolean_t useRealtime
;
60 semaphore_t wait_to_start
;
61 semaphore_t next_waiter
;
63 semaphore_t common_sema
; /* main thing everyone blocks on */
64 uint64_t wakeup_time
; /* out parameter */
68 struct t1_ctx
*ctx
= (struct t1_ctx
*)arg
;
71 dprintf("thread %d (pthread %p) started\n", ctx
->currentThread
, pthread_self());
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
);
82 if (ctx
->useRealtime
) {
83 dprintf("thread %d going realtime\n", ctx
->currentThread
);
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
);
94 * We have 1 second to block on the common semaphore before
95 * the next thread does.
97 dprintf("thread %d blocking on common semaphore\n", ctx
->currentThread
);
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
);
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
);
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
);
121 int sched_tests( void * the_argp
)
126 semaphore_t common_sema
;
127 semaphore_t all_checked_in
;
129 struct t1_ctx ctxs
[3];
132 * Test 8979062. Ensure that a realtime thread that
133 * blocks on a semaphore after a non-realtime thread
134 * gets woken up first.
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
);
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
);
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
;
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
);
161 ctxs
[i
].next_waiter
= MACH_PORT_NULL
; /* set later */
162 ctxs
[i
].common_sema
= common_sema
;
163 ctxs
[i
].wakeup_time
= 0;
166 ctxs
[1].useRealtime
= TRUE
;
168 for (i
=1; i
< sizeof(ctxs
)/sizeof(ctxs
[0]); i
++) {
169 ctxs
[i
-1].next_waiter
= ctxs
[i
].wait_to_start
;
171 ctxs
[i
-1].next_waiter
= all_checked_in
;
174 for (i
=0; i
< sizeof(ctxs
)/sizeof(ctxs
[0]); i
++) {
175 ret
= pthread_create(&ctxs
[i
].__p
, NULL
, t1
, &ctxs
[i
]);
177 warn("pthread_create failed");
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
);
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
);
196 /* Give some slack for last guy */
199 kret
= semaphore_signal(common_sema
);
200 if (kret
!= KERN_SUCCESS
) {
201 warnx("semaphore_signal(initial common_sema) failed %d", kret
);
205 for (i
=0; i
< sizeof(ctxs
)/sizeof(ctxs
[0]); i
++) {
206 ret
= pthread_join(ctxs
[i
].__p
, NULL
);
208 warn("pthread_join failed");
213 dprintf("All threads joined\n");
216 * Our expectation is that thread 1 was realtime and
217 * finished first, followed by 0 and then 2
219 if ((ctxs
[1].wakeup_time
< ctxs
[0].wakeup_time
)
220 && (ctxs
[0].wakeup_time
< ctxs
[2].wakeup_time
)) {
223 warnx("Threads woken out of order %llu %llu %llu",
224 ctxs
[0].wakeup_time
, ctxs
[1].wakeup_time
,
225 ctxs
[2].wakeup_time
);