]> git.saurik.com Git - apple/xnu.git/blob - tests/os_proc.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / tests / os_proc.c
1 #include <darwintest.h>
2 #include <darwintest_utils.h>
3 #include <mach/mach.h>
4 #include <mach/task_info.h>
5 #include <os/proc.h>
6 #include <sys/kern_memorystatus.h>
7 #include <unistd.h>
8
9 T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
10
11 #if !TARGET_OS_OSX
12 void test_os_proc_available_memory(void);
13 extern int getpid(void);
14
15 T_DECL(test_os_proc_available_memory, "Basic available memory")
16 {
17 kern_return_t err;
18 task_vm_info_data_t vm_info = {};
19 mach_msg_type_number_t count = TASK_VM_INFO_REV4_COUNT;
20 uint64_t remainingBytes;
21
22 err = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t)&vm_info, &count);
23 remainingBytes = os_proc_available_memory();
24
25 T_ASSERT_MACH_SUCCESS(err, "verify task_info call succeeded");
26 T_EXPECT_EQ(count, TASK_VM_INFO_REV4_COUNT, "task_info count(%d) is equal to TASK_VM_INFO_REV4_COUNT (%d)\n", count, TASK_VM_INFO_REV4_COUNT);
27 T_EXPECT_NE(remainingBytes, 0ULL, "os_proc_available_memory() should not return 0");
28 T_EXPECT_NE(vm_info.limit_bytes_remaining, 0ULL, "vm_info.limit_bytes_remaining should not return 0");
29 T_EXPECT_EQ(vm_info.limit_bytes_remaining, remainingBytes,
30 "task_info --rev4 call returned value 0x%llx for vm_info.limit_bytes_remaining. Expected 0x%llx",
31 vm_info.limit_bytes_remaining, remainingBytes);
32
33 /* this should now make the available memory return 0 */
34 proc_track_dirty(getpid(), PROC_DIRTY_TRACK);
35
36 count = TASK_VM_INFO_REV4_COUNT;
37 err = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t)&vm_info, &count);
38 remainingBytes = os_proc_available_memory();
39
40 T_ASSERT_MACH_SUCCESS(err, "verify task_info call succeeded");
41 T_EXPECT_EQ(count, TASK_VM_INFO_REV4_COUNT, "task_info count(%d) is equal to TASK_VM_INFO_REV4_COUNT\n", count);
42 T_EXPECT_EQ(remainingBytes, 0ULL, "os_proc_available_memory() should return 0");
43 T_EXPECT_EQ(vm_info.limit_bytes_remaining, 0ULL, "vm_info.limit_bytes_remaining should return 0");
44 T_EXPECT_EQ(vm_info.limit_bytes_remaining, remainingBytes,
45 "task_info --rev4 call returned value 0x%llx for vm_info.limit_bytes_remaining. Expected 0x%llx",
46 vm_info.limit_bytes_remaining, remainingBytes);
47 }
48 #else
49
50 /*
51 * os_proc_available_memory is only available on embedded.
52 * But the underlying syscall works on macOS to support catalyst
53 * extensions. So we test the syscall directly here.
54 */
55 extern uint64_t __memorystatus_available_memory(void);
56
57 static int
58 set_memlimit(pid_t pid, int32_t limit_mb)
59 {
60 memorystatus_memlimit_properties_t mmprops;
61
62 memset(&mmprops, 0, sizeof(memorystatus_memlimit_properties_t));
63
64 mmprops.memlimit_active = limit_mb;
65 mmprops.memlimit_inactive = limit_mb;
66
67 /* implies we want to set fatal limits */
68 mmprops.memlimit_active_attr |= MEMORYSTATUS_MEMLIMIT_ATTR_FATAL;
69 mmprops.memlimit_inactive_attr |= MEMORYSTATUS_MEMLIMIT_ATTR_FATAL;
70 return memorystatus_control(MEMORYSTATUS_CMD_SET_MEMLIMIT_PROPERTIES, pid, 0, &mmprops, sizeof(mmprops));
71 }
72 T_DECL(test_os_proc_available_memory, "Basic available memory")
73 {
74 uint64_t available_memory;
75 int ret;
76 pid_t pid = getpid();
77 static const size_t kLimitMb = 1024;
78
79 /*
80 * Should return 0 unless an proccess is both memory managed and has a
81 * hard memory limit.
82 */
83 ret = memorystatus_control(MEMORYSTATUS_CMD_SET_PROCESS_IS_MANAGED, pid, 0, NULL, 0);
84 T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "memorystatus_control");
85
86 available_memory = __memorystatus_available_memory();
87 T_ASSERT_EQ(available_memory, 0ULL, "__memorystatus_available_memory == 0");
88
89 ret = memorystatus_control(MEMORYSTATUS_CMD_SET_PROCESS_IS_MANAGED, pid, 1, NULL, 0);
90 T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "memorystatus_control");
91 available_memory = __memorystatus_available_memory();
92 T_ASSERT_EQ(available_memory, 0ULL, "__memorystatus_available_memory == 0");
93
94 /*
95 * Should not return 0 for managed procs with a hard memory limit.
96 */
97 ret = set_memlimit(pid, kLimitMb);
98 T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "memorystatus_control");
99 available_memory = __memorystatus_available_memory();
100 T_ASSERT_NE(available_memory, 0ULL, "__memorystatus_available_memory != 0");
101 }
102 #endif