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