1 #include <darwintest.h>
2 #include <darwintest_utils.h>
5 #include <mach/mach_error.h>
6 #include <mach/policy.h>
7 #include <mach/task_info.h>
8 #include <mach/thread_info.h>
13 #include <sys/sysctl.h>
16 /* *************************************************************************************
17 * Test the task_info API.
19 * This is a functional test of the following APIs:
23 * TASK_BASIC_INFO_64_2
26 * TASK_AFFINITY_TAG_INFO
27 * TASK_THREAD_TIMES_INFO
28 * TASK_ABSOLUTE_TIME_INFO
29 * <rdar://problem/22242021> Add tests to increase code coverage for the task_info API
30 * *************************************************************************************
32 #define TESTPHYSFOOTPRINTVAL 5
33 #define CANARY 0x0f0f0f0f0f0f0f0fULL
34 #if !defined(CONFIG_EMBEDDED)
35 #define ABSOLUTE_MIN_USER_TIME_DIFF 150
36 #define ABSOLUTE_MIN_SYSTEM_TIME_DIFF 300
39 enum info_kind
{ INFO_32
, INFO_64
, INFO_32_2
, INFO_64_2
, INFO_MACH
, INFO_MAX
};
41 enum info_get
{ GET_SUSPEND_COUNT
, GET_RESIDENT_SIZE
, GET_VIRTUAL_SIZE
, GET_USER_TIME
, GET_SYS_TIME
, GET_POLICY
, GET_MAX_RES
};
44 * This function uses CPU cycles by doing a factorial computation.
46 static void do_factorial_task(void);
48 void test_task_basic_info_32(void);
49 void test_task_basic_info_64(void);
50 void task_basic_info_32_debug(void);
51 void task_basic2_info_32_warmup(void);
52 static int is_development_kernel(void);
53 void test_task_basic_info(enum info_kind kind
);
54 uint64_t info_get(enum info_kind kind
, enum info_get get
, void * data
);
56 T_DECL(task_vm_info
, "tests task vm info", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT
))
59 task_vm_info_data_t vm_info
;
61 mach_msg_type_number_t count
= TASK_VM_INFO_COUNT
;
63 err
= task_info(mach_task_self(), TASK_VM_INFO_PURGEABLE
, (task_info_t
)&vm_info
, &count
);
65 T_ASSERT_MACH_SUCCESS(err
, "verify task_info call succeeded");
67 T_EXPECT_NE(vm_info
.virtual_size
, 0ULL, "task_info return value !=0 for virtual_size\n");
69 T_EXPECT_NE(vm_info
.phys_footprint
, 0ULL, "task_info return value !=0 for phys_footprint\n");
72 * Test the REV0 version of TASK_VM_INFO. It should not change the value of phys_footprint.
75 count
= TASK_VM_INFO_REV0_COUNT
;
76 vm_info
.phys_footprint
= TESTPHYSFOOTPRINTVAL
;
77 vm_info
.min_address
= CANARY
;
78 vm_info
.max_address
= CANARY
;
80 err
= task_info(mach_task_self(), TASK_VM_INFO_PURGEABLE
, (task_info_t
)&vm_info
, &count
);
82 T_ASSERT_MACH_SUCCESS(err
, "verify task_info call succeeded");
84 T_EXPECT_EQ(count
, TASK_VM_INFO_REV0_COUNT
, "task_info count(%d) is equal to TASK_VM_INFO_REV0_COUNT", count
);
86 T_EXPECT_NE(vm_info
.virtual_size
, 0ULL, "task_info --rev0 call does not return 0 for virtual_size");
88 T_EXPECT_EQ(vm_info
.phys_footprint
, (unsigned long long)TESTPHYSFOOTPRINTVAL
,
89 "task_info --rev0 call returned value %llu for vm_info.phys_footprint. Expected %u since this value should not be "
91 vm_info
.phys_footprint
, TESTPHYSFOOTPRINTVAL
);
93 T_EXPECT_EQ(vm_info
.min_address
, CANARY
,
94 "task_info --rev0 call returned value 0x%llx for vm_info.min_address. Expected 0x%llx since this value should not "
95 "be modified by rev0",
96 vm_info
.min_address
, CANARY
);
98 T_EXPECT_EQ(vm_info
.max_address
, CANARY
,
99 "task_info --rev0 call returned value 0x%llx for vm_info.max_address. Expected 0x%llx since this value should not "
100 "be modified by rev0",
101 vm_info
.max_address
, CANARY
);
104 * Test the REV1 version of TASK_VM_INFO.
107 count
= TASK_VM_INFO_REV1_COUNT
;
108 vm_info
.phys_footprint
= TESTPHYSFOOTPRINTVAL
;
109 vm_info
.min_address
= CANARY
;
110 vm_info
.max_address
= CANARY
;
112 err
= task_info(mach_task_self(), TASK_VM_INFO_PURGEABLE
, (task_info_t
)&vm_info
, &count
);
114 T_ASSERT_MACH_SUCCESS(err
, "verify task_info call succeeded");
116 T_EXPECT_EQ(count
, TASK_VM_INFO_REV1_COUNT
, "task_info count(%d) is equal to TASK_VM_INFO_REV1_COUNT", count
);
118 T_EXPECT_NE(vm_info
.virtual_size
, 0ULL, "task_info --rev1 call does not return 0 for virtual_size");
120 T_EXPECT_NE(vm_info
.phys_footprint
, (unsigned long long)TESTPHYSFOOTPRINTVAL
,
121 "task_info --rev1 call returned value %llu for vm_info.phys_footprint. Expected value is anything other than %u "
122 "since this value should not be modified by rev1",
123 vm_info
.phys_footprint
, TESTPHYSFOOTPRINTVAL
);
125 T_EXPECT_EQ(vm_info
.min_address
, CANARY
,
126 "task_info --rev1 call returned value 0x%llx for vm_info.min_address. Expected 0x%llx since this value should not "
127 "be modified by rev1",
128 vm_info
.min_address
, CANARY
);
130 T_EXPECT_EQ(vm_info
.max_address
, CANARY
,
131 "task_info --rev1 call returned value 0x%llx for vm_info.max_address. Expected 0x%llx since this value should not "
132 "be modified by rev1",
133 vm_info
.max_address
, CANARY
);
136 * Test the REV2 version of TASK_VM_INFO.
139 count
= TASK_VM_INFO_REV2_COUNT
;
140 vm_info
.phys_footprint
= TESTPHYSFOOTPRINTVAL
;
141 vm_info
.min_address
= CANARY
;
142 vm_info
.max_address
= CANARY
;
144 err
= task_info(mach_task_self(), TASK_VM_INFO_PURGEABLE
, (task_info_t
)&vm_info
, &count
);
146 T_ASSERT_MACH_SUCCESS(err
, "verify task_info call succeeded");
148 T_EXPECT_EQ(count
, TASK_VM_INFO_REV2_COUNT
, "task_info count(%d) is equal to TASK_VM_INFO_REV2_COUNT\n", count
);
150 T_EXPECT_NE(vm_info
.virtual_size
, 0ULL, "task_info --rev2 call does not return 0 for virtual_size\n");
152 T_EXPECT_NE(vm_info
.phys_footprint
, (unsigned long long)TESTPHYSFOOTPRINTVAL
,
153 "task_info --rev2 call returned value %llu for vm_info.phys_footprint. Expected anything other than %u since this "
154 "value should be modified by rev2",
155 vm_info
.phys_footprint
, TESTPHYSFOOTPRINTVAL
);
157 T_EXPECT_NE(vm_info
.min_address
, CANARY
,
158 "task_info --rev2 call returned value 0x%llx for vm_info.min_address. Expected anything other than 0x%llx since "
159 "this value should be modified by rev2",
160 vm_info
.min_address
, CANARY
);
162 T_EXPECT_NE(vm_info
.max_address
, CANARY
,
163 "task_info --rev2 call returned value 0x%llx for vm_info.max_address. Expected anything other than 0x%llx since "
164 "this value should be modified by rev2",
165 vm_info
.max_address
, CANARY
);
168 T_DECL(host_debug_info
, "tests host debug info", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT
))
171 int is_dev
= is_development_kernel();
173 T_ASSERT_TRUE(is_dev
, "verify development kernel is running");
178 host_debug_info_internal_data_t debug_info
;
179 mach_msg_type_number_t count
= HOST_DEBUG_INFO_INTERNAL_COUNT
;
180 host
= mach_host_self();
181 err
= host_info(host
, HOST_DEBUG_INFO_INTERNAL
, (host_info_t
)&debug_info
, &count
);
183 T_ASSERT_MACH_SUCCESS(err
, "verify host_info call succeeded");
186 T_DECL(task_debug_info
, "tests task debug info", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT
))
189 int is_dev
= is_development_kernel();
191 T_ASSERT_TRUE(is_dev
, "verify development kernel is running");
195 task_debug_info_internal_data_t debug_info
;
197 mach_msg_type_number_t count
= TASK_DEBUG_INFO_INTERNAL_COUNT
;
199 err
= task_info(mach_task_self(), TASK_DEBUG_INFO_INTERNAL
, (task_info_t
)&debug_info
, &count
);
201 T_ASSERT_MACH_SUCCESS(err
, "verify task_info call succeeded");
204 T_DECL(thread_debug_info
, "tests thread debug info", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT
))
207 int is_dev
= is_development_kernel();
209 T_ASSERT_TRUE(is_dev
, "verify development kernel is running");
213 thread_debug_info_internal_data_t debug_info
;
215 mach_msg_type_number_t count
= THREAD_DEBUG_INFO_INTERNAL_COUNT
;
217 err
= thread_info(mach_thread_self(), THREAD_DEBUG_INFO_INTERNAL
, (thread_info_t
)&debug_info
, &count
);
219 T_ASSERT_MACH_SUCCESS(err
, "verify task_info call succeeded");
228 for (i
= 1; i
<= number
; i
++) {
235 T_DECL(task_thread_times_info
, "tests task thread times info", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT
))
238 int is_dev
= is_development_kernel();
240 T_ASSERT_TRUE(is_dev
, "verify development kernel is running");
244 task_thread_times_info_data_t thread_times_info_data
;
245 task_thread_times_info_data_t thread_times_info_data_new
;
246 mach_msg_type_number_t count
= TASK_THREAD_TIMES_INFO_COUNT
;
248 err
= task_info(mach_task_self(), TASK_THREAD_TIMES_INFO
, (task_info_t
)&thread_times_info_data
, &count
);
250 T_ASSERT_MACH_SUCCESS(err
, "verify task_info call succeeded");
254 err
= task_info(mach_task_self(), TASK_THREAD_TIMES_INFO
, (task_info_t
)&thread_times_info_data_new
, &count
);
256 T_ASSERT_MACH_SUCCESS(err
, "verify task_info call succeeded");
259 * The difference is observed to be less than 30 microseconds for user_time
260 * and less than 50 microseconds for system_time. This observation was done for over
264 T_EXPECT_FALSE((thread_times_info_data_new
.user_time
.seconds
- thread_times_info_data
.user_time
.seconds
) != 0 ||
265 (thread_times_info_data_new
.system_time
.seconds
- thread_times_info_data
.system_time
.seconds
) != 0,
266 "Tests whether the difference between thread times is greater than the allowed limit");
269 * This is a negative case.
273 err
= task_info(mach_task_self(), TASK_THREAD_TIMES_INFO
, (task_info_t
)&thread_times_info_data
, &count
);
274 T_ASSERT_MACH_ERROR(err
, KERN_INVALID_ARGUMENT
,
275 "Negative test case: task_info should verify that count is at least equal to what is defined in API.");
278 T_DECL(task_absolutetime_info
, "tests task absolute time info", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT
))
281 int is_dev
= is_development_kernel();
283 T_ASSERT_TRUE(is_dev
, "verify development kernel is running");
287 uint64_t user_time_diff
, system_time_diff
;
288 task_absolutetime_info_data_t absolute_time_info_data
;
289 task_absolutetime_info_data_t absolute_time_info_data_new
;
290 mach_msg_type_number_t count
= TASK_ABSOLUTETIME_INFO_COUNT
;
292 err
= task_info(mach_task_self(), TASK_ABSOLUTETIME_INFO
, (task_info_t
)&absolute_time_info_data
, &count
);
294 T_ASSERT_MACH_SUCCESS(err
, "verify task_info call succeeded");
298 err
= task_info(mach_task_self(), TASK_ABSOLUTETIME_INFO
, (task_info_t
)&absolute_time_info_data_new
, &count
);
300 T_ASSERT_MACH_SUCCESS(err
, "verify task_info call succeeded");
302 user_time_diff
= absolute_time_info_data_new
.total_user
- absolute_time_info_data
.total_user
;
303 system_time_diff
= absolute_time_info_data_new
.total_system
- absolute_time_info_data
.total_system
;
305 #if !(defined(__arm__) || defined(__arm64__))
307 * On embedded devices the difference is always zero.
308 * On non-embedded devices the difference occurs in this range. This was observed over ~10000 runs.
311 T_EXPECT_FALSE(user_time_diff
< ABSOLUTE_MIN_USER_TIME_DIFF
|| system_time_diff
< ABSOLUTE_MIN_SYSTEM_TIME_DIFF
,
312 "Tests whether the difference between thread times is greater than the expected range");
315 if (absolute_time_info_data
.threads_user
<= 0) {
316 int precise_time_val
= 0;
317 size_t len
= sizeof(size_t);
319 T_LOG("User threads time is zero. This should only happen rarely and when precise_user_time is off");
321 err
= sysctlbyname("kern.precise_user_kernel_time", &precise_time_val
, &len
, NULL
, 0);
323 T_EXPECT_POSIX_SUCCESS(err
, "performing sysctl to check precise_user_time");
325 T_LOG("kern.precise_user_kernel_time val = %d", precise_time_val
);
327 T_EXPECT_FALSE(precise_time_val
, "user thread time should only be zero when precise_user_kernel_time is disabled");
329 T_PASS("task_info should return non-zero value for user threads time = %llu", absolute_time_info_data
.threads_user
);
332 #if !(defined(__arm__) || defined(__arm64__))
334 * On iOS, system threads are always zero. On OS X this value can be some large positive number.
335 * There is no real way to estimate the exact amount.
337 T_EXPECT_NE(absolute_time_info_data
.threads_system
, 0ULL,
338 "task_info should return non-zero value for system threads time = %llu", absolute_time_info_data
.threads_system
);
342 * This is a negative case.
345 err
= task_info(mach_task_self(), TASK_ABSOLUTETIME_INFO
, (task_info_t
)&absolute_time_info_data_new
, &count
);
346 T_ASSERT_MACH_ERROR(err
, KERN_INVALID_ARGUMENT
,
347 "Negative test case: task_info should verify that count is at least equal to what is defined in API.");
350 T_DECL(task_affinity_tag_info
, "tests task_affinity_tag_info", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT
))
353 int is_dev
= is_development_kernel();
355 T_ASSERT_TRUE(is_dev
, "verify development kernel is running");
359 task_affinity_tag_info_data_t affinity_tag_info_data
;
360 mach_msg_type_number_t count
= TASK_AFFINITY_TAG_INFO_COUNT
;
362 err
= task_info(mach_task_self(), TASK_AFFINITY_TAG_INFO
, (task_info_t
)&affinity_tag_info_data
, &count
);
364 T_ASSERT_MACH_SUCCESS(err
, "verify task_info call succeeded");
367 * The affinity is not set by default, hence expecting a zero value.
369 T_ASSERT_FALSE(affinity_tag_info_data
.min
!= 0 || affinity_tag_info_data
.max
!= 0,
370 "task_info call returns non-zero min or max value");
373 * This is a negative case.
376 err
= task_info(mach_task_self(), TASK_AFFINITY_TAG_INFO
, (task_info_t
)&affinity_tag_info_data
, &count
);
377 T_ASSERT_MACH_ERROR(err
, KERN_INVALID_ARGUMENT
,
378 "Negative test case: task_info should verify that count is at least equal to what is defined in API.");
381 T_DECL(task_flags_info
, "tests task_flags_info", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT
))
384 int is_dev
= is_development_kernel();
386 T_ASSERT_TRUE(is_dev
, "verify development kernel is running");
390 task_flags_info_data_t flags_info_data
;
391 mach_msg_type_number_t count
= TASK_FLAGS_INFO_COUNT
;
393 err
= task_info(mach_task_self(), TASK_FLAGS_INFO
, (task_info_t
)&flags_info_data
, &count
);
395 T_ASSERT_MACH_SUCCESS(err
, "verify task_info call succeeded");
397 /* Change for 32-bit arch possibility?*/
398 T_ASSERT_EQ((flags_info_data
.flags
& (unsigned int)(~(TF_LP64
| TF_64B_DATA
))), 0U,
399 "task_info should only give out 64-bit addr/data flags");
402 * This is a negative case.
406 err
= task_info(mach_task_self(), TASK_FLAGS_INFO
, (task_info_t
)&flags_info_data
, &count
);
407 T_ASSERT_MACH_ERROR(err
, KERN_INVALID_ARGUMENT
,
408 "Negative test case: task_info should verify that count is at least equal to what is defined in API.");
411 T_DECL(task_power_info_v2
, "tests task_power_info_v2", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT
))
414 int is_dev
= is_development_kernel();
416 T_ASSERT_TRUE(is_dev
, "verify development kernel is running");
420 task_power_info_v2_data_t power_info_data_v2
;
421 task_power_info_v2_data_t power_info_data_v2_new
;
422 mach_msg_type_number_t count
= TASK_POWER_INFO_V2_COUNT
;
426 err
= task_info(mach_task_self(), TASK_POWER_INFO_V2
, (task_info_t
)&power_info_data_v2
, &count
);
428 T_ASSERT_MACH_SUCCESS(err
, "verify task_info call succeeded");
430 T_ASSERT_LE(power_info_data_v2
.gpu_energy
.task_gpu_utilisation
, 0ULL,
431 "verified task_info call shows zero GPU utilization for non-GPU task");
436 * Verify the cpu_energy parameters.
438 err
= task_info(mach_task_self(), TASK_POWER_INFO_V2
, (task_info_t
)&power_info_data_v2_new
, &count
);
439 T_ASSERT_MACH_SUCCESS(err
, "verify task_info call succeeded");
441 #if !(defined(__arm__) || defined(__arm64__))
443 * iOS does not have system_time.
445 T_ASSERT_GT(power_info_data_v2_new
.cpu_energy
.total_user
, power_info_data_v2
.cpu_energy
.total_user
,
446 "task_info call returns valid user time");
447 T_ASSERT_GT(power_info_data_v2_new
.cpu_energy
.total_system
, power_info_data_v2
.cpu_energy
.total_system
,
448 "task_info call returns valid system time");
451 T_ASSERT_GE(power_info_data_v2
.cpu_energy
.task_interrupt_wakeups
, 1ULL,
452 "verify task_info call returns non-zero value for interrupt_wakeup (ret value = %llu)",
453 power_info_data_v2
.cpu_energy
.task_interrupt_wakeups
);
455 #if !(defined(__arm__) || defined(__arm64__))
456 if (power_info_data_v2
.cpu_energy
.task_platform_idle_wakeups
!= 0) {
457 T_LOG("task_info call returned %llu for platform_idle_wakeup", power_info_data_v2
.cpu_energy
.task_platform_idle_wakeups
);
461 count
= TASK_POWER_INFO_V2_COUNT_OLD
;
462 err
= task_info(mach_task_self(), TASK_POWER_INFO_V2
, (task_info_t
)&power_info_data_v2
, &count
);
464 T_ASSERT_MACH_SUCCESS(err
, "verify task_info call succeeded");
467 * This is a negative case.
470 err
= task_info(mach_task_self(), TASK_POWER_INFO_V2
, (task_info_t
)&power_info_data_v2
, &count
);
472 T_ASSERT_MACH_ERROR(err
, KERN_INVALID_ARGUMENT
,
473 "Negative test case: task_info should verify that count is at least equal to what is defined in API. Call "
474 "returns errno %d:%s",
475 err
, mach_error_string(err
));
478 T_DECL(test_task_basic_info_32
, "tests TASK_BASIC_INFO_32", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT
))
480 test_task_basic_info(INFO_32
);
483 T_DECL(test_task_basic_info_32_2
, "tests TASK_BASIC_INFO_32_2", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT
))
485 test_task_basic_info(INFO_32_2
);
488 #if defined(__arm__) || defined(__arm64__)
489 T_DECL(test_task_basic_info_64i_2
, "tests TASK_BASIC_INFO_64_2", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT
))
491 test_task_basic_info(INFO_64_2
);
494 T_DECL(test_task_basic_info_64
, "tests TASK_BASIC_INFO_64", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT
))
496 test_task_basic_info(INFO_64
);
498 #endif /* defined(__arm__) || defined(__arm64__) */
500 T_DECL(test_mach_task_basic_info
, "tests MACH_TASK_BASIC_INFO", T_META_ASROOT(true), T_META_LTEPHASE(LTE_POSTINIT
))
502 test_task_basic_info(INFO_MACH
);
506 test_task_basic_info(enum info_kind kind
)
512 int is_dev
= is_development_kernel();
514 T_ASSERT_TRUE(is_dev
, "verify development kernel is running");
517 task_info_t info_data
[2];
518 task_basic_info_32_data_t basic_info_32_data
[2];
519 #if defined(__arm__) || defined(__arm64__)
520 task_basic_info_64_2_data_t basic_info_64_2_data
[2];
522 task_basic_info_64_data_t basic_info_64_data
[2];
523 #endif /* defined(__arm__) || defined(__arm64__) */
524 mach_task_basic_info_data_t mach_basic_info_data
[2];
527 mach_msg_type_number_t count
;
528 task_flavor_t flavor
= 0;
529 integer_t suspend_count
;
530 uint64_t resident_size_diff
;
531 uint64_t virtual_size_diff
;
533 void * tmp_map
= NULL
;
535 mach_port_name_t child_task
;
537 int timeout
= 10; // change to max timeout
543 info_data
[BEFORE
] = (task_info_t
)&basic_info_32_data
[BEFORE
];
544 info_data
[AFTER
] = (task_info_t
)&basic_info_32_data
[AFTER
];
545 count
= TASK_BASIC_INFO_32_COUNT
;
546 flavor
= TASK_BASIC_INFO_32
;
548 if (kind
== INFO_32_2
) {
549 flavor
= TASK_BASIC2_INFO_32
;
553 #if defined(__arm__) || defined(__arm64__)
555 T_ASSERT_FAIL("invalid basic info kind");
559 info_data
[BEFORE
] = (task_info_t
)&basic_info_64_2_data
[BEFORE
];
560 info_data
[AFTER
] = (task_info_t
)&basic_info_64_2_data
[AFTER
];
561 count
= TASK_BASIC_INFO_64_2_COUNT
;
562 flavor
= TASK_BASIC_INFO_64_2
;
567 info_data
[BEFORE
] = (task_info_t
)&basic_info_64_data
[BEFORE
];
568 info_data
[AFTER
] = (task_info_t
)&basic_info_64_data
[AFTER
];
569 count
= TASK_BASIC_INFO_64_COUNT
;
570 flavor
= TASK_BASIC_INFO_64
;
574 T_ASSERT_FAIL("invalid basic info kind");
576 #endif /* defined(__arm__) || defined(__arm64__) */
578 info_data
[BEFORE
] = (task_info_t
)&mach_basic_info_data
[BEFORE
];
579 info_data
[AFTER
] = (task_info_t
)&mach_basic_info_data
[AFTER
];
580 count
= MACH_TASK_BASIC_INFO_COUNT
;
581 flavor
= MACH_TASK_BASIC_INFO
;
585 T_ASSERT_FAIL("invalid basic info kind");
589 kr
= task_info(mach_task_self(), flavor
, info_data
[BEFORE
], &count
);
591 T_ASSERT_MACH_SUCCESS(kr
, "verify task_info succeeded");
596 * Allocate virtual and resident memory.
598 tmp_map
= mmap(0, PAGE_SIZE
, PROT_WRITE
, MAP_ANON
| MAP_PRIVATE
, -1, 0);
601 T_EXPECT_NE(tmp_map
, MAP_FAILED
, "verify mmap call is successful");
603 memset(tmp_map
, 'm', PAGE_SIZE
);
607 T_ASSERT_POSIX_SUCCESS(child_pid
, "verify process can be forked");
609 if (child_pid
== 0) {
611 * This will suspend the child process.
613 kr
= task_suspend(mach_task_self());
618 * Wait for the child process to suspend itself.
622 kr
= task_for_pid(mach_task_self(), child_pid
, &child_task
);
623 T_ASSERT_MACH_SUCCESS(kr
, "verify task_for_pid succeeded. check sudo if failed");
626 * Verify the suspend_count for child and resume it.
629 kr
= task_info(child_task
, flavor
, info_data
[AFTER
], &count
);
630 T_ASSERT_MACH_SUCCESS(kr
, "verify task_info call succeeded");
632 suspend_count
= (integer_t
)(info_get(kind
, GET_SUSPEND_COUNT
, info_data
[AFTER
]));
633 T_ASSERT_EQ(suspend_count
, 1, "verify task_info shows correct suspend_count");
635 kr
= task_resume(child_task
);
636 T_ASSERT_MACH_SUCCESS(kr
, "verify task_resume succeeded");
639 * reap kr from task_suspend call in child
641 if (dt_waitpid(child_pid
, &exit_status
, NULL
, timeout
)) {
642 T_ASSERT_MACH_SUCCESS(exit_status
, "verify child task_suspend is successful");
644 T_FAIL("dt_waitpid failed");
647 kr
= task_info(mach_task_self(), flavor
, info_data
[AFTER
], &count
);
648 T_ASSERT_MACH_SUCCESS(kr
, "verify task_info call succeeded");
650 resident_size_diff
= info_get(kind
, GET_RESIDENT_SIZE
, info_data
[AFTER
]) - info_get(kind
, GET_RESIDENT_SIZE
, info_data
[BEFORE
]);
651 virtual_size_diff
= info_get(kind
, GET_VIRTUAL_SIZE
, info_data
[AFTER
]) - info_get(kind
, GET_VIRTUAL_SIZE
, info_data
[BEFORE
]);
654 * INFO_32_2 gets the max resident size instead of the current resident size
655 * 32 KB tolerance built into test. The returned value is generally between 0 and 16384
657 * max resident size is a discrete field in INFO_MACH, so it's handled differently
659 if (kind
== INFO_32_2
) {
660 T_EXPECT_EQ(resident_size_diff
% 4096, 0ULL, "verify task_info returns valid max resident_size");
661 T_EXPECT_GE(resident_size_diff
, 0ULL, "verify task_info returns non-negative max resident_size");
662 T_EXPECT_GE(virtual_size_diff
, (unsigned long long)PAGE_SIZE
, "verify task_info returns valid virtual_size");
664 T_EXPECT_GE(resident_size_diff
, (unsigned long long)PAGE_SIZE
, "task_info returns valid resident_size");
665 T_EXPECT_GE(virtual_size_diff
, (unsigned long long)PAGE_SIZE
, "task_info returns valid virtual_size");
668 if (kind
== INFO_MACH
) {
669 resident_size_diff
= info_get(kind
, GET_MAX_RES
, info_data
[AFTER
]) - info_get(kind
, GET_MAX_RES
, info_data
[BEFORE
]);
670 T_EXPECT_EQ(resident_size_diff
% 4096, 0ULL, "verify task_info returns valid max resident_size");
671 T_EXPECT_GE(resident_size_diff
, 0ULL, "verify task_info returns non-negative max resident_size");
672 T_EXPECT_GE(info_get(kind
, GET_MAX_RES
, info_data
[AFTER
]), info_get(kind
, GET_RESIDENT_SIZE
, info_data
[AFTER
]),
673 "verify max resident size is greater than or equal to curr resident size");
679 * These counters give time for threads that have terminated. We dont have any, so checking for zero.
682 time_value_t
* user_tv
= (time_value_t
*)(info_get(kind
, GET_USER_TIME
, info_data
[BEFORE
]));
683 T_EXPECT_EQ((user_tv
->seconds
+ user_tv
->microseconds
/ 1000000), 0, "verify task_info shows valid user time");
685 time_value_t
* sys_tv
= (time_value_t
*)(info_get(kind
, GET_SYS_TIME
, info_data
[BEFORE
]));
686 T_EXPECT_EQ(sys_tv
->seconds
+ (sys_tv
->microseconds
/ 1000000), 0, "verify task_info shows valid system time");
689 * The default value for non-kernel tasks is TIMESHARE.
692 policy_t pt
= (policy_t
)info_get(kind
, GET_POLICY
, info_data
[BEFORE
]);
694 T_EXPECT_EQ(pt
, POLICY_TIMESHARE
, "verify task_info shows valid policy");
697 * This is a negative case.
701 kr
= task_info(mach_task_self(), flavor
, info_data
[AFTER
], &count
);
703 T_ASSERT_MACH_ERROR(kr
, KERN_INVALID_ARGUMENT
,
704 "Negative test case: task_info should verify that count is at least equal to what is defined in API");
709 munmap(tmp_map
, PAGE_SIZE
);
717 T_DECL(test_sigcont_task_suspend_resume
,
718 "test to verify that SIGCONT on task_suspend()-ed process works",
720 T_META_LTEPHASE(LTE_POSTINIT
))
723 int is_dev
= is_development_kernel();
725 T_ASSERT_TRUE(is_dev
, "verify development kernel is running");
728 mach_task_basic_info_data_t mach_basic_info_data
;
729 task_info_t info_data
= (task_info_t
)&mach_basic_info_data
;
731 task_debug_info_internal_data_t debug_info
;
732 mach_msg_type_number_t debug_count
= TASK_DEBUG_INFO_INTERNAL_COUNT
;
736 mach_msg_type_number_t count
= MACH_TASK_BASIC_INFO_COUNT
;
737 task_flavor_t flavor
= MACH_TASK_BASIC_INFO
;
738 integer_t suspend_count
;
739 integer_t debug_suspend_count
;
741 mach_port_name_t child_task
;
749 T_ASSERT_POSIX_SUCCESS(child_pid
, "verify process can be forked");
751 if (child_pid
== 0) {
753 * This will suspend the child process.
755 kr
= task_suspend(mach_task_self());
758 * When child resumes, it exits immediately
765 * Wait for the child process to suspend itself.
769 kr
= task_for_pid(mach_task_self(), child_pid
, &child_task
);
770 T_ASSERT_MACH_SUCCESS(kr
, "verify task_for_pid succeeded. check sudo if failed");
773 * Verify the suspend_count for child and resume it.
776 kr
= task_info(child_task
, flavor
, info_data
, &count
);
777 T_ASSERT_MACH_SUCCESS(kr
, "verify task_info call succeeded");
779 suspend_count
= (integer_t
)(info_get(INFO_MACH
, GET_SUSPEND_COUNT
, info_data
));
780 T_ASSERT_EQ(suspend_count
, 1, "verify task_info shows correct suspend_count (1) (actually user stop count) ");
782 kr
= task_info(child_task
, TASK_DEBUG_INFO_INTERNAL
, (task_info_t
)&debug_info
, &debug_count
);
783 T_ASSERT_MACH_SUCCESS(kr
, "verify task_info call succeeded");
785 debug_suspend_count
= debug_info
.suspend_count
;
786 T_ASSERT_EQ(debug_info
.suspend_count
, 1, "verify debug_info shows correct suspend_count(1)");
788 posix_ret
= kill(child_pid
, SIGCONT
);
789 T_ASSERT_POSIX_SUCCESS(posix_ret
, "verify signal call succeeded");
792 * reap kr from task_suspend call in child
794 dt_waitpid(child_pid
, &exit_status
, &signal_no
, timeout
);
796 T_ASSERT_EQ(signal_no
, 0, "child should be resumed and exit without signal");
797 T_ASSERT_EQ(exit_status
, 0, "child should exit with 0");
801 T_DECL(test_sigcont_task_suspend2_resume
,
802 "test to verify that SIGCONT on task_suspend2()-ed process doesn't work",
804 T_META_LTEPHASE(LTE_POSTINIT
))
807 int is_dev
= is_development_kernel();
809 T_ASSERT_TRUE(is_dev
, "verify development kernel is running");
812 mach_task_basic_info_data_t mach_basic_info_data
;
813 task_info_t info_data
= (task_info_t
)&mach_basic_info_data
;
815 task_debug_info_internal_data_t debug_info
;
816 mach_msg_type_number_t debug_count
= TASK_DEBUG_INFO_INTERNAL_COUNT
;
820 mach_msg_type_number_t count
= MACH_TASK_BASIC_INFO_COUNT
;
821 task_flavor_t flavor
= MACH_TASK_BASIC_INFO
;
822 integer_t suspend_count
= 0;
823 integer_t debug_suspend_count
= 0;
825 mach_port_name_t child_task
;
826 task_suspension_token_t child_token
= 0xFFFFF;
830 * We expect the test to fail right now, so I've set timeout to
831 * be shorter than we may want it to be when the issue is fixed
844 T_ASSERT_POSIX_SUCCESS(child_pid
, "verify process can be forked %d", child_pid
);
846 if (child_pid
== 0) {
848 T_LOG("Waiting to read from parent...");
849 read(fd
[0], &pipe_msg
, sizeof(pipe_msg
));
850 T_LOG("Done reading from parent, about to exit...");
854 * Wait for child to fork and block on read
860 kr
= task_for_pid(mach_task_self(), child_pid
, &child_task
);
861 T_ASSERT_MACH_SUCCESS(kr
, "verify task_for_pid succeeded. check sudo if failed");
863 kr
= task_info(child_task
, TASK_DEBUG_INFO_INTERNAL
, (task_info_t
)&debug_info
, &debug_count
);
864 T_ASSERT_MACH_SUCCESS(kr
, "verify task_info call succeeded");
866 debug_suspend_count
= debug_info
.suspend_count
;
867 T_EXPECT_EQ(debug_suspend_count
, 0, "verify debug_info shows correct (true) suspend_count(0)");
869 kr
= task_suspend2(child_task
, &child_token
);
870 T_ASSERT_MACH_SUCCESS(kr
, "verify task_suspend2 call succeeded");
872 kr
= task_info(child_task
, TASK_DEBUG_INFO_INTERNAL
, (task_info_t
)&debug_info
, &debug_count
);
873 T_ASSERT_MACH_SUCCESS(kr
, "verify task_info call succeeded");
875 debug_suspend_count
= debug_info
.suspend_count
;
876 T_ASSERT_EQ(debug_suspend_count
, 1, "verify debug_info shows correct (true) suspend_count(1)");
879 * Verify the suspend_count for child and resume it.
882 kr
= task_info(child_task
, flavor
, info_data
, &count
);
883 T_ASSERT_MACH_SUCCESS(kr
, "verify task_info call succeeded");
885 suspend_count
= (integer_t
)(info_get(INFO_MACH
, GET_SUSPEND_COUNT
, info_data
));
886 T_EXPECT_EQ(suspend_count
, 1, "verify task_info shows correct (user_stop_count) suspend_count (1)");
888 posix_ret
= kill(child_pid
, SIGCONT
);
889 T_ASSERT_POSIX_SUCCESS(posix_ret
, "verify signal call succeeded");
891 kr
= task_info(child_task
, TASK_DEBUG_INFO_INTERNAL
, (task_info_t
)&debug_info
, &debug_count
);
892 T_EXPECT_MACH_SUCCESS(kr
, "verify task_info call succeeded");
894 debug_suspend_count
= debug_info
.suspend_count
;
895 T_EXPECTFAIL_WITH_RADAR(33166654);
896 T_EXPECT_EQ(debug_suspend_count
, 1, "verify debug_info shows correct (true) suspend_count (1)");
898 suspend_count
= (integer_t
)(info_get(INFO_MACH
, GET_SUSPEND_COUNT
, info_data
));
899 T_ASSERT_EQ(suspend_count
, 1, "verify task_info shows correct (user_stop_count) suspend_count (1) after SIG_CONT");
901 kr
= task_resume(child_task
);
902 T_EXPECTFAIL_WITH_RADAR(33166654);
903 T_EXPECT_MACH_SUCCESS(kr
, "verify task_resume succeeded");
906 * reap kr from task_suspend call in child
909 dt_waitpid(child_pid
, &exit_status
, &signal_no
, timeout
);
911 T_ASSERT_EQ(signal_no
, SIG_DT_TIMEOUT
, "dt_waitpid timed out as expected");
913 // Resume properly using token and then wait
915 kr
= task_resume2(child_token
);
916 T_EXPECTFAIL_WITH_RADAR(33166654);
917 T_ASSERT_MACH_SUCCESS(kr
, "verify task_resume2 succeeded");
919 write(fd
[1], &pipe_msg
, sizeof(pipe_msg
));
922 * reap kr from task_suspend call in child
924 dt_waitpid(child_pid
, &exit_status
, &signal_no
, timeout
);
926 T_ASSERT_EQ(signal_no
, 0, "child should be resumed and no signal should be returned");
927 T_ASSERT_EQ(exit_status
, 0, "child should exit with 0");
932 info_get(enum info_kind kind
, enum info_get get
, void * data
)
935 case GET_SUSPEND_COUNT
:
939 return (uint64_t)(((task_basic_info_32_t
)data
)->suspend_count
);
940 #if defined(__arm__) || defined(__arm64__)
942 T_ASSERT_FAIL("illegal info_get %d %d", kind
, get
);
946 return (uint64_t)(((task_basic_info_64_2_t
)data
)->suspend_count
);
949 return (uint64_t)(((task_basic_info_64_t
)data
)->suspend_count
);
952 T_ASSERT_FAIL("illegal info_get %d %d", kind
, get
);
954 #endif /* defined(__arm__) || defined(__arm64__) */
956 return (uint64_t)(((mach_task_basic_info_t
)data
)->suspend_count
);
959 T_ASSERT_FAIL("unhandled info_get %d %d", kind
, get
);
961 case GET_RESIDENT_SIZE
:
965 return (uint64_t)(((task_basic_info_32_t
)data
)->resident_size
);
966 #if defined(__arm__) || defined(__arm64__)
968 T_ASSERT_FAIL("illegal info_get %d %d", kind
, get
);
972 return (uint64_t)(((task_basic_info_64_2_t
)data
)->resident_size
);
975 return (uint64_t)(((task_basic_info_64_t
)data
)->resident_size
);
978 T_ASSERT_FAIL("illegal info_get %d %d", kind
, get
);
980 #endif /* defined(__arm__) || defined(__arm64__) */
982 return (uint64_t)(((mach_task_basic_info_t
)data
)->resident_size
);
985 T_ASSERT_FAIL("unhandled info_get %d %d", kind
, get
);
987 case GET_VIRTUAL_SIZE
:
991 return (uint64_t)(((task_basic_info_32_t
)data
)->virtual_size
);
992 #if defined(__arm__) || defined(__arm64__)
994 T_ASSERT_FAIL("illegal info_get %d %d", kind
, get
);
998 return (uint64_t)(((task_basic_info_64_2_t
)data
)->virtual_size
);
1001 return (uint64_t)(((task_basic_info_64_t
)data
)->virtual_size
);
1004 T_ASSERT_FAIL("illegal info_get %d %d", kind
, get
);
1006 #endif /* defined(__arm__) || defined(__arm64__) */
1008 return (uint64_t)(((mach_task_basic_info_t
)data
)->virtual_size
);
1012 T_ASSERT_FAIL("unhandled info_get %d %d", kind
, get
);
1018 return (uint64_t) & (((task_basic_info_32_t
)data
)->user_time
);
1019 #if defined(__arm__) || defined(__arm64__)
1021 T_ASSERT_FAIL("illegal info_get %d %d", kind
, get
);
1025 return (uint64_t) & (((task_basic_info_64_2_t
)data
)->user_time
);
1028 return (uint64_t) & (((task_basic_info_64_t
)data
)->user_time
);
1031 T_ASSERT_FAIL("illegal info_get %d %d", kind
, get
);
1033 #endif /* defined(__arm__) || defined(__arm64__) */
1035 return (uint64_t) & (((mach_task_basic_info_t
)data
)->user_time
);
1039 T_ASSERT_FAIL("unhandled info_get %d %d", kind
, get
);
1045 return (uint64_t) & (((task_basic_info_32_t
)data
)->system_time
);
1046 #if defined(__arm__) || defined(__arm64__)
1048 T_ASSERT_FAIL("illegal info_get %d %d", kind
, get
);
1052 return (uint64_t) & (((task_basic_info_64_2_t
)data
)->system_time
);
1055 return (uint64_t) & (((task_basic_info_64_t
)data
)->system_time
);
1058 T_ASSERT_FAIL("illegal info_get %d %d", kind
, get
);
1060 #endif /* defined(__arm__) || defined(__arm64__) */
1062 return (uint64_t) & (((mach_task_basic_info_t
)data
)->user_time
);
1065 T_ASSERT_FAIL("unhandled info_get %d %d", kind
, get
);
1071 return (uint64_t)(((task_basic_info_32_t
)data
)->policy
);
1072 #if defined(__arm__) || defined(__arm64__)
1074 T_ASSERT_FAIL("illegal info_get %d %d", kind
, get
);
1078 return (uint64_t)(((task_basic_info_64_2_t
)data
)->policy
);
1081 return (uint64_t)(((task_basic_info_64_t
)data
)->policy
);
1084 T_ASSERT_FAIL("illegal info_get %d %d", kind
, get
);
1086 #endif /* defined(__arm__) || defined(__arm64__) */
1088 return (uint64_t)(((mach_task_basic_info_t
)data
)->policy
);
1092 T_ASSERT_FAIL("unhandled info_get %d %d", kind
, get
);
1100 T_ASSERT_FAIL("illegal info_get %d %d", kind
, get
);
1102 return (uint64_t)(((mach_task_basic_info_t
)data
)->resident_size_max
);
1105 T_ASSERT_FAIL("unhandled info_get %d %d", kind
, get
);
1109 __builtin_unreachable();
1113 * Determines whether we're running on a development kernel
1116 is_development_kernel(void)
1120 static int is_dev
= NOTSET
;
1122 if (is_dev
== NOTSET
) {
1124 size_t dev_size
= sizeof(dev
);
1127 T_ASSERT_POSIX_SUCCESS(sysctlbyname("kern.development", &dev
, &dev_size
, NULL
, 0), NULL
);
1128 is_dev
= (dev
!= 0);