1 /* test that the header doesn't implicitly depend on others */
2 #include <sys/work_interval.h>
12 #include <mach/mach.h>
14 #include <darwintest.h>
16 T_GLOBAL_META(T_META_NAMESPACE("xnu.scheduler"),
17 T_META_RUN_CONCURRENTLY(true));
19 static mach_port_t port
= MACH_PORT_NULL
;
22 joining_thread_fn(__unused
void *arg
)
25 kern_return_t kr
= KERN_SUCCESS
;
27 ret
= work_interval_join_port(port
);
28 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_join_port, another thread");
30 kr
= mach_port_deallocate(mach_task_self(), port
);
31 T_ASSERT_MACH_SUCCESS(kr
, "mach_port_deallocate of port, another thread");
33 /* deliberately exit with joined work interval */
37 T_DECL(work_interval
, "work interval interface")
40 work_interval_t handle
= NULL
;
41 uint64_t now
= mach_absolute_time();
42 kern_return_t kr
= KERN_SUCCESS
;
44 ret
= work_interval_create(NULL
, 0);
45 T_ASSERT_EQ(errno
, EINVAL
, "create with null errno EINVAL");
46 T_ASSERT_EQ(ret
, -1, "create with null returns -1");
48 /* Binary must be entitled for this to succeed */
49 ret
= work_interval_create(&handle
, 0);
50 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_create, no flags");
52 ret
= work_interval_copy_port(handle
, &port
);
53 T_ASSERT_EQ(errno
, EINVAL
, "work_interval_copy_port on non-joinable interval errno EINVAL");
54 T_ASSERT_EQ(ret
, -1, "work_interval_copy_port on non-joinable interval returns -1");
56 ret
= work_interval_notify(handle
, now
- 1000, now
, now
+ 1000, now
+ 2000, 0);
57 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_notify, no flags");
59 ret
= work_interval_destroy(handle
);
60 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_destroy, no flags");
63 WORK_INTERVAL_FLAG_JOINABLE
,
64 WORK_INTERVAL_FLAG_JOINABLE
| WORK_INTERVAL_FLAG_GROUP
,
67 for (uint32_t i
= 0; i
< sizeof(flags
) / sizeof(flags
[0]); i
++) {
68 ret
= work_interval_create(&handle
, flags
[i
]);
69 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_create, joinable");
71 ret
= work_interval_copy_port(handle
, &port
);
72 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_copy_port, joinable");
74 ret
= work_interval_notify(handle
, now
- 1000, now
, now
+ 1000, now
+ 2000, 0);
75 T_ASSERT_EQ(ret
, -1, "work_interval_notify on non-joined thread returns -1");
76 T_ASSERT_EQ(errno
, EINVAL
, "work_interval_copy_port on non-joined thread errno EINVAL");
78 ret
= work_interval_join_port(port
);
79 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_join_port, joinable");
81 ret
= work_interval_notify(handle
, now
- 1000, now
, now
+ 1000, now
+ 2000, 0);
82 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_notify, on joined thread");
84 ret
= work_interval_join_port(port
);
85 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_join_port, join the same interval after destroy");
87 kr
= mach_port_deallocate(mach_task_self(), port
);
88 T_ASSERT_MACH_SUCCESS(kr
, "mach_port_deallocate of port");
90 ret
= work_interval_notify(handle
, now
- 1000, now
, now
+ 1000, now
+ 2000, 0);
91 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_notify, on joined thread after destroy");
93 ret
= work_interval_destroy(handle
);
94 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_destroy, joinable, on joined thread");
96 ret
= work_interval_leave();
97 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_leave, on destroyed work interval");
100 ret
= work_interval_create(&handle
, WORK_INTERVAL_FLAG_JOINABLE
| WORK_INTERVAL_FLAG_GROUP
);
101 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_create, joinable");
103 ret
= work_interval_copy_port(handle
, &port
);
104 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_copy_port, joinable");
106 ret
= work_interval_join_port(port
);
107 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_join_port, join before handing to another thread");
109 pthread_t joining_thread
;
111 T_ASSERT_POSIX_ZERO(pthread_create(&joining_thread
, NULL
, joining_thread_fn
, NULL
), "pthread_create");
113 T_ASSERT_POSIX_ZERO(pthread_join(joining_thread
, NULL
), "pthread_join");
115 ret
= work_interval_leave();
116 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_leave");
118 ret
= work_interval_destroy(handle
);
119 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_destroy");
122 static mach_timebase_info_data_t timebase_info
;
125 nanos_to_abs(uint64_t nanos
)
127 mach_timebase_info(&timebase_info
);
128 return nanos
* timebase_info
.denom
/ timebase_info
.numer
;
132 set_realtime(pthread_t thread
)
135 thread_time_constraint_policy_data_t pol
;
137 mach_port_t target_thread
= pthread_mach_thread_np(thread
);
138 T_ASSERT_NOTNULL(target_thread
, "pthread_mach_thread_np");
141 pol
.period
= (uint32_t)nanos_to_abs(1000000000);
142 pol
.constraint
= (uint32_t)nanos_to_abs(100000000);
143 pol
.computation
= (uint32_t)nanos_to_abs(10000000);
145 pol
.preemptible
= 0; /* Ignored by OS */
146 kr
= thread_policy_set(target_thread
, THREAD_TIME_CONSTRAINT_POLICY
, (thread_policy_t
) &pol
,
147 THREAD_TIME_CONSTRAINT_POLICY_COUNT
);
148 T_ASSERT_MACH_SUCCESS(kr
, "thread_policy_set(THREAD_TIME_CONSTRAINT_POLICY)");
152 set_nonrealtime(pthread_t thread
)
155 thread_standard_policy_data_t pol
= {0};
157 mach_port_t target_thread
= pthread_mach_thread_np(thread
);
158 T_ASSERT_NOTNULL(target_thread
, "pthread_mach_thread_np");
160 kr
= thread_policy_set(target_thread
, THREAD_STANDARD_POLICY
, (thread_policy_t
) &pol
,
161 THREAD_STANDARD_POLICY_COUNT
);
162 T_ASSERT_MACH_SUCCESS(kr
, "thread_policy_set(THREAD_STANDARD_POLICY)");
165 T_DECL(work_interval_audio_realtime_only
, "joining RT threads to audio work interval", T_META_ASROOT(YES
))
168 work_interval_t handle
= NULL
;
169 kern_return_t kr
= KERN_SUCCESS
;
171 uint32_t flags
= WORK_INTERVAL_FLAG_GROUP
| WORK_INTERVAL_FLAG_JOINABLE
| WORK_INTERVAL_TYPE_COREAUDIO
;
173 ret
= work_interval_create(&handle
, flags
);
174 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_create, joinable");
176 ret
= work_interval_copy_port(handle
, &port
);
177 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_copy_port, joinable");
179 ret
= work_interval_join_port(port
);
180 T_EXPECT_POSIX_FAILURE(ret
, EINVAL
, "work_interval_join_port for audio on non-RT thread");
182 set_realtime(pthread_self());
184 ret
= work_interval_join_port(port
);
185 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_join_port for audio on RT thread");
187 ret
= work_interval_leave();
188 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_leave");
190 ret
= work_interval_destroy(handle
);
191 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_destroy");
193 kr
= mach_port_deallocate(mach_task_self(), port
);
194 T_ASSERT_MACH_SUCCESS(kr
, "mach_port_deallocate of port");
196 set_nonrealtime(pthread_self());
199 T_DECL(work_interval_get_flags
, "querying a port for create flags")
202 work_interval_t handle
= NULL
;
203 uint32_t flags
= WORK_INTERVAL_FLAG_JOINABLE
| WORK_INTERVAL_FLAG_GROUP
| WORK_INTERVAL_TYPE_COREAUDIO
;
205 ret
= work_interval_create(&handle
, flags
);
206 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_create(AUDIO)");
208 ret
= work_interval_copy_port(handle
, &port
);
209 T_ASSERT_POSIX_SUCCESS(ret
, "work_interval_copy_port");
210 T_ASSERT_TRUE(MACH_PORT_VALID(port
), "port from copy port is a valid port");
212 uint32_t expected_flags
= 0;
214 ret
= work_interval_get_flags_from_port(port
, &expected_flags
);
215 T_ASSERT_EQ(ret
, 0, "work_interval_get_flags_from_port");
217 T_ASSERT_EQ(expected_flags
, flags
, "Flags match with what work interval was created with");
219 mach_port_mod_refs(mach_task_self(), port
, MACH_PORT_RIGHT_SEND
, -1);
220 work_interval_destroy(handle
);
224 mach_port_t fake_port
= MACH_PORT_NULL
;
225 ret
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &fake_port
);
226 T_ASSERT_EQ(ret
, 0, "successfully allocated a port");
227 T_ASSERT_TRUE(MACH_PORT_VALID(fake_port
), "allocated port is valid");
229 ret
= mach_port_insert_right(mach_task_self(), fake_port
, fake_port
, MACH_MSG_TYPE_MAKE_SEND
);
230 T_ASSERT_EQ(ret
, 0, "successfully inserted a send right");
232 ret
= work_interval_get_flags_from_port(fake_port
, &expected_flags
);
233 T_ASSERT_EQ(ret
, -1, "query port failed as expected");
235 mach_port_mod_refs(mach_task_self(), fake_port
, MACH_PORT_RIGHT_SEND
, -1);
236 mach_port_mod_refs(mach_task_self(), fake_port
, MACH_PORT_RIGHT_RECEIVE
, -1);