xref: /xnu-11417.121.6/tests/vm/memorystatus_priority_list.c (revision a1e26a70f38d1d7daa7b49b258e2f8538ad81650)
1*a1e26a70SApple OSS Distributions /*
2*a1e26a70SApple OSS Distributions  * Copyright (c) 2024 Apple Inc. All rights reserved.
3*a1e26a70SApple OSS Distributions  *
4*a1e26a70SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*a1e26a70SApple OSS Distributions  *
6*a1e26a70SApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*a1e26a70SApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*a1e26a70SApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*a1e26a70SApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*a1e26a70SApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*a1e26a70SApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*a1e26a70SApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*a1e26a70SApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*a1e26a70SApple OSS Distributions  *
15*a1e26a70SApple OSS Distributions  * Please obtain a copy of the License at
16*a1e26a70SApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*a1e26a70SApple OSS Distributions  *
18*a1e26a70SApple OSS Distributions  * The Original Code and all software distributed under the License are
19*a1e26a70SApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*a1e26a70SApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*a1e26a70SApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*a1e26a70SApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*a1e26a70SApple OSS Distributions  * Please see the License for the specific language governing rights and
24*a1e26a70SApple OSS Distributions  * limitations under the License.
25*a1e26a70SApple OSS Distributions  *
26*a1e26a70SApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*a1e26a70SApple OSS Distributions  *
28*a1e26a70SApple OSS Distributions  */
29*a1e26a70SApple OSS Distributions 
30*a1e26a70SApple OSS Distributions #include <sys/proc.h>
31*a1e26a70SApple OSS Distributions #include <sys/sysctl.h>
32*a1e26a70SApple OSS Distributions #include <sys/kern_memorystatus.h>
33*a1e26a70SApple OSS Distributions #include <mach-o/dyld.h>
34*a1e26a70SApple OSS Distributions #include <mach/mach_vm.h>
35*a1e26a70SApple OSS Distributions #include <mach/vm_page_size.h>
36*a1e26a70SApple OSS Distributions #include <mach/shared_region.h>
37*a1e26a70SApple OSS Distributions #include <mach/mach.h>
38*a1e26a70SApple OSS Distributions #include <os/reason_private.h>
39*a1e26a70SApple OSS Distributions #include <TargetConditionals.h>
40*a1e26a70SApple OSS Distributions #include <darwintest.h>
41*a1e26a70SApple OSS Distributions #include <darwintest_utils.h>
42*a1e26a70SApple OSS Distributions 
43*a1e26a70SApple OSS Distributions T_GLOBAL_META(
44*a1e26a70SApple OSS Distributions 	T_META_NAMESPACE("xnu.memorystatus"),
45*a1e26a70SApple OSS Distributions 	T_META_RADAR_COMPONENT_NAME("xnu"),
46*a1e26a70SApple OSS Distributions 	T_META_RADAR_COMPONENT_VERSION("VM"),
47*a1e26a70SApple OSS Distributions 	T_META_ASROOT(true),
48*a1e26a70SApple OSS Distributions 	T_META_TAG_VM_PREFERRED
49*a1e26a70SApple OSS Distributions 	);
50*a1e26a70SApple OSS Distributions 
51*a1e26a70SApple OSS Distributions #define SIZE_ESTIMATE_EXTRA_ENTRIES 5
52*a1e26a70SApple OSS Distributions #define MAX_TRIES 3
53*a1e26a70SApple OSS Distributions 
54*a1e26a70SApple OSS Distributions #define _STR(x) #x
55*a1e26a70SApple OSS Distributions #define STR(x) _STR(x)
56*a1e26a70SApple OSS Distributions 
57*a1e26a70SApple OSS Distributions memorystatus_priority_entry_v2_t*
get_priority_list(pid_t pid,int call,size_t entry_size,ssize_t * len)58*a1e26a70SApple OSS Distributions get_priority_list(pid_t pid, int call, size_t entry_size, ssize_t* len)
59*a1e26a70SApple OSS Distributions {
60*a1e26a70SApple OSS Distributions 	int i;
61*a1e26a70SApple OSS Distributions 	ssize_t size;
62*a1e26a70SApple OSS Distributions 	memorystatus_priority_entry_v2_t *list = NULL;
63*a1e26a70SApple OSS Distributions 
64*a1e26a70SApple OSS Distributions 	for (i = 0; i < MAX_TRIES; i++) {
65*a1e26a70SApple OSS Distributions 		T_LOG("Attempt %d", i + 1);
66*a1e26a70SApple OSS Distributions 
67*a1e26a70SApple OSS Distributions 		size = memorystatus_control(call, pid, 0, NULL, 0);
68*a1e26a70SApple OSS Distributions 
69*a1e26a70SApple OSS Distributions 		T_ASSERT_GT(size, 0l, "Priority list query size > 0");
70*a1e26a70SApple OSS Distributions 		T_ASSERT_EQ(size % entry_size, 0ul, "Priority list size is multiple of struct size");
71*a1e26a70SApple OSS Distributions 
72*a1e26a70SApple OSS Distributions 		if (size <= 0) {
73*a1e26a70SApple OSS Distributions 			return NULL;
74*a1e26a70SApple OSS Distributions 		}
75*a1e26a70SApple OSS Distributions 
76*a1e26a70SApple OSS Distributions 		/* pad out the size just in case the list gets bigger */
77*a1e26a70SApple OSS Distributions 		if (pid == 0) {
78*a1e26a70SApple OSS Distributions 			size += SIZE_ESTIMATE_EXTRA_ENTRIES * entry_size;
79*a1e26a70SApple OSS Distributions 		}
80*a1e26a70SApple OSS Distributions 
81*a1e26a70SApple OSS Distributions 		list = malloc(size);
82*a1e26a70SApple OSS Distributions 		T_QUIET; T_ASSERT_NOTNULL(list, "malloc");
83*a1e26a70SApple OSS Distributions 
84*a1e26a70SApple OSS Distributions 		*len = memorystatus_control(call, pid, 0, list, size);
85*a1e26a70SApple OSS Distributions 
86*a1e26a70SApple OSS Distributions 		if (*len <= 0) {
87*a1e26a70SApple OSS Distributions 			T_LOG("Failed, maybe the list grew? Trying again...");
88*a1e26a70SApple OSS Distributions 			free(list);
89*a1e26a70SApple OSS Distributions 			continue;
90*a1e26a70SApple OSS Distributions 		}
91*a1e26a70SApple OSS Distributions 
92*a1e26a70SApple OSS Distributions 		T_ASSERT_GE(size, *len, "List fits in buffer");
93*a1e26a70SApple OSS Distributions 		T_ASSERT_GT(size, 0l, "List size nonzero");
94*a1e26a70SApple OSS Distributions 		return list;
95*a1e26a70SApple OSS Distributions 	}
96*a1e26a70SApple OSS Distributions 
97*a1e26a70SApple OSS Distributions 	T_FAIL("Tried more than MAX_TRIES=" STR(MAX_TRIES) " times");
98*a1e26a70SApple OSS Distributions 	return NULL;
99*a1e26a70SApple OSS Distributions }
100*a1e26a70SApple OSS Distributions 
101*a1e26a70SApple OSS Distributions void
validate_entry(memorystatus_priority_entry_v2_t * entry,size_t entry_size,pid_t expect_pid)102*a1e26a70SApple OSS Distributions validate_entry(memorystatus_priority_entry_v2_t *entry, size_t entry_size, pid_t expect_pid)
103*a1e26a70SApple OSS Distributions {
104*a1e26a70SApple OSS Distributions 	int i;
105*a1e26a70SApple OSS Distributions 	if (expect_pid == -1) {
106*a1e26a70SApple OSS Distributions 		T_QUIET; T_ASSERT_GE(entry->pid, 0, "PID valid");
107*a1e26a70SApple OSS Distributions 		T_QUIET; T_ASSERT_NE(entry->pid, 0, "kernel_task not in list");
108*a1e26a70SApple OSS Distributions 		T_QUIET; T_ASSERT_NE(entry->pid, 1, "launchd not in list");
109*a1e26a70SApple OSS Distributions 	} else {
110*a1e26a70SApple OSS Distributions 		T_QUIET; T_ASSERT_EQ(entry->pid, expect_pid, "PID correct");
111*a1e26a70SApple OSS Distributions 	}
112*a1e26a70SApple OSS Distributions 
113*a1e26a70SApple OSS Distributions 	if (entry->pid > 1) {
114*a1e26a70SApple OSS Distributions 		T_QUIET; T_ASSERT_GE(
115*a1e26a70SApple OSS Distributions 			entry->priority,
116*a1e26a70SApple OSS Distributions 			0,
117*a1e26a70SApple OSS Distributions 			"Entry priority >= 0");
118*a1e26a70SApple OSS Distributions 		T_QUIET; T_ASSERT_LE(
119*a1e26a70SApple OSS Distributions 			entry->priority,
120*a1e26a70SApple OSS Distributions 			JETSAM_PRIORITY_MAX,
121*a1e26a70SApple OSS Distributions 			"Entry priority <= JETSAM_PRIORITY_MAX (" STR(JETSAM_PRIORITY_MAX) ")");
122*a1e26a70SApple OSS Distributions 	} else {
123*a1e26a70SApple OSS Distributions 		T_QUIET; T_ASSERT_EQ(
124*a1e26a70SApple OSS Distributions 			entry->priority,
125*a1e26a70SApple OSS Distributions 			JETSAM_PRIORITY_INTERNAL,
126*a1e26a70SApple OSS Distributions 			"Entry priority == JETSAM_PRIORITY_INTERNAL (" STR(JETSAM_PRIORITY_INTERNAL) ")");
127*a1e26a70SApple OSS Distributions 	}
128*a1e26a70SApple OSS Distributions 
129*a1e26a70SApple OSS Distributions 	if (entry_size == sizeof(memorystatus_priority_entry_v2_t)) {
130*a1e26a70SApple OSS Distributions 		boolean_t found_nonzero = false;
131*a1e26a70SApple OSS Distributions 		for (i = 0; i < sizeof(entry->_reserved) / sizeof(entry->_reserved[0]); i++) {
132*a1e26a70SApple OSS Distributions 			if (entry->_reserved[i]) {
133*a1e26a70SApple OSS Distributions 				found_nonzero = true;
134*a1e26a70SApple OSS Distributions 				break;
135*a1e26a70SApple OSS Distributions 			}
136*a1e26a70SApple OSS Distributions 		}
137*a1e26a70SApple OSS Distributions 		T_QUIET; T_ASSERT_FALSE(found_nonzero, "Entry reserved is empty");
138*a1e26a70SApple OSS Distributions 	}
139*a1e26a70SApple OSS Distributions }
140*a1e26a70SApple OSS Distributions 
141*a1e26a70SApple OSS Distributions T_DECL(jetsam_priority_list_v2_list, "Jetsam priority list v2 - list")
142*a1e26a70SApple OSS Distributions {
143*a1e26a70SApple OSS Distributions 	int i;
144*a1e26a70SApple OSS Distributions 	ssize_t len;
145*a1e26a70SApple OSS Distributions 	memorystatus_priority_entry_v2_t *list = get_priority_list(
146*a1e26a70SApple OSS Distributions 		0,
147*a1e26a70SApple OSS Distributions 		MEMORYSTATUS_CMD_GET_PRIORITY_LIST_V2,
148*a1e26a70SApple OSS Distributions 		sizeof(*list),
149*a1e26a70SApple OSS Distributions 		&len);
150*a1e26a70SApple OSS Distributions 
151*a1e26a70SApple OSS Distributions 	T_ASSERT_NOTNULL(list, "Priority list not null");
152*a1e26a70SApple OSS Distributions 	for (i = 0; i < len / sizeof(memorystatus_priority_entry_v2_t); i++) {
153*a1e26a70SApple OSS Distributions 		validate_entry(&list[i], sizeof(*list), -1);
154*a1e26a70SApple OSS Distributions 	}
155*a1e26a70SApple OSS Distributions 	free(list);
156*a1e26a70SApple OSS Distributions 	T_PASS("Entries valid");
157*a1e26a70SApple OSS Distributions }
158*a1e26a70SApple OSS Distributions 
159*a1e26a70SApple OSS Distributions void
validate_single(pid_t pid)160*a1e26a70SApple OSS Distributions validate_single(pid_t pid)
161*a1e26a70SApple OSS Distributions {
162*a1e26a70SApple OSS Distributions 	ssize_t len;
163*a1e26a70SApple OSS Distributions 	memorystatus_priority_entry_v2_t *list = get_priority_list(
164*a1e26a70SApple OSS Distributions 		pid,
165*a1e26a70SApple OSS Distributions 		MEMORYSTATUS_CMD_GET_PRIORITY_LIST_V2,
166*a1e26a70SApple OSS Distributions 		sizeof(*list),
167*a1e26a70SApple OSS Distributions 		&len);
168*a1e26a70SApple OSS Distributions 
169*a1e26a70SApple OSS Distributions 	T_ASSERT_NOTNULL(list, "Getting self priority entry");
170*a1e26a70SApple OSS Distributions 	T_ASSERT_EQ(len, sizeof(memorystatus_priority_entry_v2_t), "Single entry returned");
171*a1e26a70SApple OSS Distributions 	validate_entry(list, sizeof(*list), pid);
172*a1e26a70SApple OSS Distributions 	free(list);
173*a1e26a70SApple OSS Distributions }
174*a1e26a70SApple OSS Distributions 
175*a1e26a70SApple OSS Distributions T_DECL(jetsam_priority_list_v2_single, "Jetsam priority list v2 - single")
176*a1e26a70SApple OSS Distributions {
177*a1e26a70SApple OSS Distributions 	T_LOG("Getting entry for self...");
178*a1e26a70SApple OSS Distributions 	validate_single(getpid());
179*a1e26a70SApple OSS Distributions 
180*a1e26a70SApple OSS Distributions 	T_LOG("Getting entry for launchd...");
181*a1e26a70SApple OSS Distributions 	validate_single(1);
182*a1e26a70SApple OSS Distributions 
183*a1e26a70SApple OSS Distributions 	T_PASS("Entries valid");
184*a1e26a70SApple OSS Distributions }
185*a1e26a70SApple OSS Distributions 
186*a1e26a70SApple OSS Distributions T_DECL(jetsam_priority_list_compat, "Jetsam priority list - v1 compat")
187*a1e26a70SApple OSS Distributions {
188*a1e26a70SApple OSS Distributions 	int i;
189*a1e26a70SApple OSS Distributions 	ssize_t len;
190*a1e26a70SApple OSS Distributions 
191*a1e26a70SApple OSS Distributions 	memorystatus_priority_entry_t *list = (memorystatus_priority_entry_t*) get_priority_list(
192*a1e26a70SApple OSS Distributions 		0,
193*a1e26a70SApple OSS Distributions 		MEMORYSTATUS_CMD_GET_PRIORITY_LIST,
194*a1e26a70SApple OSS Distributions 		sizeof(*list),
195*a1e26a70SApple OSS Distributions 		&len);
196*a1e26a70SApple OSS Distributions 
197*a1e26a70SApple OSS Distributions 	T_ASSERT_NOTNULL(list, "Priority list not null");
198*a1e26a70SApple OSS Distributions 
199*a1e26a70SApple OSS Distributions 	for (i = 0; i < len / sizeof(memorystatus_priority_entry_v2_t); i++) {
200*a1e26a70SApple OSS Distributions 		validate_entry((memorystatus_priority_entry_v2_t*) (&list[i]), sizeof(*list), -1);
201*a1e26a70SApple OSS Distributions 	}
202*a1e26a70SApple OSS Distributions 
203*a1e26a70SApple OSS Distributions 	free(list);
204*a1e26a70SApple OSS Distributions 	T_PASS("Entries valid");
205*a1e26a70SApple OSS Distributions }
206