]>
Commit | Line | Data |
---|---|---|
cc8bc92a A |
1 | #include <darwintest.h> |
2 | #include <darwintest_utils.h> | |
3 | #include <errno.h> | |
5ba3f43e | 4 | #include <mach/mach.h> |
cc8bc92a A |
5 | #include <mach/mach_error.h> |
6 | #include <mach/policy.h> | |
5ba3f43e A |
7 | #include <mach/task_info.h> |
8 | #include <mach/thread_info.h> | |
a39ff7e2 | 9 | #include <signal.h> |
5ba3f43e | 10 | #include <stdio.h> |
5ba3f43e A |
11 | #include <stdlib.h> |
12 | #include <sys/mman.h> | |
5ba3f43e | 13 | #include <sys/sysctl.h> |
cc8bc92a | 14 | #include <unistd.h> |
5ba3f43e | 15 | |
c3c9b80d A |
16 | #include "test_utils.h" |
17 | ||
cb323159 A |
18 | T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true)); |
19 | ||
5ba3f43e A |
20 | /* ************************************************************************************* |
21 | * Test the task_info API. | |
22 | * | |
23 | * This is a functional test of the following APIs: | |
24 | * TASK_BASIC_INFO_32 | |
25 | * TASK_BASIC2_INFO_32 | |
26 | * TASK_BASIC_INFO_64 | |
27 | * TASK_BASIC_INFO_64_2 | |
28 | * TASK_POWER_INFO_V2 | |
29 | * TASK_FLAGS_INFO | |
30 | * TASK_AFFINITY_TAG_INFO | |
31 | * TASK_THREAD_TIMES_INFO | |
32 | * TASK_ABSOLUTE_TIME_INFO | |
33 | * <rdar://problem/22242021> Add tests to increase code coverage for the task_info API | |
34 | * ************************************************************************************* | |
35 | */ | |
36 | #define TESTPHYSFOOTPRINTVAL 5 | |
37 | #define CANARY 0x0f0f0f0f0f0f0f0fULL | |
38 | #if !defined(CONFIG_EMBEDDED) | |
39 | #define ABSOLUTE_MIN_USER_TIME_DIFF 150 | |
40 | #define ABSOLUTE_MIN_SYSTEM_TIME_DIFF 300 | |
41 | #endif | |
42 | ||
43 | enum info_kind { INFO_32, INFO_64, INFO_32_2, INFO_64_2, INFO_MACH, INFO_MAX }; | |
44 | ||
45 | enum info_get { GET_SUSPEND_COUNT, GET_RESIDENT_SIZE, GET_VIRTUAL_SIZE, GET_USER_TIME, GET_SYS_TIME, GET_POLICY, GET_MAX_RES }; | |
46 | ||
47 | /* | |
48 | * This function uses CPU cycles by doing a factorial computation. | |
49 | */ | |
50 | static void do_factorial_task(void); | |
51 | ||
52 | void test_task_basic_info_32(void); | |
53 | void test_task_basic_info_64(void); | |
54 | void task_basic_info_32_debug(void); | |
55 | void task_basic2_info_32_warmup(void); | |
5ba3f43e A |
56 | void test_task_basic_info(enum info_kind kind); |
57 | uint64_t info_get(enum info_kind kind, enum info_get get, void * data); | |
58 | ||
59 | T_DECL(task_vm_info, "tests task vm info", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT)) | |
60 | { | |
61 | kern_return_t err; | |
62 | task_vm_info_data_t vm_info; | |
63 | ||
64 | mach_msg_type_number_t count = TASK_VM_INFO_COUNT; | |
65 | ||
66 | err = task_info(mach_task_self(), TASK_VM_INFO_PURGEABLE, (task_info_t)&vm_info, &count); | |
67 | ||
68 | T_ASSERT_MACH_SUCCESS(err, "verify task_info call succeeded"); | |
69 | ||
70 | T_EXPECT_NE(vm_info.virtual_size, 0ULL, "task_info return value !=0 for virtual_size\n"); | |
71 | ||
72 | T_EXPECT_NE(vm_info.phys_footprint, 0ULL, "task_info return value !=0 for phys_footprint\n"); | |
73 | ||
74 | /* | |
75 | * Test the REV0 version of TASK_VM_INFO. It should not change the value of phys_footprint. | |
76 | */ | |
77 | ||
78 | count = TASK_VM_INFO_REV0_COUNT; | |
79 | vm_info.phys_footprint = TESTPHYSFOOTPRINTVAL; | |
80 | vm_info.min_address = CANARY; | |
81 | vm_info.max_address = CANARY; | |
82 | ||
83 | err = task_info(mach_task_self(), TASK_VM_INFO_PURGEABLE, (task_info_t)&vm_info, &count); | |
84 | ||
85 | T_ASSERT_MACH_SUCCESS(err, "verify task_info call succeeded"); | |
86 | ||
87 | T_EXPECT_EQ(count, TASK_VM_INFO_REV0_COUNT, "task_info count(%d) is equal to TASK_VM_INFO_REV0_COUNT", count); | |
88 | ||
89 | T_EXPECT_NE(vm_info.virtual_size, 0ULL, "task_info --rev0 call does not return 0 for virtual_size"); | |
90 | ||
91 | T_EXPECT_EQ(vm_info.phys_footprint, (unsigned long long)TESTPHYSFOOTPRINTVAL, | |
0a7de745 A |
92 | "task_info --rev0 call returned value %llu for vm_info.phys_footprint. Expected %u since this value should not be " |
93 | "modified by rev0", | |
94 | vm_info.phys_footprint, TESTPHYSFOOTPRINTVAL); | |
5ba3f43e A |
95 | |
96 | T_EXPECT_EQ(vm_info.min_address, CANARY, | |
0a7de745 A |
97 | "task_info --rev0 call returned value 0x%llx for vm_info.min_address. Expected 0x%llx since this value should not " |
98 | "be modified by rev0", | |
99 | vm_info.min_address, CANARY); | |
5ba3f43e A |
100 | |
101 | T_EXPECT_EQ(vm_info.max_address, CANARY, | |
0a7de745 A |
102 | "task_info --rev0 call returned value 0x%llx for vm_info.max_address. Expected 0x%llx since this value should not " |
103 | "be modified by rev0", | |
104 | vm_info.max_address, CANARY); | |
5ba3f43e A |
105 | |
106 | /* | |
107 | * Test the REV1 version of TASK_VM_INFO. | |
108 | */ | |
109 | ||
110 | count = TASK_VM_INFO_REV1_COUNT; | |
111 | vm_info.phys_footprint = TESTPHYSFOOTPRINTVAL; | |
112 | vm_info.min_address = CANARY; | |
113 | vm_info.max_address = CANARY; | |
114 | ||
115 | err = task_info(mach_task_self(), TASK_VM_INFO_PURGEABLE, (task_info_t)&vm_info, &count); | |
116 | ||
117 | T_ASSERT_MACH_SUCCESS(err, "verify task_info call succeeded"); | |
118 | ||
119 | T_EXPECT_EQ(count, TASK_VM_INFO_REV1_COUNT, "task_info count(%d) is equal to TASK_VM_INFO_REV1_COUNT", count); | |
120 | ||
121 | T_EXPECT_NE(vm_info.virtual_size, 0ULL, "task_info --rev1 call does not return 0 for virtual_size"); | |
122 | ||
123 | T_EXPECT_NE(vm_info.phys_footprint, (unsigned long long)TESTPHYSFOOTPRINTVAL, | |
0a7de745 A |
124 | "task_info --rev1 call returned value %llu for vm_info.phys_footprint. Expected value is anything other than %u " |
125 | "since this value should not be modified by rev1", | |
126 | vm_info.phys_footprint, TESTPHYSFOOTPRINTVAL); | |
5ba3f43e A |
127 | |
128 | T_EXPECT_EQ(vm_info.min_address, CANARY, | |
0a7de745 A |
129 | "task_info --rev1 call returned value 0x%llx for vm_info.min_address. Expected 0x%llx since this value should not " |
130 | "be modified by rev1", | |
131 | vm_info.min_address, CANARY); | |
5ba3f43e A |
132 | |
133 | T_EXPECT_EQ(vm_info.max_address, CANARY, | |
0a7de745 A |
134 | "task_info --rev1 call returned value 0x%llx for vm_info.max_address. Expected 0x%llx since this value should not " |
135 | "be modified by rev1", | |
136 | vm_info.max_address, CANARY); | |
5ba3f43e A |
137 | |
138 | /* | |
139 | * Test the REV2 version of TASK_VM_INFO. | |
140 | */ | |
141 | ||
142 | count = TASK_VM_INFO_REV2_COUNT; | |
143 | vm_info.phys_footprint = TESTPHYSFOOTPRINTVAL; | |
144 | vm_info.min_address = CANARY; | |
145 | vm_info.max_address = CANARY; | |
146 | ||
147 | err = task_info(mach_task_self(), TASK_VM_INFO_PURGEABLE, (task_info_t)&vm_info, &count); | |
148 | ||
149 | T_ASSERT_MACH_SUCCESS(err, "verify task_info call succeeded"); | |
150 | ||
151 | T_EXPECT_EQ(count, TASK_VM_INFO_REV2_COUNT, "task_info count(%d) is equal to TASK_VM_INFO_REV2_COUNT\n", count); | |
152 | ||
153 | T_EXPECT_NE(vm_info.virtual_size, 0ULL, "task_info --rev2 call does not return 0 for virtual_size\n"); | |
154 | ||
155 | T_EXPECT_NE(vm_info.phys_footprint, (unsigned long long)TESTPHYSFOOTPRINTVAL, | |
0a7de745 A |
156 | "task_info --rev2 call returned value %llu for vm_info.phys_footprint. Expected anything other than %u since this " |
157 | "value should be modified by rev2", | |
158 | vm_info.phys_footprint, TESTPHYSFOOTPRINTVAL); | |
5ba3f43e A |
159 | |
160 | T_EXPECT_NE(vm_info.min_address, CANARY, | |
0a7de745 A |
161 | "task_info --rev2 call returned value 0x%llx for vm_info.min_address. Expected anything other than 0x%llx since " |
162 | "this value should be modified by rev2", | |
163 | vm_info.min_address, CANARY); | |
5ba3f43e A |
164 | |
165 | T_EXPECT_NE(vm_info.max_address, CANARY, | |
0a7de745 A |
166 | "task_info --rev2 call returned value 0x%llx for vm_info.max_address. Expected anything other than 0x%llx since " |
167 | "this value should be modified by rev2", | |
168 | vm_info.max_address, CANARY); | |
cb323159 A |
169 | |
170 | /* | |
171 | * Test the REV4 version of TASK_VM_INFO. | |
172 | */ | |
173 | ||
174 | count = TASK_VM_INFO_REV4_COUNT; | |
175 | vm_info.phys_footprint = TESTPHYSFOOTPRINTVAL; | |
176 | vm_info.min_address = CANARY; | |
177 | vm_info.max_address = CANARY; | |
178 | vm_info.limit_bytes_remaining = CANARY; | |
179 | ||
180 | err = task_info(mach_task_self(), TASK_VM_INFO_PURGEABLE, (task_info_t)&vm_info, &count); | |
181 | ||
182 | T_ASSERT_MACH_SUCCESS(err, "verify task_info call succeeded"); | |
183 | ||
184 | T_EXPECT_EQ(count, TASK_VM_INFO_REV4_COUNT, "task_info count(%d) is equal to TASK_VM_INFO_REV4_COUNT\n", count); | |
185 | ||
186 | T_EXPECT_NE(vm_info.phys_footprint, (unsigned long long)TESTPHYSFOOTPRINTVAL, | |
187 | "task_info --rev4 call returned value %llu for vm_info.phys_footprint. Expected anything other than %u since this " | |
188 | "value should be modified by rev4", | |
189 | vm_info.phys_footprint, TESTPHYSFOOTPRINTVAL); | |
190 | ||
191 | T_EXPECT_NE(vm_info.min_address, CANARY, | |
192 | "task_info --rev4 call returned value 0x%llx for vm_info.min_address. Expected anything other than 0x%llx since " | |
193 | "this value should be modified by rev4", | |
194 | vm_info.min_address, CANARY); | |
195 | ||
196 | T_EXPECT_NE(vm_info.max_address, CANARY, | |
197 | "task_info --rev4 call returned value 0x%llx for vm_info.max_address. Expected anything other than 0x%llx since " | |
198 | "this value should be modified by rev4", | |
199 | vm_info.max_address, CANARY); | |
200 | ||
201 | T_EXPECT_NE(vm_info.limit_bytes_remaining, CANARY, | |
202 | "task_info --rev4 call returned value 0x%llx for vm_info.limit_bytes_remaining. Expected anything other than 0x%llx since " | |
203 | "this value should be modified by rev4", | |
204 | vm_info.limit_bytes_remaining, CANARY); | |
5ba3f43e A |
205 | } |
206 | ||
207 | T_DECL(host_debug_info, "tests host debug info", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT)) | |
208 | { | |
209 | T_SETUPBEGIN; | |
210 | int is_dev = is_development_kernel(); | |
211 | T_QUIET; | |
212 | T_ASSERT_TRUE(is_dev, "verify development kernel is running"); | |
213 | T_SETUPEND; | |
214 | ||
215 | kern_return_t err; | |
216 | mach_port_t host; | |
217 | host_debug_info_internal_data_t debug_info; | |
218 | mach_msg_type_number_t count = HOST_DEBUG_INFO_INTERNAL_COUNT; | |
219 | host = mach_host_self(); | |
220 | err = host_info(host, HOST_DEBUG_INFO_INTERNAL, (host_info_t)&debug_info, &count); | |
221 | ||
222 | T_ASSERT_MACH_SUCCESS(err, "verify host_info call succeeded"); | |
223 | } | |
224 | ||
225 | T_DECL(task_debug_info, "tests task debug info", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT)) | |
226 | { | |
227 | T_SETUPBEGIN; | |
228 | int is_dev = is_development_kernel(); | |
229 | T_QUIET; | |
230 | T_ASSERT_TRUE(is_dev, "verify development kernel is running"); | |
231 | T_SETUPEND; | |
232 | ||
233 | kern_return_t err; | |
234 | task_debug_info_internal_data_t debug_info; | |
235 | ||
236 | mach_msg_type_number_t count = TASK_DEBUG_INFO_INTERNAL_COUNT; | |
237 | ||
238 | err = task_info(mach_task_self(), TASK_DEBUG_INFO_INTERNAL, (task_info_t)&debug_info, &count); | |
239 | ||
240 | T_ASSERT_MACH_SUCCESS(err, "verify task_info call succeeded"); | |
241 | } | |
242 | ||
243 | T_DECL(thread_debug_info, "tests thread debug info", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT)) | |
244 | { | |
245 | T_SETUPBEGIN; | |
246 | int is_dev = is_development_kernel(); | |
247 | T_QUIET; | |
248 | T_ASSERT_TRUE(is_dev, "verify development kernel is running"); | |
249 | T_SETUPEND; | |
250 | ||
251 | kern_return_t err; | |
252 | thread_debug_info_internal_data_t debug_info; | |
253 | ||
254 | mach_msg_type_number_t count = THREAD_DEBUG_INFO_INTERNAL_COUNT; | |
255 | ||
256 | err = thread_info(mach_thread_self(), THREAD_DEBUG_INFO_INTERNAL, (thread_info_t)&debug_info, &count); | |
257 | ||
258 | T_ASSERT_MACH_SUCCESS(err, "verify task_info call succeeded"); | |
259 | } | |
260 | ||
261 | static void | |
262 | do_factorial_task() | |
263 | { | |
264 | int number = 20; | |
265 | int factorial = 1; | |
266 | int i; | |
267 | for (i = 1; i <= number; i++) { | |
268 | factorial *= i; | |
269 | } | |
270 | ||
271 | return; | |
272 | } | |
273 | ||
274 | T_DECL(task_thread_times_info, "tests task thread times info", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT)) | |
275 | { | |
276 | T_SETUPBEGIN; | |
277 | int is_dev = is_development_kernel(); | |
278 | T_QUIET; | |
279 | T_ASSERT_TRUE(is_dev, "verify development kernel is running"); | |
280 | T_SETUPEND; | |
281 | ||
282 | kern_return_t err; | |
283 | task_thread_times_info_data_t thread_times_info_data; | |
284 | task_thread_times_info_data_t thread_times_info_data_new; | |
285 | mach_msg_type_number_t count = TASK_THREAD_TIMES_INFO_COUNT; | |
286 | ||
287 | err = task_info(mach_task_self(), TASK_THREAD_TIMES_INFO, (task_info_t)&thread_times_info_data, &count); | |
288 | ||
289 | T_ASSERT_MACH_SUCCESS(err, "verify task_info call succeeded"); | |
290 | ||
291 | do_factorial_task(); | |
292 | ||
293 | err = task_info(mach_task_self(), TASK_THREAD_TIMES_INFO, (task_info_t)&thread_times_info_data_new, &count); | |
294 | ||
295 | T_ASSERT_MACH_SUCCESS(err, "verify task_info call succeeded"); | |
296 | ||
297 | /* | |
298 | * The difference is observed to be less than 30 microseconds for user_time | |
299 | * and less than 50 microseconds for system_time. This observation was done for over | |
300 | * 1000 runs. | |
301 | */ | |
302 | ||
303 | T_EXPECT_FALSE((thread_times_info_data_new.user_time.seconds - thread_times_info_data.user_time.seconds) != 0 || | |
0a7de745 A |
304 | (thread_times_info_data_new.system_time.seconds - thread_times_info_data.system_time.seconds) != 0, |
305 | "Tests whether the difference between thread times is greater than the allowed limit"); | |
5ba3f43e A |
306 | |
307 | /* | |
308 | * This is a negative case. | |
309 | */ | |
310 | ||
311 | count--; | |
312 | err = task_info(mach_task_self(), TASK_THREAD_TIMES_INFO, (task_info_t)&thread_times_info_data, &count); | |
313 | T_ASSERT_MACH_ERROR(err, KERN_INVALID_ARGUMENT, | |
0a7de745 | 314 | "Negative test case: task_info should verify that count is at least equal to what is defined in API."); |
5ba3f43e A |
315 | } |
316 | ||
317 | T_DECL(task_absolutetime_info, "tests task absolute time info", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT)) | |
318 | { | |
319 | T_SETUPBEGIN; | |
320 | int is_dev = is_development_kernel(); | |
321 | T_QUIET; | |
322 | T_ASSERT_TRUE(is_dev, "verify development kernel is running"); | |
323 | T_SETUPEND; | |
324 | ||
325 | kern_return_t err; | |
326 | uint64_t user_time_diff, system_time_diff; | |
327 | task_absolutetime_info_data_t absolute_time_info_data; | |
328 | task_absolutetime_info_data_t absolute_time_info_data_new; | |
329 | mach_msg_type_number_t count = TASK_ABSOLUTETIME_INFO_COUNT; | |
330 | ||
331 | err = task_info(mach_task_self(), TASK_ABSOLUTETIME_INFO, (task_info_t)&absolute_time_info_data, &count); | |
332 | ||
333 | T_ASSERT_MACH_SUCCESS(err, "verify task_info call succeeded"); | |
334 | ||
335 | do_factorial_task(); | |
336 | ||
337 | err = task_info(mach_task_self(), TASK_ABSOLUTETIME_INFO, (task_info_t)&absolute_time_info_data_new, &count); | |
338 | ||
339 | T_ASSERT_MACH_SUCCESS(err, "verify task_info call succeeded"); | |
340 | ||
341 | user_time_diff = absolute_time_info_data_new.total_user - absolute_time_info_data.total_user; | |
342 | system_time_diff = absolute_time_info_data_new.total_system - absolute_time_info_data.total_system; | |
343 | ||
344 | #if !(defined(__arm__) || defined(__arm64__)) | |
345 | /* | |
346 | * On embedded devices the difference is always zero. | |
347 | * On non-embedded devices the difference occurs in this range. This was observed over ~10000 runs. | |
348 | */ | |
349 | ||
350 | T_EXPECT_FALSE(user_time_diff < ABSOLUTE_MIN_USER_TIME_DIFF || system_time_diff < ABSOLUTE_MIN_SYSTEM_TIME_DIFF, | |
0a7de745 | 351 | "Tests whether the difference between thread times is greater than the expected range"); |
5ba3f43e A |
352 | #endif |
353 | ||
cc8bc92a A |
354 | if (absolute_time_info_data.threads_user <= 0) { |
355 | int precise_time_val = 0; | |
356 | size_t len = sizeof(size_t); | |
357 | ||
358 | T_LOG("User threads time is zero. This should only happen rarely and when precise_user_time is off"); | |
5ba3f43e | 359 | |
cc8bc92a A |
360 | err = sysctlbyname("kern.precise_user_kernel_time", &precise_time_val, &len, NULL, 0); |
361 | ||
362 | T_EXPECT_POSIX_SUCCESS(err, "performing sysctl to check precise_user_time"); | |
363 | ||
364 | T_LOG("kern.precise_user_kernel_time val = %d", precise_time_val); | |
365 | ||
366 | T_EXPECT_FALSE(precise_time_val, "user thread time should only be zero when precise_user_kernel_time is disabled"); | |
367 | } else { | |
368 | T_PASS("task_info should return non-zero value for user threads time = %llu", absolute_time_info_data.threads_user); | |
369 | } | |
5ba3f43e A |
370 | |
371 | #if !(defined(__arm__) || defined(__arm64__)) | |
372 | /* | |
373 | * On iOS, system threads are always zero. On OS X this value can be some large positive number. | |
374 | * There is no real way to estimate the exact amount. | |
375 | */ | |
cc8bc92a | 376 | T_EXPECT_NE(absolute_time_info_data.threads_system, 0ULL, |
0a7de745 | 377 | "task_info should return non-zero value for system threads time = %llu", absolute_time_info_data.threads_system); |
5ba3f43e A |
378 | #endif |
379 | ||
380 | /* | |
381 | * This is a negative case. | |
382 | */ | |
383 | count--; | |
384 | err = task_info(mach_task_self(), TASK_ABSOLUTETIME_INFO, (task_info_t)&absolute_time_info_data_new, &count); | |
385 | T_ASSERT_MACH_ERROR(err, KERN_INVALID_ARGUMENT, | |
0a7de745 | 386 | "Negative test case: task_info should verify that count is at least equal to what is defined in API."); |
5ba3f43e A |
387 | } |
388 | ||
389 | T_DECL(task_affinity_tag_info, "tests task_affinity_tag_info", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT)) | |
390 | { | |
391 | T_SETUPBEGIN; | |
392 | int is_dev = is_development_kernel(); | |
393 | T_QUIET; | |
394 | T_ASSERT_TRUE(is_dev, "verify development kernel is running"); | |
395 | T_SETUPEND; | |
396 | ||
397 | kern_return_t err; | |
398 | task_affinity_tag_info_data_t affinity_tag_info_data; | |
399 | mach_msg_type_number_t count = TASK_AFFINITY_TAG_INFO_COUNT; | |
400 | ||
401 | err = task_info(mach_task_self(), TASK_AFFINITY_TAG_INFO, (task_info_t)&affinity_tag_info_data, &count); | |
402 | ||
403 | T_ASSERT_MACH_SUCCESS(err, "verify task_info call succeeded"); | |
404 | ||
405 | /* | |
406 | * The affinity is not set by default, hence expecting a zero value. | |
407 | */ | |
408 | T_ASSERT_FALSE(affinity_tag_info_data.min != 0 || affinity_tag_info_data.max != 0, | |
0a7de745 | 409 | "task_info call returns non-zero min or max value"); |
5ba3f43e A |
410 | |
411 | /* | |
0a7de745 A |
412 | * This is a negative case. |
413 | */ | |
5ba3f43e A |
414 | count--; |
415 | err = task_info(mach_task_self(), TASK_AFFINITY_TAG_INFO, (task_info_t)&affinity_tag_info_data, &count); | |
416 | T_ASSERT_MACH_ERROR(err, KERN_INVALID_ARGUMENT, | |
0a7de745 | 417 | "Negative test case: task_info should verify that count is at least equal to what is defined in API."); |
5ba3f43e A |
418 | } |
419 | ||
420 | T_DECL(task_flags_info, "tests task_flags_info", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT)) | |
421 | { | |
422 | T_SETUPBEGIN; | |
423 | int is_dev = is_development_kernel(); | |
424 | T_QUIET; | |
425 | T_ASSERT_TRUE(is_dev, "verify development kernel is running"); | |
426 | T_SETUPEND; | |
427 | ||
428 | kern_return_t err; | |
429 | task_flags_info_data_t flags_info_data; | |
430 | mach_msg_type_number_t count = TASK_FLAGS_INFO_COUNT; | |
431 | ||
432 | err = task_info(mach_task_self(), TASK_FLAGS_INFO, (task_info_t)&flags_info_data, &count); | |
433 | ||
434 | T_ASSERT_MACH_SUCCESS(err, "verify task_info call succeeded"); | |
435 | ||
436 | /* Change for 32-bit arch possibility?*/ | |
d9a64523 | 437 | T_ASSERT_EQ((flags_info_data.flags & (unsigned int)(~(TF_LP64 | TF_64B_DATA))), 0U, |
0a7de745 | 438 | "task_info should only give out 64-bit addr/data flags"); |
5ba3f43e A |
439 | |
440 | /* | |
441 | * This is a negative case. | |
442 | */ | |
443 | ||
444 | count--; | |
445 | err = task_info(mach_task_self(), TASK_FLAGS_INFO, (task_info_t)&flags_info_data, &count); | |
446 | T_ASSERT_MACH_ERROR(err, KERN_INVALID_ARGUMENT, | |
0a7de745 | 447 | "Negative test case: task_info should verify that count is at least equal to what is defined in API."); |
5ba3f43e A |
448 | } |
449 | ||
450 | T_DECL(task_power_info_v2, "tests task_power_info_v2", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT)) | |
451 | { | |
452 | T_SETUPBEGIN; | |
453 | int is_dev = is_development_kernel(); | |
454 | T_QUIET; | |
455 | T_ASSERT_TRUE(is_dev, "verify development kernel is running"); | |
456 | T_SETUPEND; | |
457 | ||
458 | kern_return_t err; | |
459 | task_power_info_v2_data_t power_info_data_v2; | |
460 | task_power_info_v2_data_t power_info_data_v2_new; | |
461 | mach_msg_type_number_t count = TASK_POWER_INFO_V2_COUNT; | |
462 | ||
463 | sleep(1); | |
464 | ||
465 | err = task_info(mach_task_self(), TASK_POWER_INFO_V2, (task_info_t)&power_info_data_v2, &count); | |
466 | ||
467 | T_ASSERT_MACH_SUCCESS(err, "verify task_info call succeeded"); | |
468 | ||
469 | T_ASSERT_LE(power_info_data_v2.gpu_energy.task_gpu_utilisation, 0ULL, | |
0a7de745 | 470 | "verified task_info call shows zero GPU utilization for non-GPU task"); |
5ba3f43e A |
471 | |
472 | do_factorial_task(); | |
473 | ||
474 | /* | |
475 | * Verify the cpu_energy parameters. | |
476 | */ | |
477 | err = task_info(mach_task_self(), TASK_POWER_INFO_V2, (task_info_t)&power_info_data_v2_new, &count); | |
478 | T_ASSERT_MACH_SUCCESS(err, "verify task_info call succeeded"); | |
479 | ||
480 | #if !(defined(__arm__) || defined(__arm64__)) | |
481 | /* | |
482 | * iOS does not have system_time. | |
483 | */ | |
484 | T_ASSERT_GT(power_info_data_v2_new.cpu_energy.total_user, power_info_data_v2.cpu_energy.total_user, | |
0a7de745 | 485 | "task_info call returns valid user time"); |
5ba3f43e | 486 | T_ASSERT_GT(power_info_data_v2_new.cpu_energy.total_system, power_info_data_v2.cpu_energy.total_system, |
0a7de745 | 487 | "task_info call returns valid system time"); |
5ba3f43e A |
488 | #endif |
489 | ||
490 | T_ASSERT_GE(power_info_data_v2.cpu_energy.task_interrupt_wakeups, 1ULL, | |
0a7de745 A |
491 | "verify task_info call returns non-zero value for interrupt_wakeup (ret value = %llu)", |
492 | power_info_data_v2.cpu_energy.task_interrupt_wakeups); | |
5ba3f43e A |
493 | |
494 | #if !(defined(__arm__) || defined(__arm64__)) | |
495 | if (power_info_data_v2.cpu_energy.task_platform_idle_wakeups != 0) { | |
496 | T_LOG("task_info call returned %llu for platform_idle_wakeup", power_info_data_v2.cpu_energy.task_platform_idle_wakeups); | |
497 | } | |
498 | #endif | |
499 | ||
500 | count = TASK_POWER_INFO_V2_COUNT_OLD; | |
501 | err = task_info(mach_task_self(), TASK_POWER_INFO_V2, (task_info_t)&power_info_data_v2, &count); | |
502 | ||
503 | T_ASSERT_MACH_SUCCESS(err, "verify task_info call succeeded"); | |
504 | ||
505 | /* | |
506 | * This is a negative case. | |
507 | */ | |
508 | count--; | |
509 | err = task_info(mach_task_self(), TASK_POWER_INFO_V2, (task_info_t)&power_info_data_v2, &count); | |
510 | ||
511 | T_ASSERT_MACH_ERROR(err, KERN_INVALID_ARGUMENT, | |
0a7de745 A |
512 | "Negative test case: task_info should verify that count is at least equal to what is defined in API. Call " |
513 | "returns errno %d:%s", | |
514 | err, mach_error_string(err)); | |
5ba3f43e A |
515 | } |
516 | ||
517 | T_DECL(test_task_basic_info_32, "tests TASK_BASIC_INFO_32", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT)) | |
518 | { | |
519 | test_task_basic_info(INFO_32); | |
520 | } | |
521 | ||
522 | T_DECL(test_task_basic_info_32_2, "tests TASK_BASIC_INFO_32_2", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT)) | |
523 | { | |
524 | test_task_basic_info(INFO_32_2); | |
525 | } | |
526 | ||
527 | #if defined(__arm__) || defined(__arm64__) | |
528 | T_DECL(test_task_basic_info_64i_2, "tests TASK_BASIC_INFO_64_2", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT)) | |
529 | { | |
530 | test_task_basic_info(INFO_64_2); | |
531 | } | |
532 | #else | |
533 | T_DECL(test_task_basic_info_64, "tests TASK_BASIC_INFO_64", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT)) | |
534 | { | |
535 | test_task_basic_info(INFO_64); | |
536 | } | |
537 | #endif /* defined(__arm__) || defined(__arm64__) */ | |
538 | ||
539 | T_DECL(test_mach_task_basic_info, "tests MACH_TASK_BASIC_INFO", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT)) | |
540 | { | |
541 | test_task_basic_info(INFO_MACH); | |
542 | } | |
543 | ||
544 | void | |
545 | test_task_basic_info(enum info_kind kind) | |
546 | { | |
547 | #define BEFORE 0 | |
548 | #define AFTER 1 | |
549 | ||
550 | T_SETUPBEGIN; | |
551 | int is_dev = is_development_kernel(); | |
552 | T_QUIET; | |
553 | T_ASSERT_TRUE(is_dev, "verify development kernel is running"); | |
554 | T_SETUPEND; | |
555 | ||
556 | task_info_t info_data[2]; | |
557 | task_basic_info_32_data_t basic_info_32_data[2]; | |
558 | #if defined(__arm__) || defined(__arm64__) | |
559 | task_basic_info_64_2_data_t basic_info_64_2_data[2]; | |
560 | #else | |
561 | task_basic_info_64_data_t basic_info_64_data[2]; | |
562 | #endif /* defined(__arm__) || defined(__arm64__) */ | |
563 | mach_task_basic_info_data_t mach_basic_info_data[2]; | |
564 | ||
565 | kern_return_t kr; | |
566 | mach_msg_type_number_t count; | |
567 | task_flavor_t flavor = 0; | |
568 | integer_t suspend_count; | |
569 | uint64_t resident_size_diff; | |
570 | uint64_t virtual_size_diff; | |
571 | ||
572 | void * tmp_map = NULL; | |
573 | pid_t child_pid; | |
574 | mach_port_name_t child_task; | |
575 | /*for dt_waitpid*/ | |
576 | int timeout = 10; // change to max timeout | |
577 | int exit_status = 0; | |
578 | ||
579 | switch (kind) { | |
580 | case INFO_32: | |
581 | case INFO_32_2: | |
582 | info_data[BEFORE] = (task_info_t)&basic_info_32_data[BEFORE]; | |
583 | info_data[AFTER] = (task_info_t)&basic_info_32_data[AFTER]; | |
584 | count = TASK_BASIC_INFO_32_COUNT; | |
585 | flavor = TASK_BASIC_INFO_32; | |
586 | ||
587 | if (kind == INFO_32_2) { | |
588 | flavor = TASK_BASIC2_INFO_32; | |
589 | } | |
590 | ||
591 | break; | |
592 | #if defined(__arm__) || defined(__arm64__) | |
593 | case INFO_64: | |
594 | T_ASSERT_FAIL("invalid basic info kind"); | |
595 | break; | |
596 | ||
597 | case INFO_64_2: | |
598 | info_data[BEFORE] = (task_info_t)&basic_info_64_2_data[BEFORE]; | |
599 | info_data[AFTER] = (task_info_t)&basic_info_64_2_data[AFTER]; | |
600 | count = TASK_BASIC_INFO_64_2_COUNT; | |
601 | flavor = TASK_BASIC_INFO_64_2; | |
602 | break; | |
603 | ||
604 | #else | |
605 | case INFO_64: | |
606 | info_data[BEFORE] = (task_info_t)&basic_info_64_data[BEFORE]; | |
607 | info_data[AFTER] = (task_info_t)&basic_info_64_data[AFTER]; | |
608 | count = TASK_BASIC_INFO_64_COUNT; | |
609 | flavor = TASK_BASIC_INFO_64; | |
610 | break; | |
611 | ||
612 | case INFO_64_2: | |
613 | T_ASSERT_FAIL("invalid basic info kind"); | |
614 | break; | |
615 | #endif /* defined(__arm__) || defined(__arm64__) */ | |
616 | case INFO_MACH: | |
617 | info_data[BEFORE] = (task_info_t)&mach_basic_info_data[BEFORE]; | |
618 | info_data[AFTER] = (task_info_t)&mach_basic_info_data[AFTER]; | |
619 | count = MACH_TASK_BASIC_INFO_COUNT; | |
620 | flavor = MACH_TASK_BASIC_INFO; | |
621 | break; | |
622 | case INFO_MAX: | |
623 | default: | |
624 | T_ASSERT_FAIL("invalid basic info kind"); | |
625 | break; | |
626 | } | |
627 | ||
628 | kr = task_info(mach_task_self(), flavor, info_data[BEFORE], &count); | |
629 | ||
630 | T_ASSERT_MACH_SUCCESS(kr, "verify task_info succeeded"); | |
631 | ||
632 | do_factorial_task(); | |
633 | ||
634 | /* | |
635 | * Allocate virtual and resident memory. | |
636 | */ | |
637 | tmp_map = mmap(0, PAGE_SIZE, PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); | |
638 | ||
639 | T_WITH_ERRNO; | |
640 | T_EXPECT_NE(tmp_map, MAP_FAILED, "verify mmap call is successful"); | |
641 | ||
642 | memset(tmp_map, 'm', PAGE_SIZE); | |
643 | ||
644 | child_pid = fork(); | |
645 | ||
646 | T_ASSERT_POSIX_SUCCESS(child_pid, "verify process can be forked"); | |
647 | ||
648 | if (child_pid == 0) { | |
649 | /* | |
650 | * This will suspend the child process. | |
651 | */ | |
652 | kr = task_suspend(mach_task_self()); | |
653 | exit(kr); | |
654 | } | |
655 | ||
656 | /* | |
657 | * Wait for the child process to suspend itself. | |
658 | */ | |
659 | sleep(1); | |
660 | ||
661 | kr = task_for_pid(mach_task_self(), child_pid, &child_task); | |
662 | T_ASSERT_MACH_SUCCESS(kr, "verify task_for_pid succeeded. check sudo if failed"); | |
663 | ||
664 | /* | |
665 | * Verify the suspend_count for child and resume it. | |
666 | */ | |
667 | ||
668 | kr = task_info(child_task, flavor, info_data[AFTER], &count); | |
669 | T_ASSERT_MACH_SUCCESS(kr, "verify task_info call succeeded"); | |
670 | ||
671 | suspend_count = (integer_t)(info_get(kind, GET_SUSPEND_COUNT, info_data[AFTER])); | |
672 | T_ASSERT_EQ(suspend_count, 1, "verify task_info shows correct suspend_count"); | |
673 | ||
674 | kr = task_resume(child_task); | |
675 | T_ASSERT_MACH_SUCCESS(kr, "verify task_resume succeeded"); | |
676 | ||
677 | /* | |
678 | * reap kr from task_suspend call in child | |
679 | */ | |
680 | if (dt_waitpid(child_pid, &exit_status, NULL, timeout)) { | |
681 | T_ASSERT_MACH_SUCCESS(exit_status, "verify child task_suspend is successful"); | |
682 | } else { | |
683 | T_FAIL("dt_waitpid failed"); | |
684 | } | |
685 | ||
686 | kr = task_info(mach_task_self(), flavor, info_data[AFTER], &count); | |
687 | T_ASSERT_MACH_SUCCESS(kr, "verify task_info call succeeded"); | |
688 | ||
689 | resident_size_diff = info_get(kind, GET_RESIDENT_SIZE, info_data[AFTER]) - info_get(kind, GET_RESIDENT_SIZE, info_data[BEFORE]); | |
690 | virtual_size_diff = info_get(kind, GET_VIRTUAL_SIZE, info_data[AFTER]) - info_get(kind, GET_VIRTUAL_SIZE, info_data[BEFORE]); | |
691 | ||
692 | /* | |
693 | * INFO_32_2 gets the max resident size instead of the current resident size | |
694 | * 32 KB tolerance built into test. The returned value is generally between 0 and 16384 | |
695 | * | |
696 | * max resident size is a discrete field in INFO_MACH, so it's handled differently | |
697 | */ | |
698 | if (kind == INFO_32_2) { | |
699 | T_EXPECT_EQ(resident_size_diff % 4096, 0ULL, "verify task_info returns valid max resident_size"); | |
700 | T_EXPECT_GE(resident_size_diff, 0ULL, "verify task_info returns non-negative max resident_size"); | |
701 | T_EXPECT_GE(virtual_size_diff, (unsigned long long)PAGE_SIZE, "verify task_info returns valid virtual_size"); | |
702 | } else { | |
703 | T_EXPECT_GE(resident_size_diff, (unsigned long long)PAGE_SIZE, "task_info returns valid resident_size"); | |
704 | T_EXPECT_GE(virtual_size_diff, (unsigned long long)PAGE_SIZE, "task_info returns valid virtual_size"); | |
705 | } | |
706 | ||
707 | if (kind == INFO_MACH) { | |
708 | resident_size_diff = info_get(kind, GET_MAX_RES, info_data[AFTER]) - info_get(kind, GET_MAX_RES, info_data[BEFORE]); | |
709 | T_EXPECT_EQ(resident_size_diff % 4096, 0ULL, "verify task_info returns valid max resident_size"); | |
710 | T_EXPECT_GE(resident_size_diff, 0ULL, "verify task_info returns non-negative max resident_size"); | |
711 | T_EXPECT_GE(info_get(kind, GET_MAX_RES, info_data[AFTER]), info_get(kind, GET_RESIDENT_SIZE, info_data[AFTER]), | |
0a7de745 | 712 | "verify max resident size is greater than or equal to curr resident size"); |
5ba3f43e A |
713 | } |
714 | ||
715 | do_factorial_task(); | |
716 | ||
717 | /* | |
718 | * These counters give time for threads that have terminated. We dont have any, so checking for zero. | |
719 | */ | |
720 | ||
721 | time_value_t * user_tv = (time_value_t *)(info_get(kind, GET_USER_TIME, info_data[BEFORE])); | |
722 | T_EXPECT_EQ((user_tv->seconds + user_tv->microseconds / 1000000), 0, "verify task_info shows valid user time"); | |
723 | ||
724 | time_value_t * sys_tv = (time_value_t *)(info_get(kind, GET_SYS_TIME, info_data[BEFORE])); | |
725 | T_EXPECT_EQ(sys_tv->seconds + (sys_tv->microseconds / 1000000), 0, "verify task_info shows valid system time"); | |
726 | ||
727 | /* | |
728 | * The default value for non-kernel tasks is TIMESHARE. | |
729 | */ | |
730 | ||
731 | policy_t pt = (policy_t)info_get(kind, GET_POLICY, info_data[BEFORE]); | |
732 | ||
733 | T_EXPECT_EQ(pt, POLICY_TIMESHARE, "verify task_info shows valid policy"); | |
734 | ||
735 | /* | |
736 | * This is a negative case. | |
737 | */ | |
738 | ||
739 | count--; | |
740 | kr = task_info(mach_task_self(), flavor, info_data[AFTER], &count); | |
741 | ||
742 | T_ASSERT_MACH_ERROR(kr, KERN_INVALID_ARGUMENT, | |
0a7de745 | 743 | "Negative test case: task_info should verify that count is at least equal to what is defined in API"); |
5ba3f43e A |
744 | |
745 | /* | |
746 | * deallocate memory | |
747 | */ | |
748 | munmap(tmp_map, PAGE_SIZE); | |
749 | ||
750 | return; | |
751 | ||
752 | #undef BEFORE | |
753 | #undef AFTER | |
754 | } | |
755 | ||
a39ff7e2 | 756 | T_DECL(test_sigcont_task_suspend_resume, |
0a7de745 A |
757 | "test to verify that SIGCONT on task_suspend()-ed process works", |
758 | T_META_ASROOT(true), | |
759 | T_META_LTEPHASE(LTE_POSTINIT)) | |
a39ff7e2 A |
760 | { |
761 | T_SETUPBEGIN; | |
762 | int is_dev = is_development_kernel(); | |
763 | T_QUIET; | |
764 | T_ASSERT_TRUE(is_dev, "verify development kernel is running"); | |
765 | T_SETUPEND; | |
766 | ||
767 | mach_task_basic_info_data_t mach_basic_info_data; | |
768 | task_info_t info_data = (task_info_t)&mach_basic_info_data; | |
769 | ||
770 | task_debug_info_internal_data_t debug_info; | |
771 | mach_msg_type_number_t debug_count = TASK_DEBUG_INFO_INTERNAL_COUNT; | |
772 | ||
773 | kern_return_t kr; | |
774 | int posix_ret; | |
775 | mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT; | |
776 | task_flavor_t flavor = MACH_TASK_BASIC_INFO; | |
777 | integer_t suspend_count; | |
778 | integer_t debug_suspend_count; | |
779 | pid_t child_pid = 0; | |
780 | mach_port_name_t child_task; | |
781 | /*for dt_waitpid*/ | |
782 | int timeout = 5; | |
783 | int exit_status = 0; | |
784 | int signal_no = 0; | |
785 | ||
786 | child_pid = fork(); | |
787 | ||
788 | T_ASSERT_POSIX_SUCCESS(child_pid, "verify process can be forked"); | |
789 | ||
790 | if (child_pid == 0) { | |
791 | /* | |
792 | * This will suspend the child process. | |
793 | */ | |
794 | kr = task_suspend(mach_task_self()); | |
795 | ||
796 | /* | |
797 | * When child resumes, it exits immediately | |
798 | */ | |
799 | ||
800 | exit(kr); | |
801 | } | |
802 | ||
803 | /* | |
804 | * Wait for the child process to suspend itself. | |
805 | */ | |
806 | sleep(1); | |
807 | ||
808 | kr = task_for_pid(mach_task_self(), child_pid, &child_task); | |
809 | T_ASSERT_MACH_SUCCESS(kr, "verify task_for_pid succeeded. check sudo if failed"); | |
810 | ||
811 | /* | |
812 | * Verify the suspend_count for child and resume it. | |
813 | */ | |
814 | ||
815 | kr = task_info(child_task, flavor, info_data, &count); | |
816 | T_ASSERT_MACH_SUCCESS(kr, "verify task_info call succeeded"); | |
817 | ||
818 | suspend_count = (integer_t)(info_get(INFO_MACH, GET_SUSPEND_COUNT, info_data)); | |
819 | T_ASSERT_EQ(suspend_count, 1, "verify task_info shows correct suspend_count (1) (actually user stop count) "); | |
820 | ||
821 | kr = task_info(child_task, TASK_DEBUG_INFO_INTERNAL, (task_info_t)&debug_info, &debug_count); | |
822 | T_ASSERT_MACH_SUCCESS(kr, "verify task_info call succeeded"); | |
823 | ||
824 | debug_suspend_count = debug_info.suspend_count; | |
825 | T_ASSERT_EQ(debug_info.suspend_count, 1, "verify debug_info shows correct suspend_count(1)"); | |
826 | ||
827 | posix_ret = kill(child_pid, SIGCONT); | |
828 | T_ASSERT_POSIX_SUCCESS(posix_ret, "verify signal call succeeded"); | |
829 | ||
830 | /* | |
831 | * reap kr from task_suspend call in child | |
832 | */ | |
833 | dt_waitpid(child_pid, &exit_status, &signal_no, timeout); | |
834 | ||
835 | T_ASSERT_EQ(signal_no, 0, "child should be resumed and exit without signal"); | |
836 | T_ASSERT_EQ(exit_status, 0, "child should exit with 0"); | |
a39ff7e2 A |
837 | } |
838 | ||
839 | T_DECL(test_sigcont_task_suspend2_resume, | |
0a7de745 A |
840 | "test to verify that SIGCONT on task_suspend2()-ed process doesn't work", |
841 | T_META_ASROOT(true), | |
842 | T_META_LTEPHASE(LTE_POSTINIT)) | |
a39ff7e2 A |
843 | { |
844 | T_SETUPBEGIN; | |
845 | int is_dev = is_development_kernel(); | |
846 | T_QUIET; | |
847 | T_ASSERT_TRUE(is_dev, "verify development kernel is running"); | |
848 | T_SETUPEND; | |
849 | ||
850 | mach_task_basic_info_data_t mach_basic_info_data; | |
851 | task_info_t info_data = (task_info_t)&mach_basic_info_data; | |
852 | ||
853 | task_debug_info_internal_data_t debug_info; | |
854 | mach_msg_type_number_t debug_count = TASK_DEBUG_INFO_INTERNAL_COUNT; | |
855 | ||
856 | kern_return_t kr; | |
857 | int posix_ret; | |
858 | mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT; | |
859 | task_flavor_t flavor = MACH_TASK_BASIC_INFO; | |
860 | integer_t suspend_count = 0; | |
861 | integer_t debug_suspend_count = 0; | |
862 | pid_t child_pid = 0; | |
863 | mach_port_name_t child_task; | |
864 | task_suspension_token_t child_token = 0xFFFFF; | |
865 | ||
866 | /* | |
867 | * for dt_waitpid | |
868 | * We expect the test to fail right now, so I've set timeout to | |
869 | * be shorter than we may want it to be when the issue is fixed | |
870 | */ | |
871 | int timeout = 1; | |
872 | int exit_status = 0; | |
873 | int signal_no = 0; | |
874 | ||
875 | /* for pipe */ | |
876 | int fd[2]; | |
877 | pipe(fd); | |
878 | int pipe_msg = 0; | |
879 | ||
880 | child_pid = fork(); | |
881 | ||
882 | T_ASSERT_POSIX_SUCCESS(child_pid, "verify process can be forked %d", child_pid); | |
883 | ||
884 | if (child_pid == 0) { | |
885 | close(fd[1]); | |
886 | T_LOG("Waiting to read from parent..."); | |
887 | read(fd[0], &pipe_msg, sizeof(pipe_msg)); | |
888 | T_LOG("Done reading from parent, about to exit..."); | |
889 | exit(0); | |
890 | } | |
891 | /* | |
892 | * Wait for child to fork and block on read | |
893 | */ | |
894 | sleep(1); | |
895 | ||
896 | close(fd[0]); | |
897 | ||
898 | kr = task_for_pid(mach_task_self(), child_pid, &child_task); | |
899 | T_ASSERT_MACH_SUCCESS(kr, "verify task_for_pid succeeded. check sudo if failed"); | |
900 | ||
901 | kr = task_info(child_task, TASK_DEBUG_INFO_INTERNAL, (task_info_t)&debug_info, &debug_count); | |
902 | T_ASSERT_MACH_SUCCESS(kr, "verify task_info call succeeded"); | |
903 | ||
904 | debug_suspend_count = debug_info.suspend_count; | |
905 | T_EXPECT_EQ(debug_suspend_count, 0, "verify debug_info shows correct (true) suspend_count(0)"); | |
906 | ||
907 | kr = task_suspend2(child_task, &child_token); | |
908 | T_ASSERT_MACH_SUCCESS(kr, "verify task_suspend2 call succeeded"); | |
909 | ||
910 | kr = task_info(child_task, TASK_DEBUG_INFO_INTERNAL, (task_info_t)&debug_info, &debug_count); | |
911 | T_ASSERT_MACH_SUCCESS(kr, "verify task_info call succeeded"); | |
912 | ||
913 | debug_suspend_count = debug_info.suspend_count; | |
914 | T_ASSERT_EQ(debug_suspend_count, 1, "verify debug_info shows correct (true) suspend_count(1)"); | |
915 | ||
916 | /* | |
917 | * Verify the suspend_count for child and resume it. | |
918 | */ | |
919 | ||
920 | kr = task_info(child_task, flavor, info_data, &count); | |
921 | T_ASSERT_MACH_SUCCESS(kr, "verify task_info call succeeded"); | |
922 | ||
923 | suspend_count = (integer_t)(info_get(INFO_MACH, GET_SUSPEND_COUNT, info_data)); | |
924 | T_EXPECT_EQ(suspend_count, 1, "verify task_info shows correct (user_stop_count) suspend_count (1)"); | |
925 | ||
926 | posix_ret = kill(child_pid, SIGCONT); | |
927 | T_ASSERT_POSIX_SUCCESS(posix_ret, "verify signal call succeeded"); | |
928 | ||
929 | kr = task_info(child_task, TASK_DEBUG_INFO_INTERNAL, (task_info_t)&debug_info, &debug_count); | |
930 | T_EXPECT_MACH_SUCCESS(kr, "verify task_info call succeeded"); | |
931 | ||
932 | debug_suspend_count = debug_info.suspend_count; | |
933 | T_EXPECTFAIL_WITH_RADAR(33166654); | |
934 | T_EXPECT_EQ(debug_suspend_count, 1, "verify debug_info shows correct (true) suspend_count (1)"); | |
935 | ||
936 | suspend_count = (integer_t)(info_get(INFO_MACH, GET_SUSPEND_COUNT, info_data)); | |
937 | T_ASSERT_EQ(suspend_count, 1, "verify task_info shows correct (user_stop_count) suspend_count (1) after SIG_CONT"); | |
938 | ||
939 | kr = task_resume(child_task); | |
940 | T_EXPECTFAIL_WITH_RADAR(33166654); | |
941 | T_EXPECT_MACH_SUCCESS(kr, "verify task_resume succeeded"); | |
942 | ||
943 | /* | |
944 | * reap kr from task_suspend call in child | |
945 | */ | |
946 | ||
947 | dt_waitpid(child_pid, &exit_status, &signal_no, timeout); | |
948 | ||
949 | T_ASSERT_EQ(signal_no, SIG_DT_TIMEOUT, "dt_waitpid timed out as expected"); | |
950 | ||
951 | // Resume properly using token and then wait | |
952 | ||
953 | kr = task_resume2(child_token); | |
954 | T_EXPECTFAIL_WITH_RADAR(33166654); | |
955 | T_ASSERT_MACH_SUCCESS(kr, "verify task_resume2 succeeded"); | |
956 | ||
957 | write(fd[1], &pipe_msg, sizeof(pipe_msg)); | |
958 | ||
959 | /* | |
960 | * reap kr from task_suspend call in child | |
961 | */ | |
962 | dt_waitpid(child_pid, &exit_status, &signal_no, timeout); | |
963 | ||
964 | T_ASSERT_EQ(signal_no, 0, "child should be resumed and no signal should be returned"); | |
965 | T_ASSERT_EQ(exit_status, 0, "child should exit with 0"); | |
a39ff7e2 A |
966 | } |
967 | ||
5ba3f43e A |
968 | uint64_t |
969 | info_get(enum info_kind kind, enum info_get get, void * data) | |
970 | { | |
971 | switch (get) { | |
972 | case GET_SUSPEND_COUNT: | |
973 | switch (kind) { | |
974 | case INFO_32: | |
975 | case INFO_32_2: | |
976 | return (uint64_t)(((task_basic_info_32_t)data)->suspend_count); | |
977 | #if defined(__arm__) || defined(__arm64__) | |
978 | case INFO_64: | |
979 | T_ASSERT_FAIL("illegal info_get %d %d", kind, get); | |
980 | break; | |
981 | ||
982 | case INFO_64_2: | |
983 | return (uint64_t)(((task_basic_info_64_2_t)data)->suspend_count); | |
984 | #else | |
985 | case INFO_64: | |
986 | return (uint64_t)(((task_basic_info_64_t)data)->suspend_count); | |
987 | ||
988 | case INFO_64_2: | |
989 | T_ASSERT_FAIL("illegal info_get %d %d", kind, get); | |
990 | break; | |
991 | #endif /* defined(__arm__) || defined(__arm64__) */ | |
992 | case INFO_MACH: | |
993 | return (uint64_t)(((mach_task_basic_info_t)data)->suspend_count); | |
994 | case INFO_MAX: | |
995 | default: | |
996 | T_ASSERT_FAIL("unhandled info_get %d %d", kind, get); | |
997 | } | |
998 | case GET_RESIDENT_SIZE: | |
999 | switch (kind) { | |
1000 | case INFO_32: | |
1001 | case INFO_32_2: | |
1002 | return (uint64_t)(((task_basic_info_32_t)data)->resident_size); | |
1003 | #if defined(__arm__) || defined(__arm64__) | |
1004 | case INFO_64: | |
1005 | T_ASSERT_FAIL("illegal info_get %d %d", kind, get); | |
1006 | break; | |
1007 | ||
1008 | case INFO_64_2: | |
1009 | return (uint64_t)(((task_basic_info_64_2_t)data)->resident_size); | |
1010 | #else | |
1011 | case INFO_64: | |
1012 | return (uint64_t)(((task_basic_info_64_t)data)->resident_size); | |
1013 | ||
1014 | case INFO_64_2: | |
1015 | T_ASSERT_FAIL("illegal info_get %d %d", kind, get); | |
1016 | break; | |
1017 | #endif /* defined(__arm__) || defined(__arm64__) */ | |
1018 | case INFO_MACH: | |
1019 | return (uint64_t)(((mach_task_basic_info_t)data)->resident_size); | |
1020 | case INFO_MAX: | |
1021 | default: | |
1022 | T_ASSERT_FAIL("unhandled info_get %d %d", kind, get); | |
1023 | } | |
1024 | case GET_VIRTUAL_SIZE: | |
1025 | switch (kind) { | |
1026 | case INFO_32: | |
1027 | case INFO_32_2: | |
1028 | return (uint64_t)(((task_basic_info_32_t)data)->virtual_size); | |
1029 | #if defined(__arm__) || defined(__arm64__) | |
1030 | case INFO_64: | |
1031 | T_ASSERT_FAIL("illegal info_get %d %d", kind, get); | |
1032 | break; | |
1033 | ||
1034 | case INFO_64_2: | |
1035 | return (uint64_t)(((task_basic_info_64_2_t)data)->virtual_size); | |
1036 | #else | |
1037 | case INFO_64: | |
1038 | return (uint64_t)(((task_basic_info_64_t)data)->virtual_size); | |
1039 | ||
1040 | case INFO_64_2: | |
1041 | T_ASSERT_FAIL("illegal info_get %d %d", kind, get); | |
1042 | break; | |
1043 | #endif /* defined(__arm__) || defined(__arm64__) */ | |
1044 | case INFO_MACH: | |
1045 | return (uint64_t)(((mach_task_basic_info_t)data)->virtual_size); | |
1046 | ||
1047 | case INFO_MAX: | |
1048 | default: | |
1049 | T_ASSERT_FAIL("unhandled info_get %d %d", kind, get); | |
1050 | } | |
1051 | case GET_USER_TIME: | |
1052 | switch (kind) { | |
1053 | case INFO_32: | |
1054 | case INFO_32_2: | |
0a7de745 | 1055 | return (uint64_t) &(((task_basic_info_32_t)data)->user_time); |
5ba3f43e A |
1056 | #if defined(__arm__) || defined(__arm64__) |
1057 | case INFO_64: | |
1058 | T_ASSERT_FAIL("illegal info_get %d %d", kind, get); | |
1059 | break; | |
1060 | ||
1061 | case INFO_64_2: | |
0a7de745 | 1062 | return (uint64_t) &(((task_basic_info_64_2_t)data)->user_time); |
5ba3f43e A |
1063 | #else |
1064 | case INFO_64: | |
0a7de745 | 1065 | return (uint64_t) &(((task_basic_info_64_t)data)->user_time); |
5ba3f43e A |
1066 | |
1067 | case INFO_64_2: | |
1068 | T_ASSERT_FAIL("illegal info_get %d %d", kind, get); | |
1069 | break; | |
1070 | #endif /* defined(__arm__) || defined(__arm64__) */ | |
1071 | case INFO_MACH: | |
0a7de745 | 1072 | return (uint64_t) &(((mach_task_basic_info_t)data)->user_time); |
5ba3f43e A |
1073 | |
1074 | case INFO_MAX: | |
1075 | default: | |
1076 | T_ASSERT_FAIL("unhandled info_get %d %d", kind, get); | |
1077 | } | |
1078 | case GET_SYS_TIME: | |
1079 | switch (kind) { | |
1080 | case INFO_32: | |
1081 | case INFO_32_2: | |
0a7de745 | 1082 | return (uint64_t) &(((task_basic_info_32_t)data)->system_time); |
5ba3f43e A |
1083 | #if defined(__arm__) || defined(__arm64__) |
1084 | case INFO_64: | |
1085 | T_ASSERT_FAIL("illegal info_get %d %d", kind, get); | |
1086 | break; | |
1087 | ||
1088 | case INFO_64_2: | |
0a7de745 | 1089 | return (uint64_t) &(((task_basic_info_64_2_t)data)->system_time); |
5ba3f43e A |
1090 | #else |
1091 | case INFO_64: | |
0a7de745 | 1092 | return (uint64_t) &(((task_basic_info_64_t)data)->system_time); |
5ba3f43e A |
1093 | |
1094 | case INFO_64_2: | |
1095 | T_ASSERT_FAIL("illegal info_get %d %d", kind, get); | |
1096 | break; | |
1097 | #endif /* defined(__arm__) || defined(__arm64__) */ | |
1098 | case INFO_MACH: | |
0a7de745 | 1099 | return (uint64_t) &(((mach_task_basic_info_t)data)->user_time); |
5ba3f43e A |
1100 | case INFO_MAX: |
1101 | default: | |
1102 | T_ASSERT_FAIL("unhandled info_get %d %d", kind, get); | |
1103 | } | |
1104 | case GET_POLICY: | |
1105 | switch (kind) { | |
1106 | case INFO_32: | |
1107 | case INFO_32_2: | |
1108 | return (uint64_t)(((task_basic_info_32_t)data)->policy); | |
1109 | #if defined(__arm__) || defined(__arm64__) | |
1110 | case INFO_64: | |
1111 | T_ASSERT_FAIL("illegal info_get %d %d", kind, get); | |
1112 | break; | |
1113 | ||
1114 | case INFO_64_2: | |
1115 | return (uint64_t)(((task_basic_info_64_2_t)data)->policy); | |
1116 | #else | |
1117 | case INFO_64: | |
1118 | return (uint64_t)(((task_basic_info_64_t)data)->policy); | |
1119 | ||
1120 | case INFO_64_2: | |
1121 | T_ASSERT_FAIL("illegal info_get %d %d", kind, get); | |
1122 | break; | |
1123 | #endif /* defined(__arm__) || defined(__arm64__) */ | |
1124 | case INFO_MACH: | |
1125 | return (uint64_t)(((mach_task_basic_info_t)data)->policy); | |
1126 | ||
1127 | case INFO_MAX: | |
1128 | default: | |
1129 | T_ASSERT_FAIL("unhandled info_get %d %d", kind, get); | |
1130 | } | |
1131 | case GET_MAX_RES: | |
1132 | switch (kind) { | |
1133 | case INFO_32: | |
1134 | case INFO_32_2: | |
1135 | case INFO_64: | |
1136 | case INFO_64_2: | |
1137 | T_ASSERT_FAIL("illegal info_get %d %d", kind, get); | |
1138 | case INFO_MACH: | |
1139 | return (uint64_t)(((mach_task_basic_info_t)data)->resident_size_max); | |
1140 | case INFO_MAX: | |
1141 | default: | |
1142 | T_ASSERT_FAIL("unhandled info_get %d %d", kind, get); | |
1143 | } | |
1144 | } | |
1145 | ||
1146 | __builtin_unreachable(); | |
1147 | } |