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