]>
Commit | Line | Data |
---|---|---|
cb323159 A |
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> | |
f427ee49 A |
6 | #include <sys/kern_memorystatus.h> |
7 | #include <unistd.h> | |
cb323159 A |
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 | |
f427ee49 A |
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 | } | |
cb323159 A |
72 | T_DECL(test_os_proc_available_memory, "Basic available memory") |
73 | { | |
f427ee49 A |
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"); | |
cb323159 A |
101 | } |
102 | #endif |