1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <errno.h>
5 #include <string.h>
6 #include <assert.h>
7 #include <signal.h>
8 #include <spawn.h>
9 #include <spawn_private.h>
10 #include <stdint.h>
11 #include <sys/sysctl.h>
12 #include <sys/spawn_internal.h>
13 #include <sys/kern_memorystatus.h>
14 #include <mach-o/dyld.h>
15
16 #include <darwintest.h>
17 #include <darwintest_utils.h>
18
19 #include "memorystatus_assertion_helpers.h"
20
21 T_GLOBAL_META(
22 T_META_NAMESPACE("xnu.vm"),
23 T_META_RADAR_COMPONENT_NAME("xnu"),
24 T_META_RADAR_COMPONENT_VERSION("VM"),
25 T_META_CHECK_LEAKS(false)
26 );
27
28 extern char **environ;
29
30 /*
31 * This test has multiple sub-tests that set and then verify jetsam priority transitions
32 * as though they were driven by assertions. It uses the MEMORYSTATUS_CMD_SET_MEMLIMIT_PROPERTIES
33 * version of the memorystatus_control() system call and specifically tests the use of the
34 * MEMORYSTATUS_SET_PRIORITY_ASSERTION flag.
35 *
36 * The kernel will apply policy that chooses a maximum jetsam priority, resolving conflicts
37 * between an assertion driven priority and clean/dirty transition policy.
38 *
39 * Processes that do not opt into dirty-tracking should behave as they always have.
40 * This is the typical App transition behavior.
41 *
42 * Processes that do opt into dirty-tracking have more complex policy:
43 * For example:
44 * A MAX assertion priority will prevent a dirty process from transitioning to a clean
45 * state if the process opts into idle-exit.
46 * See: memorystatus_schedule_idle_demotion_locked() where we note that
47 * the process isn't going to be making the trip to the lower bands.
48 *
49 * But a MAX assertion evaluation will not prevent a clean process from transition to dirty.
50 * Assertion driven priorities should not change memory limits, they are expected to
51 * just change a process's position in the jetsam priority bands.
52 *
53 * MEMORYSTATUS_CMD_xxx requires root (in the absence of entitlement).
54 * Use T_META_ASROOT(true) to accomplish this.
55 *
56 * A note on test strategy. It is not necessary to spawn a child to test these
57 * assertion calls. The test can act on itself, that is, it can make calls to
58 * set and relinquish assertion state just like it can make calls to do dirty/clean
59 * transitions. Of course, in reality, we expect only runningboardd to manipulate
60 * assertion based priorities.
61 */
62
63 /*
64 * New flag to tell kernel this is an assertion driven priority update.
65 */
66 #ifndef MEMORYSTATUS_SET_PRIORITY_ASSERTION
67 #define MEMORYSTATUS_SET_PRIORITY_ASSERTION 0x1
68 #endif
69
70 static void
proc_will_set_clean(pid_t pid)71 proc_will_set_clean(pid_t pid)
72 {
73 proc_set_dirty(pid, false);
74 T_LOG("pid[%d] --> now clean", pid);
75 return;
76 }
77
78 static void
proc_will_set_dirty(pid_t pid)79 proc_will_set_dirty(pid_t pid)
80 {
81 proc_set_dirty(pid, true);
82 T_LOG("pid[%d] --> now dirty", pid);
83 return;
84 }
85
86 #define kJetsamAgingPolicyNone (0)
87 #define kJetsamAgingPolicyLegacy (1)
88 #define kJetsamAgingPolicySysProcsReclaimedFirst (2)
89 #define kJetsamAgingPolicyAppsReclaimedFirst (3)
90 #define kJetsamAgingPolicyMax kJetsamAgingPolicyAppsReclaimedFirst
91
92 #ifndef kMemorystatusAssertion
93 #define kMemorystatusAssertion 0x40
94 #endif
95
96 /*
97 * Make repetitive (eg: back-to-back) calls using MEMORYSTATUS_SET_PRIORITY_ASSERTION.
98 * We know that runningboardd may try to relinquish its hold on an assertion priority
99 * when it hasn't first set the assertion priority. The kernel must survive this
100 * pattern even though it might be considered poor behavior on runningboardd's part.
101 * When dirty tracking processes are involved, we are exercising the kernel's
102 * idle-deferred paths. Only assertion state (whether or not assertion state is
103 * set or relinquished) is verified in this round of tests.
104 * Test is invoked three times:
105 * Scenario 1) as a non-dirty-tracking process (like a typical app)
106 * relinquish assertion priority multiple times
107 * set same assertion priority multiple times.
108 * Scenario 2) setup a dirty-tracking process that is clean (like a typical extension)
109 * relinquish assertion priority multiple times
110 * set same assertion priority multiple times.
111 * Scenario 3) setup dirty-tracking process that is dirty (like a typical extension)
112 * relinquish assertion priority multiple times
113 * set same assertion priority multiple times.
114 */
115
116 static void
memorystatus_assertion_test_repetitive(char * test,boolean_t turn_on_dirty_tracking,boolean_t start_clean)117 memorystatus_assertion_test_repetitive(char *test, boolean_t turn_on_dirty_tracking, boolean_t start_clean)
118 {
119 int count;
120 int maxcount = 3;
121 boolean_t verbose;
122 uint32_t state;
123 uint64_t user_data = 0;
124 pid_t mypid = getpid();
125
126 /* these values will remain fixed during testing */
127 int active_limit_mb = 35; /* arbitrary */
128 int inactive_limit_mb = 25; /* arbitrary */
129
130 /* these values may vary during test */
131 int requestedpriority = 0;
132 int assertionpriority = 0;
133
134 T_SETUPBEGIN;
135
136 requestedpriority = JETSAM_PRIORITY_UI_SUPPORT;
137 assertionpriority = JETSAM_PRIORITY_FOREGROUND;
138 set_memlimits(mypid, active_limit_mb, inactive_limit_mb, true, true);
139 set_priority(mypid, requestedpriority, 0, false);
140
141 if (turn_on_dirty_tracking) {
142 proc_track_dirty(mypid, (PROC_DIRTY_TRACK | PROC_DIRTY_ALLOW_IDLE_EXIT | PROC_DIRTY_DEFER));
143
144 if (start_clean) {
145 proc_will_set_clean(mypid);
146 } else {
147 proc_will_set_dirty(mypid);
148 }
149 } else {
150 /*
151 * Do nothing.
152 * Acts like an app with no dirty tracking
153 * By default launches in the requested priority and is
154 * considered idle because it's below FG band.
155 */
156 }
157
158
159 verbose = false;
160 (void)get_priority_props(mypid, verbose, NULL, NULL, NULL, NULL);
161
162 /* log current setup state */
163 T_LOG("SETUP STATE COMPLETE: Test %s", test);
164
165 T_SETUPEND;
166
167 int i;
168 boolean_t ret;
169 for (i = 0; i < 2; i++) {
170 if (i == 1 && turn_on_dirty_tracking) {
171 T_LOG("Avoid idle-deferred - sleeping for 20");
172 sleep(20);
173
174 if (start_clean) {
175 proc_will_set_dirty(mypid);
176 } else {
177 proc_will_set_clean(mypid);
178 }
179
180 (void)get_priority_props(mypid, verbose, NULL, NULL, NULL, &state);
181 }
182
183 /*
184 * Relinquish assertion priority even though we don't
185 * currently hold an assertion priority.
186 */
187 for (count = 0; count < maxcount; count++) {
188 if (relinquish_assertion_priority(mypid, user_data)) {
189 T_ASSERT_FAIL("relinquish_assertion_priority failed");
190 }
191 }
192
193 /* Verify assertion state is relinquished */
194 (void)get_priority_props(mypid, verbose, NULL, NULL, NULL, &state);
195
196 ret = verify_assertion_state(state, ASSERTION_STATE_IS_RELINQUISHED);
197 T_QUIET;
198 T_ASSERT_TRUE(ret, "verify_assertion_state failed");
199
200
201
202 /*
203 * Set an assertion priority multiple times in a row.
204 */
205 for (count = 0; count < maxcount; count++) {
206 if (set_assertion_priority(mypid, assertionpriority, user_data) != 0) {
207 T_ASSERT_FAIL("set_assertion_priority failed");
208 }
209 }
210
211 /* Verify state holds an assertion priority */
212 (void)get_priority_props(mypid, verbose, NULL, NULL, NULL, &state);
213
214 ret = verify_assertion_state(state, ASSERTION_STATE_IS_SET);
215 T_QUIET;
216 T_ASSERT_TRUE(ret, "verify_assertion_state failed");
217 }
218 }
219
220 /*
221 * Process is dirty tracking and opts into pressured exit.
222 */
223 static void
memorystatus_assertion_test_allow_idle_exit()224 memorystatus_assertion_test_allow_idle_exit()
225 {
226 pid_t mypid = getpid();
227
228 /* these values will remain fixed during testing */
229 int active_limit_mb = 35; /* arbitrary */
230 int inactive_limit_mb = 25; /* arbitrary */
231
232 /* these values may vary during test */
233 int requestedpriority = JETSAM_PRIORITY_UI_SUPPORT;
234
235 T_SETUPBEGIN;
236
237 set_memlimits(mypid, active_limit_mb, inactive_limit_mb, true, true);
238 set_priority(mypid, requestedpriority, 0, false);
239
240 proc_track_dirty(mypid, (PROC_DIRTY_TRACK | PROC_DIRTY_ALLOW_IDLE_EXIT | PROC_DIRTY_DEFER));
241
242 proc_will_set_clean(mypid);
243
244 (void)check_properties(mypid, JETSAM_PRIORITY_IDLE_DEFERRED, inactive_limit_mb, 0x0, ASSERTION_STATE_IS_RELINQUISHED, "Clean start");
245
246 T_LOG("SETUP STATE COMPLETE");
247
248 int g_jetsam_aging_policy = 0;
249 /*
250 * Jetsam aging policy
251 * Failure to retrieve is not fatal.
252 */
253 size_t size = sizeof(g_jetsam_aging_policy);
254 if (sysctlbyname("kern.jetsam_aging_policy", &g_jetsam_aging_policy, &size, NULL, 0) != 0) {
255 T_LOG(__func__, true, "Unable to retrieve jetsam aging policy (not fatal)");
256 }
257
258 T_SETUPEND;
259
260 /*
261 * Relinquish assertion priority even though we don't hold it. No change in state expected.
262 */
263 T_LOG("********Test0 clean: no state change on relinquish");
264 relinquish_assertion_priority(mypid, 0xF00D);
265 (void)check_properties(mypid, JETSAM_PRIORITY_IDLE_DEFERRED, inactive_limit_mb, 0xF00D, ASSERTION_STATE_IS_RELINQUISHED, "Test0");
266
267 T_LOG("********Test1 clean: deferred now assertion[10]");
268 set_assertion_priority(mypid, JETSAM_PRIORITY_FOREGROUND, 0xFEED);
269 (void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, inactive_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test1");
270
271 /* Test2 */
272 T_LOG("********Test2 clean: assertion[10 -> 3]");
273 set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFACE);
274 (void)check_properties(mypid, JETSAM_PRIORITY_BACKGROUND, inactive_limit_mb, 0xFACE, ASSERTION_STATE_IS_SET, "Test2");
275
276 /* Test3 */
277 T_LOG("********Test3 clean: assertion[3 -> 0], but now deferred");
278 relinquish_assertion_priority(mypid, 0xBEEF);
279 (void)check_properties(mypid, JETSAM_PRIORITY_IDLE_DEFERRED, inactive_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test3");
280
281 /* Test4 */
282 T_LOG("********Test4 clean: deferred now assertion[10]");
283 set_assertion_priority(mypid, JETSAM_PRIORITY_FOREGROUND, 0xFEED);
284 (void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, inactive_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test4");
285
286 T_LOG("Avoid idle-deferred moving forward. Sleeping for 20");
287 sleep(20);
288
289 /* Test5 */
290 T_LOG("********Test5 dirty: set dirty priority but assertion[10] prevails");
291 proc_will_set_dirty(mypid); /* active priority is less than FG*/
292 (void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test5");
293
294 /* Test6 */
295 T_LOG("********Test6 dirty: assertion[10 -> 3] but dirty priority prevails");
296 set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFEEB); /* active priority is > BG */
297 (void)check_properties(mypid, JETSAM_PRIORITY_UI_SUPPORT, active_limit_mb, 0xFEEB, ASSERTION_STATE_IS_SET, "Test6");
298
299 /* Test7 */
300 T_LOG("********Test7 dirty: assertion[3 -> 0] but dirty prevails");
301 relinquish_assertion_priority(mypid, 0xBEEF);
302 (void)check_properties(mypid, JETSAM_PRIORITY_UI_SUPPORT, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test7");
303
304
305 /* Test8 */
306 T_LOG("********Test8 dirty: assertion[0 -> 10] overrides dirty");
307 set_assertion_priority(mypid, JETSAM_PRIORITY_FOREGROUND, 0xFEED);
308 (void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test8");
309
310 /* Test9 */
311 T_LOG("********Test9 dirty wants to go clean, but clean state is prevented as assertion[10] prevails");
312 proc_will_set_clean(mypid);
313 (void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test9");
314
315 /* Test10 */
316 T_LOG("********Test10 dirty goes dirty and stays dirty, and assertion[10] prevails again");
317 proc_will_set_dirty(mypid);
318 (void)check_properties(mypid, JETSAM_PRIORITY_FOREGROUND, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test10");
319
320 /* Test11 */
321 T_LOG("********Test11 dirty: assertion[10 -> 3] but dirty prevails");
322 set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFACE);
323 (void)check_properties(mypid, JETSAM_PRIORITY_UI_SUPPORT, active_limit_mb, 0xFACE, ASSERTION_STATE_IS_SET, "Test11");
324
325 /* Test12 */
326 T_LOG("********Test12 dirty: assertion[3 -> 0] but dirty prevails");
327 relinquish_assertion_priority(mypid, 0xBEEF);
328 (void)check_properties(mypid, JETSAM_PRIORITY_UI_SUPPORT, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test12");
329
330
331 /* Test13 */
332 T_LOG("********Test13 dirty goes clean: both assertion[0] and clean");
333 proc_will_set_clean(mypid);
334 if (g_jetsam_aging_policy == kJetsamAgingPolicySysProcsReclaimedFirst) {
335 /* For sysproc aging policy the daemon should be at idle deferred and with an active memory limit */
336 (void)check_properties(mypid, JETSAM_PRIORITY_IDLE_DEFERRED, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test13");
337 } else {
338 /* For the legacy aging policy, daemon should be at idle band with inactive memory limit */
339 (void)check_properties(mypid, JETSAM_PRIORITY_IDLE, inactive_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test13");
340 }
341 }
342
343 /*
344 * Process is dirty tracking and does not opt into pressured exit.
345 * This test lives above Foreground. Assertions will have no affect
346 * except where the assertion priority bumps it above the requested priority.
347 */
348 static void
memorystatus_assertion_test_do_not_allow_idle_exit()349 memorystatus_assertion_test_do_not_allow_idle_exit()
350 {
351 pid_t mypid = getpid();
352
353 /* these values will remain fixed during testing */
354 int active_limit_mb = 35; /* arbitrary */
355 int inactive_limit_mb = 25; /* arbitrary */
356 int requestedpriority = JETSAM_PRIORITY_AUDIO_AND_ACCESSORY;
357
358 T_SETUPBEGIN;
359
360 set_memlimits(mypid, active_limit_mb, inactive_limit_mb, true, true);
361 set_priority(mypid, requestedpriority, 0, false);
362 proc_track_dirty(mypid, (PROC_DIRTY_TRACK));
363
364 proc_will_set_dirty(mypid);
365
366 (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, active_limit_mb, 0x0, ASSERTION_STATE_IS_RELINQUISHED, "Dirty start");
367
368 proc_will_set_clean(mypid);
369
370 (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0x0, ASSERTION_STATE_IS_RELINQUISHED, "Clean transition");
371
372 T_LOG("SETUP STATE COMPLETE");
373
374 T_SETUPEND;
375
376 /*
377 * Relinquish assertion priority even though we don't hold it. No change in state expected.
378 */
379
380
381 /* Test0 */
382 T_LOG("********Test0 clean: no state change on relinquish");
383 relinquish_assertion_priority(mypid, 0xF00D);
384 (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xF00D, ASSERTION_STATE_IS_RELINQUISHED, "Test0");
385
386 /* Test1 */
387 T_LOG("********Test1 clean: assertion[0 -> 10] but inactive priority prevails");
388 set_assertion_priority(mypid, JETSAM_PRIORITY_FOREGROUND, 0xFEED);
389 (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test1");
390
391 /* Test2 */
392 T_LOG("********Test2 clean: assertion[10 -> 3] but inactive priority prevails");
393 set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFACE);
394 (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xFACE, ASSERTION_STATE_IS_SET, "Test2");
395
396 /* Test3 */
397 T_LOG("********Test3 clean: assertion[3 -> 0], but inactive priority prevails");
398 relinquish_assertion_priority(mypid, 0xBEEF);
399 (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test3");
400
401 /* Test4 */
402 T_LOG("********Test4 go dirty: assertion[0] has no affect, active priority prevails");
403 proc_will_set_dirty(mypid);
404 (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test4");
405
406 /* Test5 */
407 T_LOG("********Test5 dirty: assertion[0 -> 10] active priority prevails");
408 set_assertion_priority(mypid, JETSAM_PRIORITY_FOREGROUND, 0xFEED);
409 (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test5");
410
411 /* Test6 */
412 T_LOG("********Test6 dirty: assertion[10 -> 3] active priority prevails");
413 set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFACE);
414 (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, active_limit_mb, 0xFACE, ASSERTION_STATE_IS_SET, "Test6");
415
416 /* Test 7 */
417 T_LOG("********Test7 dirty: assertion[3 -> 0], active priority prevails");
418 relinquish_assertion_priority(mypid, 0xBEEF);
419 (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, active_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test7");
420
421 /* Test8 */
422 T_LOG("********Test8 dirty: assertion[0 -> 19], dirty but now assertion[19] prevails");
423 set_assertion_priority(mypid, JETSAM_PRIORITY_CRITICAL, 0xFEED);
424 (void)check_properties(mypid, JETSAM_PRIORITY_CRITICAL, active_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test8");
425
426
427 /* Test9 */
428 T_LOG("********Test9 go clean: inactive priority but assertion[19] prevails");
429 proc_will_set_clean(mypid);
430 (void)check_properties(mypid, JETSAM_PRIORITY_CRITICAL, inactive_limit_mb, 0xFEED, ASSERTION_STATE_IS_SET, "Test9");
431
432 /* Test10 */
433 T_LOG("********Test10 clean: assertion[19 -> 3] inactive limit prevails");
434 set_assertion_priority(mypid, JETSAM_PRIORITY_BACKGROUND, 0xFACE);
435 (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xFACE, ASSERTION_STATE_IS_SET, "Test10");
436
437
438 /* Test11 */
439 T_LOG("********Test11 clean: assertion[3 -> 0] inactive priority still prevails");
440 relinquish_assertion_priority(mypid, 0xBEEF);
441 (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test11");
442
443 /* Test12 */
444 T_LOG("********Test12 dirty goes clean: both assertion[0] and clean");
445 proc_will_set_clean(mypid);
446 (void)check_properties(mypid, JETSAM_PRIORITY_AUDIO_AND_ACCESSORY, inactive_limit_mb, 0xBEEF, ASSERTION_STATE_IS_RELINQUISHED, "Test12");
447 }
448
449 T_DECL(assertion_test_bad_flags, "verify bad flag returns an error", T_META_TIMEOUT(30), T_META_ASROOT(true)) {
450 int err;
451 uint32_t flag = 0;
452
453 memorystatus_priority_properties_t mjp = { 0 };
454
455 mjp.priority = JETSAM_PRIORITY_FOREGROUND;
456 mjp.user_data = 0;
457
458 /*
459 * init a bad flag
460 */
461
462 flag = 0xf;
463
464 err = memorystatus_control(MEMORYSTATUS_CMD_SET_PRIORITY_PROPERTIES, getpid(), flag, &mjp, sizeof(mjp));
465
466 T_QUIET;
467 T_ASSERT_POSIX_FAILURE(err, EINVAL, "MEMORYSTATUS_CMD_SET_PRIORITY_PROPERTIES should fail with bad flags (err=%d)", err);
468 }
469
470 #if TARGET_OS_OSX
471 /*
472 * Idle band deferral, aka aging band/demotion, has been disabled on macOS till
473 * we do the daemon hygiene work on macOS to make sure that processes don't change
474 * their role after spawn e.g. apps opting into dirty-tracking/idle-exit.
475 * The following set of tests rely on PROC_DIRTY_DEFER, aka aging bands, for the tests.
476 */
477 #else /* TARGET_OS_OSX */
478
479 T_DECL(assertion_test_repetitive_non_dirty_tracking, "Scenario #1 - repetitive assertion priority on non-dirty-tracking process", T_META_TIMEOUT(60), T_META_ASROOT(true)) {
480 /*
481 * Verify back-to-back assertion calls set assertion state as expected.
482 * false --> non-dirty-tracking process (like a typical app)
483 * false --> clean/dirty does not apply here
484 */
485
486 memorystatus_assertion_test_repetitive("Scenario #1", false, false);
487 }
488
489 T_DECL(assertion_test_repetitive_dirty_tracking_clean, "Scenario #2 - repetitive assertion priority on clean dirty-tracking process", T_META_TIMEOUT(60), T_META_ASROOT(true)) {
490 /*
491 * Verify back-to-back assertion calls set assertion state as expected.
492 * true --> dirty-tracking process (like a typical extension/widget)
493 * true --> start clean / inactive
494 * This will exercise idle-deferred paths.
495 */
496 memorystatus_assertion_test_repetitive("Scenario #2", true, true);
497 }
498
499 T_DECL(assertion_test_repetitive_dirty_tracking_dirty, "Scenario #3 - repetitive assertion priority on dirty dirty-tracking processes", T_META_TIMEOUT(60), T_META_ASROOT(true)) {
500 /*
501 * Verify back-to-back assertion calls set assertion state as expected.
502 * true --> dirty-tracking process (like a typical extension/widget)
503 * false --> start dirty / active state
504 * This will exercise idle-deferred paths.
505 */
506 memorystatus_assertion_test_repetitive("Scenario #3", true, false);
507 }
508
509
510 T_DECL(assertion_test_allow_idle_exit, "set assertion priorities on process supporting idle exit", T_META_TIMEOUT(360), T_META_ASROOT(true)) {
511 memorystatus_assertion_test_allow_idle_exit();
512 }
513
514 T_DECL(assertion_test_do_not_allow_idle_exit, "set assertion priorities on process no idle exit allowed", T_META_TIMEOUT(360), T_META_ASROOT(true)) {
515 memorystatus_assertion_test_do_not_allow_idle_exit();
516 }
517 #endif /* TARGET_OS_OSX */
518