1 #include <sys/sysctl.h>
2 #include <sys/kern_memorystatus.h>
4 #include <darwintest.h>
6 #include "memorystatus_assertion_helpers.h"
8 static void log_state(uint32_t state
);
11 set_priority(pid_t pid
, int32_t priority
, uint64_t user_data
, boolean_t is_assertion_driven
)
15 memorystatus_priority_properties_t mjp
= { 0 };
17 if (is_assertion_driven
) {
19 * Control over an assertion driven priority will be
20 * relinquished when priority == JETSAM_PRIORITY_IDLE
22 if (priority
== JETSAM_PRIORITY_IDLE
) {
23 T_LOG("Relinquish ...assertion... priority(%d) for pid[%d]", priority
, pid
);
25 T_LOG("Setting ...assertion... priority(%d) for pid[%d]", priority
, pid
);
27 flag
|= MEMORYSTATUS_SET_PRIORITY_ASSERTION
;
29 T_LOG("Setting ...requested... priority(%d) for pid[%d]", priority
, pid
);
33 mjp
.priority
= priority
;
34 mjp
.user_data
= user_data
;
36 err
= memorystatus_control(MEMORYSTATUS_CMD_SET_PRIORITY_PROPERTIES
, pid
, flag
, &mjp
, sizeof(mjp
));
39 T_ASSERT_POSIX_SUCCESS(err
, "MEMORYSTATUS_CMD_SET_PRIORITY_PROPERTIES failed");
44 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
)
46 const char *PROP_CHECK_ERROR_STRING
= "property mismatch";
47 boolean_t verbose
= true;
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;
56 (void)get_priority_props(pid
, verbose
, &actual_priority
, &actual_limit_mb
, &actual_user_data
, &actual_state
);
59 T_LOG("check_properties: %s", test
);
62 ret
= verify_assertion_state(actual_state
, expected_assertion_state
);
64 T_ASSERT_TRUE(ret
, "verify_assertion_state failed");
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.
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
);
76 if (actual_priority
!= expected_priority
) {
77 T_LOG("priority mismatch [actual / expected] [%d / %d]", actual_priority
, expected_priority
);
80 if (actual_limit_mb
!= expected_limit_mb
) {
81 T_LOG("limit mismatch [actual / expected] [%d / %d]", actual_limit_mb
, expected_limit_mb
);
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
);
88 T_LOG("state is 0x%x\n", actual_state
);
89 log_state(actual_state
);
91 T_ASSERT_FAIL("check_properties: %s", test
);
93 T_PASS("check_properties: %s ok", test
);
100 set_assertion_priority(pid_t pid
, int32_t priority
, uint64_t user_data
)
102 return set_priority(pid
, priority
, user_data
, TRUE
);
106 relinquish_assertion_priority(pid_t pid
, uint64_t user_data
)
108 return set_assertion_priority(pid
, JETSAM_PRIORITY_IDLE
, user_data
);
114 int32_t active_limit_mb
, int32_t inactive_limit_mb
,
115 boolean_t active_is_fatal
, boolean_t inactive_is_fatal
)
118 memorystatus_memlimit_properties_t mmprops
;
120 memset(&mmprops
, 0, sizeof(memorystatus_memlimit_properties_t
));
122 mmprops
.memlimit_active
= active_limit_mb
;
123 mmprops
.memlimit_inactive
= inactive_limit_mb
;
125 if (active_is_fatal
) {
126 mmprops
.memlimit_active_attr
|= MEMORYSTATUS_MEMLIMIT_ATTR_FATAL
;
128 mmprops
.memlimit_active_attr
&= ~(uint32_t)MEMORYSTATUS_MEMLIMIT_ATTR_FATAL
;
131 if (inactive_is_fatal
) {
132 mmprops
.memlimit_inactive_attr
|= MEMORYSTATUS_MEMLIMIT_ATTR_FATAL
;
134 mmprops
.memlimit_inactive_attr
&= ~(uint32_t)MEMORYSTATUS_MEMLIMIT_ATTR_FATAL
;
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"));
141 err
= memorystatus_control(MEMORYSTATUS_CMD_SET_MEMLIMIT_PROPERTIES
, pid
, 0, &mmprops
, sizeof(mmprops
));
144 T_ASSERT_POSIX_SUCCESS(err
, "MEMORYSTATUS_CMD_SET_MEMLIMIT_PROPERTIES failed");
149 get_priority_props(pid_t pid
, boolean_t verbose
, int32_t *priority
, int32_t *limit_mb
, uint64_t *user_data
, uint32_t *state
)
151 memorystatus_priority_entry_t entry
= {0};
153 int size
= memorystatus_control(MEMORYSTATUS_CMD_GET_PRIORITY_LIST
, pid
, 0, &entry
, sizeof(entry
));
155 /* validate size returned */
157 T_ASSERT_FAIL("get_priority: can't get list size: %d!\n", size
);
160 if (size
!= sizeof(entry
)) {
161 T_ASSERT_FAIL("get_priority: returned unexpected entry size\n");
164 if (entry
.pid
!= pid
) {
165 T_ASSERT_FAIL("get_priority: returned unexpected entry pid\n");
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
);
173 log_state(entry
.state
);
177 *priority
= entry
.priority
;
180 *limit_mb
= entry
.limit
;
183 *user_data
= entry
.user_data
;
186 *state
= entry
.state
;
193 verify_assertion_state(uint32_t state
, boolean_t expected_assertion_state
)
195 boolean_t actual_assertion_state
;
197 char *expected_string
;
199 if (expected_assertion_state
== ASSERTION_STATE_IS_SET
) {
200 expected_string
= "ASSERTION_STATE_IS_SET";
202 expected_string
= "ASSERTION_STATE_IS_RELINQUISHED";
205 if (state
& kMemorystatusAssertion
) {
207 * An assertion driven jetsam priority is at play.
209 actual_assertion_state
= ASSERTION_STATE_IS_SET
;
210 actual_string
= "ASSERTION_STATE_IS_SET";
213 * There is no assertion driven jetsam priority in place.
215 actual_assertion_state
= ASSERTION_STATE_IS_RELINQUISHED
;
216 actual_string
= "ASSERTION_STATE_IS_RELINQUISHED";
219 if (actual_assertion_state
== expected_assertion_state
) {
220 T_PASS("%s as expected", expected_string
);
223 T_FAIL("state 0x%x: %s but expected %s", state
, actual_string
, expected_string
);
225 return false; /* failed */
230 log_state(uint32_t state
)
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"));