]>
Commit | Line | Data |
---|---|---|
f427ee49 A |
1 | /* test that the header doesn't implicitly depend on others */ |
2 | #include <sys/work_interval.h> | |
3 | ||
4 | #include <stdlib.h> | |
5 | #include <stdio.h> | |
6 | #include <unistd.h> | |
7 | #include <errno.h> | |
8 | #include <err.h> | |
9 | #include <string.h> | |
10 | #include <pthread.h> | |
11 | ||
12 | #include <mach/mach.h> | |
13 | ||
14 | #include <darwintest.h> | |
15 | ||
16 | T_GLOBAL_META(T_META_NAMESPACE("xnu.scheduler"), | |
17 | T_META_RUN_CONCURRENTLY(true)); | |
18 | ||
19 | static mach_port_t port = MACH_PORT_NULL; | |
20 | ||
21 | static mach_timebase_info_data_t timebase_info; | |
22 | ||
23 | static uint64_t | |
24 | nanos_to_abs(uint64_t nanos) | |
25 | { | |
26 | mach_timebase_info(&timebase_info); | |
27 | return nanos * timebase_info.denom / timebase_info.numer; | |
28 | } | |
29 | ||
30 | static void | |
31 | set_realtime(pthread_t thread) | |
32 | { | |
33 | kern_return_t kr; | |
34 | thread_time_constraint_policy_data_t pol; | |
35 | ||
36 | mach_port_t target_thread = pthread_mach_thread_np(thread); | |
37 | T_EXPECT_NE(target_thread, MACH_PORT_NULL, "pthread_mach_thread_np"); | |
38 | ||
39 | /* 1s 100ms 10ms */ | |
40 | pol.period = (uint32_t)nanos_to_abs(1000000000); | |
41 | pol.constraint = (uint32_t)nanos_to_abs(100000000); | |
42 | pol.computation = (uint32_t)nanos_to_abs(10000000); | |
43 | ||
44 | pol.preemptible = 0; /* Ignored by OS */ | |
45 | kr = thread_policy_set(target_thread, THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t) &pol, | |
46 | THREAD_TIME_CONSTRAINT_POLICY_COUNT); | |
47 | T_ASSERT_MACH_SUCCESS(kr, "thread_policy_set(THREAD_TIME_CONSTRAINT_POLICY)"); | |
48 | } | |
49 | ||
50 | static void | |
51 | set_nonrealtime(pthread_t thread) | |
52 | { | |
53 | kern_return_t kr; | |
54 | thread_standard_policy_data_t pol = {0}; | |
55 | ||
56 | mach_port_t target_thread = pthread_mach_thread_np(thread); | |
57 | T_EXPECT_NE(target_thread, MACH_PORT_NULL, "pthread_mach_thread_np"); | |
58 | ||
59 | kr = thread_policy_set(target_thread, THREAD_STANDARD_POLICY, (thread_policy_t) &pol, | |
60 | THREAD_STANDARD_POLICY_COUNT); | |
61 | T_ASSERT_MACH_SUCCESS(kr, "thread_policy_set(THREAD_STANDARD_POLICY)"); | |
62 | } | |
63 | ||
64 | T_DECL(unentitled_work_intervals, "work interval interface for unentitled types") | |
65 | { | |
66 | int ret = 0; | |
67 | work_interval_t handle = NULL; | |
68 | uint64_t now = mach_absolute_time(); | |
69 | kern_return_t kr = KERN_SUCCESS; | |
70 | ||
71 | ret = work_interval_create(NULL, 0); | |
72 | T_ASSERT_EQ(errno, EINVAL, "create with null errno EINVAL"); | |
73 | T_ASSERT_EQ(ret, -1, "create with null returns -1"); | |
74 | ||
75 | ret = work_interval_create(&handle, WORK_INTERVAL_FLAG_GROUP | WORK_INTERVAL_FLAG_UNRESTRICTED | WORK_INTERVAL_TYPE_DEFAULT); | |
76 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_create, public flags"); | |
77 | ||
78 | ret = work_interval_copy_port(handle, &port); | |
79 | T_ASSERT_EQ(errno, EINVAL, "work_interval_copy_port on non-joinable interval errno EINVAL"); | |
80 | T_ASSERT_EQ(ret, -1, "work_interval_copy_port on non-joinable interval returns -1"); | |
81 | ||
82 | ret = work_interval_notify(handle, now - 1000, now, now + 1000, now + 2000, 0); | |
83 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_notify, no flags"); | |
84 | ||
85 | ret = work_interval_destroy(handle); | |
86 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_destroy, no flags"); | |
87 | ||
88 | uint32_t flags[] = { | |
89 | WORK_INTERVAL_FLAG_JOINABLE | WORK_INTERVAL_FLAG_GROUP | WORK_INTERVAL_FLAG_UNRESTRICTED | WORK_INTERVAL_TYPE_DEFAULT, | |
90 | }; | |
91 | ||
92 | for (uint32_t i = 0; i < sizeof(flags) / sizeof(flags[0]); i++) { | |
93 | ret = work_interval_create(&handle, flags[i]); | |
94 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_create, joinable"); | |
95 | ||
96 | ret = work_interval_copy_port(handle, &port); | |
97 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_copy_port, joinable"); | |
98 | ||
99 | ret = work_interval_notify(handle, now - 1000, now, now + 1000, now + 2000, 0); | |
100 | T_ASSERT_EQ(ret, -1, "work_interval_notify on non-joined thread returns -1"); | |
101 | T_ASSERT_EQ(errno, EINVAL, "work_interval_copy_port on non-joined thread errno EINVAL"); | |
102 | ||
103 | ret = work_interval_join_port(port); | |
104 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_join_port, joinable"); | |
105 | ||
106 | ret = work_interval_notify(handle, now - 1000, now, now + 1000, now + 2000, 0); | |
107 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_notify, on joined thread"); | |
108 | ||
109 | ret = work_interval_join_port(port); | |
110 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_join_port, join the same interval after destroy"); | |
111 | ||
112 | kr = mach_port_deallocate(mach_task_self(), port); | |
113 | T_ASSERT_MACH_SUCCESS(kr, "mach_port_deallocate of port"); | |
114 | ||
115 | ret = work_interval_notify(handle, now - 1000, now, now + 1000, now + 2000, 0); | |
116 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_notify, on joined thread after destroy"); | |
117 | ||
118 | ret = work_interval_destroy(handle); | |
119 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_destroy, joinable, on joined thread"); | |
120 | ||
121 | ret = work_interval_leave(); | |
122 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_leave, on destroyed work interval"); | |
123 | } | |
124 | } | |
125 | ||
126 | T_DECL(unentitled_work_interval_create_while_joined, "work interval interface: create while joined") | |
127 | { | |
128 | int ret = 0; | |
129 | work_interval_t handle = NULL; | |
130 | work_interval_t handle2 = NULL; | |
131 | mach_port_t port1 = MACH_PORT_NULL; | |
132 | mach_port_t port2 = MACH_PORT_NULL; | |
133 | kern_return_t kr = KERN_SUCCESS; | |
134 | ||
135 | uint32_t flags = WORK_INTERVAL_FLAG_JOINABLE | WORK_INTERVAL_FLAG_GROUP | WORK_INTERVAL_FLAG_UNRESTRICTED | WORK_INTERVAL_TYPE_DEFAULT; | |
136 | ||
137 | ret = work_interval_create(&handle, flags); | |
138 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_create, joinable"); | |
139 | ||
140 | ret = work_interval_copy_port(handle, &port1); | |
141 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_copy_port, joinable"); | |
142 | ||
143 | ret = work_interval_join_port(port1); | |
144 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_join_port, joinable"); | |
145 | ||
146 | ||
147 | ret = work_interval_create(&handle2, flags); | |
148 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_create, joinable, while already joined"); | |
149 | ||
150 | ret = work_interval_copy_port(handle2, &port2); | |
151 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_copy_port, joinable, while already joined"); | |
152 | ||
153 | ret = work_interval_join_port(port2); | |
154 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_join_port, joinable, while already joined"); | |
155 | ||
156 | ret = work_interval_leave(); | |
157 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_leave, first time"); | |
158 | ||
159 | ret = work_interval_leave(); | |
160 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_leave, again"); | |
161 | ||
162 | ret = work_interval_destroy(handle); | |
163 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_destroy"); | |
164 | ||
165 | ret = work_interval_destroy(handle2); | |
166 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_destroy"); | |
167 | ||
168 | kr = mach_port_deallocate(mach_task_self(), port1); | |
169 | T_ASSERT_MACH_SUCCESS(kr, "mach_port_deallocate of port"); | |
170 | ||
171 | kr = mach_port_deallocate(mach_task_self(), port2); | |
172 | T_ASSERT_MACH_SUCCESS(kr, "mach_port_deallocate of port"); | |
173 | } | |
174 | ||
175 | T_DECL(work_interval_audio_unentitled, "unentitled work interval for audio") | |
176 | { | |
177 | int ret = 0; | |
178 | work_interval_t handle = NULL; | |
179 | kern_return_t kr = KERN_SUCCESS; | |
180 | ||
181 | uint32_t flags = WORK_INTERVAL_FLAG_GROUP | WORK_INTERVAL_FLAG_JOINABLE | WORK_INTERVAL_TYPE_COREAUDIO | WORK_INTERVAL_FLAG_UNRESTRICTED; | |
182 | ||
183 | ret = work_interval_create(&handle, flags); | |
184 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_create, joinable"); | |
185 | ||
186 | ret = work_interval_copy_port(handle, &port); | |
187 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_copy_port, joinable"); | |
188 | ||
189 | ret = work_interval_join_port(port); | |
190 | T_EXPECT_POSIX_FAILURE(ret, EINVAL, "work_interval_join_port for audio on non-RT thread"); | |
191 | ||
192 | set_realtime(pthread_self()); | |
193 | ||
194 | ret = work_interval_join_port(port); | |
195 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_join_port for audio on RT thread"); | |
196 | ||
197 | ret = work_interval_leave(); | |
198 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_leave"); | |
199 | ||
200 | ret = work_interval_destroy(handle); | |
201 | T_ASSERT_POSIX_SUCCESS(ret, "work_interval_destroy"); | |
202 | ||
203 | kr = mach_port_deallocate(mach_task_self(), port); | |
204 | T_ASSERT_MACH_SUCCESS(kr, "mach_port_deallocate of port"); | |
205 | ||
206 | set_nonrealtime(pthread_self()); | |
207 | } |