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