xref: /xnu-11215.1.10/tests/memorystatus_assertion_helpers.c (revision 8d741a5de7ff4191bf97d57b9f54c2f6d4a15585)
1*8d741a5dSApple OSS Distributions #include <sys/sysctl.h>
2*8d741a5dSApple OSS Distributions #include <sys/kern_memorystatus.h>
3*8d741a5dSApple OSS Distributions 
4*8d741a5dSApple OSS Distributions #include <darwintest.h>
5*8d741a5dSApple OSS Distributions 
6*8d741a5dSApple OSS Distributions #include "memorystatus_assertion_helpers.h"
7*8d741a5dSApple OSS Distributions 
8*8d741a5dSApple OSS Distributions static void log_state(uint32_t state);
9*8d741a5dSApple OSS Distributions 
10*8d741a5dSApple OSS Distributions int
set_priority(pid_t pid,int32_t priority,uint64_t user_data,boolean_t is_assertion_driven)11*8d741a5dSApple OSS Distributions set_priority(pid_t pid, int32_t priority, uint64_t user_data, boolean_t is_assertion_driven)
12*8d741a5dSApple OSS Distributions {
13*8d741a5dSApple OSS Distributions 	int err;
14*8d741a5dSApple OSS Distributions 	uint32_t flag = 0;
15*8d741a5dSApple OSS Distributions 	memorystatus_priority_properties_t mjp = { 0 };
16*8d741a5dSApple OSS Distributions 
17*8d741a5dSApple OSS Distributions 	if (is_assertion_driven) {
18*8d741a5dSApple OSS Distributions 		/*
19*8d741a5dSApple OSS Distributions 		 * Control over an assertion driven priority will be
20*8d741a5dSApple OSS Distributions 		 * relinquished when priority == JETSAM_PRIORITY_IDLE
21*8d741a5dSApple OSS Distributions 		 */
22*8d741a5dSApple OSS Distributions 		if (priority == JETSAM_PRIORITY_IDLE) {
23*8d741a5dSApple OSS Distributions 			T_LOG("Relinquish ...assertion... priority(%d) for pid[%d]", priority, pid);
24*8d741a5dSApple OSS Distributions 		} else {
25*8d741a5dSApple OSS Distributions 			T_LOG("Setting ...assertion... priority(%d) for pid[%d]", priority, pid);
26*8d741a5dSApple OSS Distributions 		}
27*8d741a5dSApple OSS Distributions 		flag |= MEMORYSTATUS_SET_PRIORITY_ASSERTION;
28*8d741a5dSApple OSS Distributions 	} else {
29*8d741a5dSApple OSS Distributions 		T_LOG("Setting ...requested... priority(%d) for pid[%d]", priority, pid);
30*8d741a5dSApple OSS Distributions 		flag = 0;
31*8d741a5dSApple OSS Distributions 	}
32*8d741a5dSApple OSS Distributions 
33*8d741a5dSApple OSS Distributions 	mjp.priority = priority;
34*8d741a5dSApple OSS Distributions 	mjp.user_data = user_data;
35*8d741a5dSApple OSS Distributions 
36*8d741a5dSApple OSS Distributions 	err = memorystatus_control(MEMORYSTATUS_CMD_SET_PRIORITY_PROPERTIES, pid, flag, &mjp, sizeof(mjp));
37*8d741a5dSApple OSS Distributions 
38*8d741a5dSApple OSS Distributions 	T_QUIET;
39*8d741a5dSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(err, "MEMORYSTATUS_CMD_SET_PRIORITY_PROPERTIES failed");
40*8d741a5dSApple OSS Distributions 	return err;
41*8d741a5dSApple OSS Distributions }
42*8d741a5dSApple OSS Distributions 
43*8d741a5dSApple OSS Distributions boolean_t
check_properties(pid_t pid,int32_t expected_priority,int32_t expected_limit_mb,uint64_t expected_user_data,boolean_t expected_assertion_state,const char * test)44*8d741a5dSApple OSS Distributions check_properties(pid_t pid, int32_t expected_priority, int32_t expected_limit_mb, uint64_t expected_user_data, boolean_t expected_assertion_state, const char *test)
45*8d741a5dSApple OSS Distributions {
46*8d741a5dSApple OSS Distributions 	const char *PROP_CHECK_ERROR_STRING = "property mismatch";
47*8d741a5dSApple OSS Distributions 	boolean_t verbose = true;
48*8d741a5dSApple OSS Distributions 	boolean_t ret;
49*8d741a5dSApple OSS Distributions 
50*8d741a5dSApple OSS Distributions 	int32_t  actual_priority = 0;
51*8d741a5dSApple OSS Distributions 	int32_t  actual_limit_mb = 0;
52*8d741a5dSApple OSS Distributions 	uint64_t actual_user_data = 0;
53*8d741a5dSApple OSS Distributions 	uint32_t actual_state = 0;
54*8d741a5dSApple OSS Distributions 
55*8d741a5dSApple OSS Distributions 	verbose = false;
56*8d741a5dSApple OSS Distributions 	(void)get_priority_props(pid, verbose, &actual_priority, &actual_limit_mb, &actual_user_data, &actual_state);
57*8d741a5dSApple OSS Distributions 
58*8d741a5dSApple OSS Distributions 	if (test != NULL) {
59*8d741a5dSApple OSS Distributions 		T_LOG("check_properties: %s", test);
60*8d741a5dSApple OSS Distributions 	}
61*8d741a5dSApple OSS Distributions 
62*8d741a5dSApple OSS Distributions 	ret = verify_assertion_state(actual_state, expected_assertion_state);
63*8d741a5dSApple OSS Distributions 	T_QUIET;
64*8d741a5dSApple OSS Distributions 	T_ASSERT_TRUE(ret, "verify_assertion_state failed");
65*8d741a5dSApple OSS Distributions 
66*8d741a5dSApple OSS Distributions 
67*8d741a5dSApple OSS Distributions 	/*
68*8d741a5dSApple OSS Distributions 	 * These tests use well defined limits, so we don't try to handle defaults like
69*8d741a5dSApple OSS Distributions 	 * a limit of <= 0 which typically applies a system-wide per process limit.
70*8d741a5dSApple OSS Distributions 	 */
71*8d741a5dSApple OSS Distributions 
72*8d741a5dSApple OSS Distributions 	if ((actual_priority != expected_priority) || (actual_limit_mb != expected_limit_mb) || (actual_user_data != expected_user_data)) {
73*8d741a5dSApple OSS Distributions 		/* we have a mismatch */
74*8d741a5dSApple OSS Distributions 		T_LOG("%s test failed: %s\n", test, PROP_CHECK_ERROR_STRING);
75*8d741a5dSApple OSS Distributions 
76*8d741a5dSApple OSS Distributions 		if (actual_priority != expected_priority) {
77*8d741a5dSApple OSS Distributions 			T_LOG("priority mismatch [actual / expected] [%d / %d]", actual_priority, expected_priority);
78*8d741a5dSApple OSS Distributions 		}
79*8d741a5dSApple OSS Distributions 
80*8d741a5dSApple OSS Distributions 		if (actual_limit_mb != expected_limit_mb) {
81*8d741a5dSApple OSS Distributions 			T_LOG("limit mismatch [actual / expected] [%d / %d]", actual_limit_mb, expected_limit_mb);
82*8d741a5dSApple OSS Distributions 		}
83*8d741a5dSApple OSS Distributions 
84*8d741a5dSApple OSS Distributions 		if (actual_user_data != expected_user_data) {
85*8d741a5dSApple OSS Distributions 			T_LOG("user data mismatch [actual / expected] [0x%llx / 0x%llx]", actual_user_data, expected_user_data);
86*8d741a5dSApple OSS Distributions 		}
87*8d741a5dSApple OSS Distributions 
88*8d741a5dSApple OSS Distributions 		T_LOG("state is 0x%x\n", actual_state);
89*8d741a5dSApple OSS Distributions 		log_state(actual_state);
90*8d741a5dSApple OSS Distributions 
91*8d741a5dSApple OSS Distributions 		T_FAIL("check_properties: %s", test);
92*8d741a5dSApple OSS Distributions 	} else {
93*8d741a5dSApple OSS Distributions 		T_PASS("check_properties: %s ok", test);
94*8d741a5dSApple OSS Distributions 		return true;
95*8d741a5dSApple OSS Distributions 	}
96*8d741a5dSApple OSS Distributions 	return false;
97*8d741a5dSApple OSS Distributions }
98*8d741a5dSApple OSS Distributions 
99*8d741a5dSApple OSS Distributions int
set_assertion_priority(pid_t pid,int32_t priority,uint64_t user_data)100*8d741a5dSApple OSS Distributions set_assertion_priority(pid_t pid, int32_t priority, uint64_t user_data)
101*8d741a5dSApple OSS Distributions {
102*8d741a5dSApple OSS Distributions 	return set_priority(pid, priority, user_data, TRUE);
103*8d741a5dSApple OSS Distributions }
104*8d741a5dSApple OSS Distributions 
105*8d741a5dSApple OSS Distributions int
relinquish_assertion_priority(pid_t pid,uint64_t user_data)106*8d741a5dSApple OSS Distributions relinquish_assertion_priority(pid_t pid, uint64_t user_data)
107*8d741a5dSApple OSS Distributions {
108*8d741a5dSApple OSS Distributions 	return set_assertion_priority(pid, JETSAM_PRIORITY_IDLE, user_data);
109*8d741a5dSApple OSS Distributions }
110*8d741a5dSApple OSS Distributions 
111*8d741a5dSApple OSS Distributions int
set_memlimits(pid_t pid,int32_t active_limit_mb,int32_t inactive_limit_mb,boolean_t active_is_fatal,boolean_t inactive_is_fatal)112*8d741a5dSApple OSS Distributions set_memlimits(
113*8d741a5dSApple OSS Distributions 	pid_t pid,
114*8d741a5dSApple OSS Distributions 	int32_t active_limit_mb, int32_t inactive_limit_mb,
115*8d741a5dSApple OSS Distributions 	boolean_t active_is_fatal, boolean_t inactive_is_fatal)
116*8d741a5dSApple OSS Distributions {
117*8d741a5dSApple OSS Distributions 	int err;
118*8d741a5dSApple OSS Distributions 	memorystatus_memlimit_properties_t mmprops;
119*8d741a5dSApple OSS Distributions 
120*8d741a5dSApple OSS Distributions 	memset(&mmprops, 0, sizeof(memorystatus_memlimit_properties_t));
121*8d741a5dSApple OSS Distributions 
122*8d741a5dSApple OSS Distributions 	mmprops.memlimit_active = active_limit_mb;
123*8d741a5dSApple OSS Distributions 	mmprops.memlimit_inactive = inactive_limit_mb;
124*8d741a5dSApple OSS Distributions 
125*8d741a5dSApple OSS Distributions 	if (active_is_fatal) {
126*8d741a5dSApple OSS Distributions 		mmprops.memlimit_active_attr |= MEMORYSTATUS_MEMLIMIT_ATTR_FATAL;
127*8d741a5dSApple OSS Distributions 	} else {
128*8d741a5dSApple OSS Distributions 		mmprops.memlimit_active_attr &= ~(uint32_t)MEMORYSTATUS_MEMLIMIT_ATTR_FATAL;
129*8d741a5dSApple OSS Distributions 	}
130*8d741a5dSApple OSS Distributions 
131*8d741a5dSApple OSS Distributions 	if (inactive_is_fatal) {
132*8d741a5dSApple OSS Distributions 		mmprops.memlimit_inactive_attr |= MEMORYSTATUS_MEMLIMIT_ATTR_FATAL;
133*8d741a5dSApple OSS Distributions 	} else {
134*8d741a5dSApple OSS Distributions 		mmprops.memlimit_inactive_attr &= ~(uint32_t)MEMORYSTATUS_MEMLIMIT_ATTR_FATAL;
135*8d741a5dSApple OSS Distributions 	}
136*8d741a5dSApple OSS Distributions 
137*8d741a5dSApple OSS Distributions 	T_LOG("Setting pid[%d] limits active [%d %s] inactive [%d %s]", pid,
138*8d741a5dSApple OSS Distributions 	    mmprops.memlimit_active, (active_is_fatal ? "hard" : "soft"),
139*8d741a5dSApple OSS Distributions 	    mmprops.memlimit_inactive, (inactive_is_fatal ? "hard" : "soft"));
140*8d741a5dSApple OSS Distributions 
141*8d741a5dSApple OSS Distributions 	err =  memorystatus_control(MEMORYSTATUS_CMD_SET_MEMLIMIT_PROPERTIES, pid, 0, &mmprops, sizeof(mmprops));
142*8d741a5dSApple OSS Distributions 
143*8d741a5dSApple OSS Distributions 	T_QUIET;
144*8d741a5dSApple OSS Distributions 	T_ASSERT_POSIX_SUCCESS(err, "MEMORYSTATUS_CMD_SET_MEMLIMIT_PROPERTIES failed");
145*8d741a5dSApple OSS Distributions 	return err;
146*8d741a5dSApple OSS Distributions }
147*8d741a5dSApple OSS Distributions 
148*8d741a5dSApple OSS Distributions boolean_t
get_priority_props(pid_t pid,boolean_t verbose,int32_t * priority,int32_t * limit_mb,uint64_t * user_data,uint32_t * state)149*8d741a5dSApple OSS Distributions get_priority_props(pid_t pid, boolean_t verbose, int32_t *priority, int32_t *limit_mb, uint64_t *user_data, uint32_t *state)
150*8d741a5dSApple OSS Distributions {
151*8d741a5dSApple OSS Distributions 	memorystatus_priority_entry_t entry = {0};
152*8d741a5dSApple OSS Distributions 
153*8d741a5dSApple OSS Distributions 	int size = memorystatus_control(MEMORYSTATUS_CMD_GET_PRIORITY_LIST, pid, 0, &entry, sizeof(entry));
154*8d741a5dSApple OSS Distributions 
155*8d741a5dSApple OSS Distributions 	/* validate size returned */
156*8d741a5dSApple OSS Distributions 	if (size <= 0) {
157*8d741a5dSApple OSS Distributions 		T_ASSERT_FAIL("get_priority: can't get list size: %d!\n", size);
158*8d741a5dSApple OSS Distributions 	}
159*8d741a5dSApple OSS Distributions 
160*8d741a5dSApple OSS Distributions 	if (size != sizeof(entry)) {
161*8d741a5dSApple OSS Distributions 		T_ASSERT_FAIL("get_priority: returned unexpected entry size\n");
162*8d741a5dSApple OSS Distributions 	}
163*8d741a5dSApple OSS Distributions 
164*8d741a5dSApple OSS Distributions 	if (entry.pid != pid) {
165*8d741a5dSApple OSS Distributions 		T_ASSERT_FAIL("get_priority: returned unexpected entry pid\n");
166*8d741a5dSApple OSS Distributions 	}
167*8d741a5dSApple OSS Distributions 
168*8d741a5dSApple OSS Distributions 	T_LOG("get_priority_props: pid[%d] limit %d, user_data 0x%llx, priority %d, state 0x%x",
169*8d741a5dSApple OSS Distributions 	    entry.pid, entry.limit, entry.user_data, entry.priority, entry.state);
170*8d741a5dSApple OSS Distributions 
171*8d741a5dSApple OSS Distributions 
172*8d741a5dSApple OSS Distributions 	if (verbose) {
173*8d741a5dSApple OSS Distributions 		log_state(entry.state);
174*8d741a5dSApple OSS Distributions 	}
175*8d741a5dSApple OSS Distributions 
176*8d741a5dSApple OSS Distributions 	if (priority) {
177*8d741a5dSApple OSS Distributions 		*priority = entry.priority;
178*8d741a5dSApple OSS Distributions 	}
179*8d741a5dSApple OSS Distributions 	if (limit_mb) {
180*8d741a5dSApple OSS Distributions 		*limit_mb = entry.limit;
181*8d741a5dSApple OSS Distributions 	}
182*8d741a5dSApple OSS Distributions 	if (user_data) {
183*8d741a5dSApple OSS Distributions 		*user_data = entry.user_data;
184*8d741a5dSApple OSS Distributions 	}
185*8d741a5dSApple OSS Distributions 	if (state) {
186*8d741a5dSApple OSS Distributions 		*state = entry.state;
187*8d741a5dSApple OSS Distributions 	}
188*8d741a5dSApple OSS Distributions 
189*8d741a5dSApple OSS Distributions 	return true;
190*8d741a5dSApple OSS Distributions }
191*8d741a5dSApple OSS Distributions 
192*8d741a5dSApple OSS Distributions boolean_t
verify_assertion_state(uint32_t state,boolean_t expected_assertion_state)193*8d741a5dSApple OSS Distributions verify_assertion_state(uint32_t state, boolean_t expected_assertion_state)
194*8d741a5dSApple OSS Distributions {
195*8d741a5dSApple OSS Distributions 	boolean_t actual_assertion_state;
196*8d741a5dSApple OSS Distributions 	char *actual_string;
197*8d741a5dSApple OSS Distributions 	char *expected_string;
198*8d741a5dSApple OSS Distributions 
199*8d741a5dSApple OSS Distributions 	if (expected_assertion_state == ASSERTION_STATE_IS_SET) {
200*8d741a5dSApple OSS Distributions 		expected_string = "ASSERTION_STATE_IS_SET";
201*8d741a5dSApple OSS Distributions 	} else {
202*8d741a5dSApple OSS Distributions 		expected_string = "ASSERTION_STATE_IS_RELINQUISHED";
203*8d741a5dSApple OSS Distributions 	}
204*8d741a5dSApple OSS Distributions 
205*8d741a5dSApple OSS Distributions 	if (state & kMemorystatusAssertion) {
206*8d741a5dSApple OSS Distributions 		/*
207*8d741a5dSApple OSS Distributions 		 * An assertion driven jetsam priority is at play.
208*8d741a5dSApple OSS Distributions 		 */
209*8d741a5dSApple OSS Distributions 		actual_assertion_state = ASSERTION_STATE_IS_SET;
210*8d741a5dSApple OSS Distributions 		actual_string = "ASSERTION_STATE_IS_SET";
211*8d741a5dSApple OSS Distributions 	} else {
212*8d741a5dSApple OSS Distributions 		/*
213*8d741a5dSApple OSS Distributions 		 * There is no assertion driven jetsam priority in place.
214*8d741a5dSApple OSS Distributions 		 */
215*8d741a5dSApple OSS Distributions 		actual_assertion_state = ASSERTION_STATE_IS_RELINQUISHED;
216*8d741a5dSApple OSS Distributions 		actual_string = "ASSERTION_STATE_IS_RELINQUISHED";
217*8d741a5dSApple OSS Distributions 	}
218*8d741a5dSApple OSS Distributions 
219*8d741a5dSApple OSS Distributions 	if (actual_assertion_state == expected_assertion_state) {
220*8d741a5dSApple OSS Distributions 		T_PASS("%s as expected", expected_string);
221*8d741a5dSApple OSS Distributions 		return true;
222*8d741a5dSApple OSS Distributions 	} else {
223*8d741a5dSApple OSS Distributions 		T_FAIL("state 0x%x:  %s but expected %s", state, actual_string, expected_string);
224*8d741a5dSApple OSS Distributions 		// log_state(state);
225*8d741a5dSApple OSS Distributions 		return false;   /* failed */
226*8d741a5dSApple OSS Distributions 	}
227*8d741a5dSApple OSS Distributions }
228*8d741a5dSApple OSS Distributions 
229*8d741a5dSApple OSS Distributions static void
log_state(uint32_t state)230*8d741a5dSApple OSS Distributions log_state(uint32_t state)
231*8d741a5dSApple OSS Distributions {
232*8d741a5dSApple OSS Distributions 	T_LOG("\t%s kMemorystatusSuspended", ((state & kMemorystatusSuspended)        ? "IS " : "NOT"));
233*8d741a5dSApple OSS Distributions 	T_LOG("\t%s kMemorystatusFrozen", ((state & kMemorystatusFrozen)           ? "IS " : "NOT"));
234*8d741a5dSApple OSS Distributions 	T_LOG("\t%s kMemorystatusWasThawed", ((state & kMemorystatusWasThawed)        ? "IS " : "NOT"));
235*8d741a5dSApple OSS Distributions 	T_LOG("\t%s kMemorystatusTracked", ((state & kMemorystatusTracked)          ? "IS " : "NOT"));
236*8d741a5dSApple OSS Distributions 	T_LOG("\t%s kMemorystatusSupportsIdleExit", ((state & kMemorystatusSupportsIdleExit) ? "IS " : "NOT"));
237*8d741a5dSApple OSS Distributions 	T_LOG("\t%s kMemorystatusDirty", ((state & kMemorystatusDirty)            ? "IS " : "NOT"));
238*8d741a5dSApple OSS Distributions 	T_LOG("\t%s kMemorystatusAssertion", ((state & kMemorystatusAssertion)        ? "IS " : "NOT"));
239*8d741a5dSApple OSS Distributions }
240