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