xref: /xnu-12377.61.12/bsd/kern/kern_memorystatus_internal.h (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8)
1 /*
2  * Copyright (c) 2006-2019 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  *
28  */
29 
30 #ifndef _KERN_MEMORYSTATUS_INTERNAL_H_
31 #define _KERN_MEMORYSTATUS_INTERNAL_H_
32 
33 /*
34  * Contains memorystatus subsystem definitions that are not
35  * exported outside of the memorystatus subsystem.
36  *
37  * For example, all of the mechanisms used by kern_memorystatus_policy.c
38  * should be defined in this header.
39  */
40 
41 #if BSD_KERNEL_PRIVATE
42 
43 #include <mach/boolean.h>
44 #include <stdbool.h>
45 #include <os/atomic_private.h>
46 #include <os/base.h>
47 #include <os/log.h>
48 #include <os/overflow.h>
49 #include <kern/locks.h>
50 #include <kern/sched_prim.h>
51 #include <sys/kern_memorystatus.h>
52 #include <sys/kernel_types.h>
53 #include <sys/proc.h>
54 #include <sys/proc_internal.h>
55 
56 #if CONFIG_FREEZE
57 #include <sys/kern_memorystatus_freeze.h>
58 #endif /* CONFIG_FREEZE */
59 
60 /*
61  * memorystatus subsystem globals
62  */
63 extern uint32_t memorystatus_available_pages;
64 #if CONFIG_JETSAM
65 extern bool jetsam_kill_on_low_swap;
66 #endif /* CONFIG_JETSAM */
67 extern bool kill_on_no_paging_space;
68 extern int block_corpses; /* counter to block new corpses if jetsam purges them */
69 extern int system_procs_aging_band;
70 extern int applications_aging_band;
71 /* the jetsam band which will contain P_MEMSTAT_FROZEN processes */
72 extern int memorystatus_freeze_jetsam_band;
73 #if CONFIG_FREEZE
74 extern unsigned int memorystatus_suspended_count;
75 #endif /* CONFIG_FREEZE */
76 extern uint64_t memorystatus_sysprocs_idle_delay_time;
77 extern uint64_t memorystatus_apps_idle_delay_time;
78 
79 /*
80  * TODO(jason): This should really be calculated dynamically by the zalloc
81  * subsystem before we do a zone map exhaustion kill. But the zone_gc
82  * logic is non-trivial, so for now it just sets this global.
83  */
84 extern _Atomic bool memorystatus_zone_map_is_exhausted;
85 /*
86  * TODO(jason): We should get rid of this global
87  * and have the memorystatus thread check for compressor space shortages
88  * itself. However, there are 3 async call sites remaining that require more work to get us there:
89  * 2 of them are in vm_swap_defragment. When it's about to swap in a segment, it checks if that
90  * will cause a compressor space shortage & pre-emptively triggers jetsam. vm_compressor_backing_store
91  * needs to keep track of in-flight swapins due to defrag so we can perform those checks
92  * in the memorystatus thread.
93  * The other is in no_paging_space_action. This is only on macOS right now, but will
94  * be needed on iPad when we run out of swap space. This should be a new kill
95  * reason and we need to add a new health check for it.
96  * We need to maintain the macOS behavior though that we kill no more than 1 process
97  * every 5 seconds.
98  */
99 extern _Atomic bool memorystatus_compressor_space_shortage;
100 /*
101  * TODO(jason): We should also get rid of this global
102  * and check for phantom cache pressure from the memorystatus
103  * thread. But first we need to fix the syncronization in
104  * vm_phantom_cache_check_pressure
105  */
106 extern _Atomic bool memorystatus_phantom_cache_pressure;
107 
108 extern _Atomic bool memorystatus_pageout_starved;
109 /*
110  * The actions that the memorystatus thread can perform
111  * when we're low on memory.
112  * See memorystatus_pick_action to see when each action is deployed.
113  */
114 OS_CLOSED_ENUM(memorystatus_action, uint32_t,
115     MEMORYSTATUS_KILL_HIWATER,     // Kill 1 highwatermark process
116     MEMORYSTATUS_KILL_AGGRESSIVE,     // Do aggressive jetsam
117     MEMORYSTATUS_KILL_TOP_PROCESS,     // Kill based on jetsam priority
118     MEMORYSTATUS_WAKE_SWAPPER,  // Wake up the swap thread
119     MEMORYSTATUS_PROCESS_SWAPIN_QUEUE, // Compact the swapin queue and move segments to the swapout queue
120     MEMORYSTATUS_KILL_SUSPENDED_SWAPPABLE, // Kill a suspended swap-eligible processes based on jetsam priority
121     MEMORYSTATUS_KILL_SWAPPABLE, // Kill a swap-eligible process (even if it's running)  based on jetsam priority
122     MEMORYSTATUS_KILL_IDLE, // Kill an idle process
123     MEMORYSTATUS_KILL_LONG_IDLE, // Kill a long-idle process (reaper)
124     MEMORYSTATUS_NO_PAGING_SPACE, // Perform a no-paging-space-action
125     MEMORYSTATUS_PURGE_CACHES, // Purge system memory caches (e.g. corpses, deferred reclaim memory)
126     MEMORYSTATUS_KILL_NONE,     // Do nothing
127     );
128 
129 __options_closed_decl(memstat_kill_options_t, uint8_t, {
130 	MEMSTAT_ONLY_SWAPPABBLE = 0x01,
131 	MEMSTAT_ONLY_LONG_IDLE  = 0x02,
132 	MEMSTAT_SORT_BUCKET     = 0x04,
133 });
134 
135 /*
136  * Structure to hold state for a jetsam thread.
137  * Typically there should be a single jetsam thread
138  * unless parallel jetsam is enabled.
139  */
140 typedef struct jetsam_state_s {
141 	bool                            inited; /* if the thread is initialized */
142 	bool                            limit_to_low_bands; /* limit kills to < JETSAM_PRIORITY_ELEVATED_INACTIVE */
143 	int                             index; /* jetsam thread index */
144 	thread_t                        thread; /* jetsam thread pointer */
145 	int                             jld_idle_kills; /*  idle jetsam kill counter for this session */
146 	uint32_t                        errors; /* Error accumulator */
147 	bool                            errors_cleared; /* Have we tried clearing all errors this iteration? */
148 	bool                            sort_flag; /* Sort the fg band (idle on macOS) before killing? */
149 	bool                            corpse_list_purged; /* Has the corpse list been purged? */
150 	bool                            bg_approached; /* Has the BG band been approached? */
151 	bool                            fg_approached; /* Has the FG band been approached? */
152 	bool                            post_snapshot; /* Do we need to post a jetsam snapshot after this session? */
153 	uint64_t                        memory_reclaimed; /* Amount of memory that was just reclaimed */
154 	uint32_t                        hwm_kills; /* hwm kill counter for this session */
155 	sched_cond_atomic_t             jt_wakeup_cond; /* condition var used to synchronize wake/sleep operations for this jetsam thread */
156 } *jetsam_state_t;
157 
158 /*
159  * The memorystatus thread monitors these conditions
160  * and will continue to act until the system is considered
161  * healthy.
162  */
163 typedef struct memorystatus_system_health_s {
164 #if CONFIG_JETSAM
165 	bool msh_available_pages_below_soft;
166 	bool msh_available_pages_below_idle;
167 	bool msh_available_pages_below_critical;
168 	bool msh_available_pages_below_reaper;
169 	bool msh_compressor_needs_to_swap;
170 	bool msh_compressor_is_thrashing;
171 	bool msh_filecache_is_thrashing;
172 	bool msh_phantom_cache_pressure;
173 	bool msh_swappable_compressor_segments_over_limit;
174 	bool msh_swapin_queue_over_limit;
175 	bool msh_pageout_starved;
176 #endif /* CONFIG_JETSAM */
177 	bool msh_vm_pressure_warning;
178 	bool msh_vm_pressure_critical;
179 	bool msh_compressor_low_on_space;
180 	bool msh_compressor_exhausted;
181 	bool msh_swap_exhausted;
182 	bool msh_swap_low_on_space;
183 	bool msh_zone_map_is_exhausted;
184 } *memorystatus_system_health_t;
185 
186 /*
187  * @func memstat_check_system_health
188  *
189  * @brief Evaluate system memory conditions and return if the system is healthy.
190  *
191  * @discussion
192  * Evaluates various system memory conditions, including compressor size and
193  * available page quantities. If conditions indicate a kill should be
194  * performed, the system is considered "unhealthy".
195  *
196  * @returns @c true if the system is healthy, @c false otherwise.
197  */
198 extern bool memstat_check_system_health(memorystatus_system_health_t status);
199 
200 #pragma mark Locks
201 
202 extern lck_mtx_t memorystatus_jetsam_broadcast_lock;
203 
204 #pragma mark Agressive jetsam tunables
205 
206 extern boolean_t memorystatus_jld_enabled;              /* Enable jetsam loop detection */
207 extern uint32_t memorystatus_jld_eval_period_msecs;         /* Init pass sets this based on device memory size */
208 extern int      memorystatus_jld_max_kill_loops;            /* How many times should we try and kill up to the target band */
209 extern unsigned int memorystatus_sysproc_aging_aggr_pages; /* Aggressive jetsam pages threshold for sysproc aging policy */
210 extern unsigned int jld_eval_aggressive_count;
211 extern uint64_t  jld_timestamp_msecs;
212 extern int       jld_idle_kill_candidates;
213 
214 #pragma mark No Paging Space Globals
215 
216 extern _Atomic uint64_t last_no_space_action_ts;
217 extern uint64_t no_paging_space_action_throttle_delay_ns;
218 
219 #pragma mark Pressure Response Globals
220 extern uint64_t memstat_last_cache_purge_ts;
221 extern uint64_t memstat_cache_purge_backoff_ns;
222 
223 __options_decl(memstat_pressure_options_t, uint32_t, {
224 	/* Kill long idle processes at kVMPressureWarning */
225 	MEMSTAT_WARNING_KILL_LONG_IDLE = 0x01,
226 	/* Kill idle processes from the notify thread at kVMPressureWarning */
227 	MEMSTAT_WARNING_KILL_IDLE_THROTTLED = 0x02,
228 	/* Purge memory caches (e.g. corpses, deferred reclaim rings) at kVMPressureCritical */
229 	MEMSTAT_CRITICAL_PURGE_CACHES = 0x04,
230 	/* Kill all idle processes at kVMPressureCritical */
231 	MEMSTAT_CRITICAL_KILL_IDLE = 0x08,
232 	/* Kill when at kVMPressureWarning for a prolonged period */
233 	MEMSTAT_WARNING_KILL_SUSTAINED = 0x10,
234 });
235 /* Maximum value for sysctl handler */
236 #define MEMSTAT_PRESSURE_CONFIG_MAX (0x18U)
237 
238 extern memstat_pressure_options_t memstat_pressure_config;
239 
240 #pragma mark Config Globals
241 extern boolean_t memstat_reaper_enabled;
242 
243 #pragma mark VM globals read by the memorystatus subsystem
244 
245 extern unsigned int    vm_page_free_count;
246 extern unsigned int    vm_page_active_count;
247 extern unsigned int    vm_page_inactive_count;
248 extern unsigned int    vm_page_throttled_count;
249 extern unsigned int    vm_page_purgeable_count;
250 extern unsigned int    vm_page_wire_count;
251 extern unsigned int    vm_page_speculative_count;
252 extern uint32_t        c_late_swapout_count, c_late_swappedin_count;
253 extern uint32_t        c_seg_allocsize;
254 extern bool            vm_swapout_thread_running;
255 extern _Atomic bool    vm_swapout_wake_pending;
256 #define VM_PAGE_DONATE_DISABLED     0
257 #define VM_PAGE_DONATE_ENABLED      1
258 extern uint32_t vm_page_donate_mode;
259 
260 #if CONFIG_JETSAM
261 #define MEMORYSTATUS_LOG_AVAILABLE_PAGES os_atomic_load(&memorystatus_available_pages, relaxed)
262 #else /* CONFIG_JETSAM */
263 #define MEMORYSTATUS_LOG_AVAILABLE_PAGES (vm_page_active_count + vm_page_inactive_count + vm_page_free_count + vm_page_speculative_count)
264 #endif /* CONFIG_JETSAM */
265 
266 bool memorystatus_avail_pages_below_pressure(void);
267 bool memorystatus_avail_pages_below_critical(void);
268 #if CONFIG_JETSAM
269 bool memorystatus_swap_over_trigger(uint64_t adjustment_factor);
270 bool memorystatus_swapin_over_trigger(void);
271 #endif /* CONFIG_JETSAM */
272 
273 /* Does cause indicate vm or fc thrashing? */
274 bool is_reason_thrashing(unsigned cause);
275 /* Is the zone map almost full? */
276 bool is_reason_zone_map_exhaustion(unsigned cause);
277 
278 memorystatus_action_t memorystatus_pick_action(jetsam_state_t state,
279     uint32_t *kill_cause, bool highwater_remaining,
280     bool suspended_swappable_apps_remaining,
281     bool swappable_apps_remaining, int *jld_idle_kills);
282 
283 #define MEMSTAT_PERCENT_TOTAL_PAGES(p) ((uint32_t)(p * atop_64(max_mem) / 100))
284 
285 /*
286  * Take a (redacted) zprint snapshot along with the jetsam snapshot.
287  */
288 #define JETSAM_ZPRINT_SNAPSHOT (CONFIG_MEMORYSTATUS && (DEBUG || DEVELOPMENT))
289 
290 #pragma mark Logging Utilities
291 
292 __enum_decl(memorystatus_log_level_t, unsigned int, {
293 	MEMORYSTATUS_LOG_LEVEL_DEFAULT = 0,
294 	MEMORYSTATUS_LOG_LEVEL_INFO = 1,
295 	MEMORYSTATUS_LOG_LEVEL_DEBUG = 2,
296 });
297 
298 extern os_log_t memorystatus_log_handle;
299 extern memorystatus_log_level_t memorystatus_log_level;
300 
301 /*
302  * NB: Critical memorystatus logs (e.g. jetsam kills) are load-bearing for OS
303  * performance testing infrastructure. Be careful when modifying the log-level for
304  * important system events.
305  *
306  * Memorystatus logs are interpreted by a wide audience. To avoid logging information
307  * that could lead to false diagnoses, INFO and DEBUG messages are only logged if the
308  * system has been configured to do so via `kern.memorystatus_log_level` (sysctl) or
309  * `memorystatus_log_level` (boot-arg).
310  *
311  * os_log supports a mechanism for configuring these properties dynamically; however,
312  * this mechanism is currently unsupported in XNU.
313  *
314  * TODO (JC) Deprecate sysctl/boot-arg and move to subsystem preferences pending:
315  *  - rdar://27006343 (Custom kernel log handles)
316  *  - rdar://80958044 (Kernel Logging Configuration)
317  */
318 #define _memorystatus_log_with_type(type, format, ...) os_log_with_startup_serial_and_type(memorystatus_log_handle, type, format, ##__VA_ARGS__)
319 #define memorystatus_log(format, ...) _memorystatus_log_with_type(OS_LOG_TYPE_DEFAULT, format, ##__VA_ARGS__)
320 #define memorystatus_log_info(format, ...) if (memorystatus_log_level >= MEMORYSTATUS_LOG_LEVEL_INFO) { _memorystatus_log_with_type(OS_LOG_TYPE_INFO, format, ##__VA_ARGS__); }
321 #define memorystatus_log_debug(format, ...) if (memorystatus_log_level >= MEMORYSTATUS_LOG_LEVEL_DEBUG) { _memorystatus_log_with_type(OS_LOG_TYPE_DEBUG, format, ##__VA_ARGS__); }
322 #define memorystatus_log_error(format, ...) _memorystatus_log_with_type(OS_LOG_TYPE_ERROR, format, ##__VA_ARGS__)
323 #define memorystatus_log_fault(format, ...) _memorystatus_log_with_type(OS_LOG_TYPE_FAULT, format, ##__VA_ARGS__)
324 
325 #pragma mark Jetsam Priority Management
326 
327 /*
328  * Cancel a process' idle aging
329  * Returns whether a reschedule of the idle demotion thread is needed.
330  */
331 void memstat_update_priority_locked(proc_t p, int priority,
332     memstat_priority_options_t options);
333 
334 static inline bool
_memstat_proc_is_aging(proc_t p)335 _memstat_proc_is_aging(proc_t p)
336 {
337 	return p->p_memstat_dirty & P_DIRTY_AGING_IN_PROGRESS;
338 }
339 
340 static inline bool
_memstat_proc_is_tracked(proc_t p)341 _memstat_proc_is_tracked(proc_t p)
342 {
343 	return p->p_memstat_dirty & P_DIRTY_TRACK;
344 }
345 
346 static inline bool
_memstat_proc_is_dirty(proc_t p)347 _memstat_proc_is_dirty(proc_t p)
348 {
349 	return p->p_memstat_dirty & P_DIRTY_IS_DIRTY;
350 }
351 
352 /*
353  * Return true if this process is self-terminating via ActivityTracking.
354  */
355 static inline bool
_memstat_proc_is_terminating(proc_t p)356 _memstat_proc_is_terminating(proc_t p)
357 {
358 	return p->p_memstat_dirty & P_DIRTY_TERMINATED;
359 }
360 
361 /*
362  * Return true if this process has been killed and is in the process of exiting.
363  */
364 static inline bool
_memstat_proc_was_killed(proc_t p)365 _memstat_proc_was_killed(proc_t p)
366 {
367 	return p->p_memstat_state & P_MEMSTAT_TERMINATED;
368 }
369 
370 static inline bool
_memstat_proc_is_internal(proc_t p)371 _memstat_proc_is_internal(proc_t p)
372 {
373 	return p->p_memstat_state & P_MEMSTAT_INTERNAL;
374 }
375 
376 static inline bool
_memstat_proc_can_idle_exit(proc_t p)377 _memstat_proc_can_idle_exit(proc_t p)
378 {
379 	return _memstat_proc_is_tracked(p) &&
380 	       (p->p_memstat_dirty & P_DIRTY_ALLOW_IDLE_EXIT);
381 }
382 
383 static inline bool
_memstat_proc_shutdown_on_clean(proc_t p)384 _memstat_proc_shutdown_on_clean(proc_t p)
385 {
386 	return _memstat_proc_is_tracked(p) &&
387 	       (p->p_memstat_dirty & P_DIRTY_SHUTDOWN_ON_CLEAN);
388 }
389 
390 static inline bool
_memstat_proc_has_priority_assertion(proc_t p)391 _memstat_proc_has_priority_assertion(proc_t p)
392 {
393 	return p->p_memstat_state & P_MEMSTAT_PRIORITY_ASSERTION;
394 }
395 
396 static inline bool
_memstat_proc_is_managed(proc_t p)397 _memstat_proc_is_managed(proc_t p)
398 {
399 	return p->p_memstat_state & P_MEMSTAT_MANAGED;
400 }
401 
402 static inline bool
_memstat_proc_is_frozen(proc_t p)403 _memstat_proc_is_frozen(proc_t p)
404 {
405 	return p->p_memstat_state & P_MEMSTAT_FROZEN;
406 }
407 
408 static inline bool
_memstat_proc_is_suspended(proc_t p)409 _memstat_proc_is_suspended(proc_t p)
410 {
411 	return p->p_memstat_state & P_MEMSTAT_SUSPENDED;
412 }
413 
414 static inline void
_memstat_proc_set_suspended(proc_t p)415 _memstat_proc_set_suspended(proc_t p)
416 {
417 	LCK_MTX_ASSERT(&proc_list_mlock, LCK_ASSERT_OWNED);
418 	if (!_memstat_proc_is_suspended(p)) {
419 		p->p_memstat_state |= P_MEMSTAT_SUSPENDED;
420 #if CONFIG_FREEZE
421 		if (os_inc_overflow(&memorystatus_suspended_count)) {
422 			panic("Overflowed memorystatus_suspended_count");
423 		}
424 #endif /* CONFIG_FREEZE */
425 	}
426 }
427 
428 static inline void
_memstat_proc_set_resumed(proc_t p)429 _memstat_proc_set_resumed(proc_t p)
430 {
431 	LCK_MTX_ASSERT(&proc_list_mlock, LCK_ASSERT_OWNED);
432 	if (_memstat_proc_is_suspended(p)) {
433 		p->p_memstat_state &= ~P_MEMSTAT_SUSPENDED;
434 #if CONFIG_FREEZE
435 		if (os_dec_overflow(&memorystatus_suspended_count)) {
436 			panic("Underflowed memorystatus_suspended_count");
437 		}
438 #endif /* CONFIG_FREEZE */
439 	}
440 }
441 
442 /*
443  * Return whether the process is to be placed in an elevated band while idle.
444  */
445 static inline bool
_memstat_proc_is_elevated(proc_t p)446 _memstat_proc_is_elevated(proc_t p)
447 {
448 	return p->p_memstat_state & P_MEMSTAT_USE_ELEVATED_INACTIVE_BAND;
449 }
450 
451 /*
452  * Return whether p's ledger-enforced memlimit is fatal (as last cached by
453  * memorystatus)
454  */
455 static inline bool
_memstat_proc_cached_memlimit_is_fatal(proc_t p)456 _memstat_proc_cached_memlimit_is_fatal(proc_t p)
457 {
458 	return p->p_memstat_state & P_MEMSTAT_FATAL_MEMLIMIT;
459 }
460 
461 /*
462  * Return whether p's inactive/active memlimit is fatal
463  */
464 static inline bool
_memstat_proc_memlimit_is_fatal(proc_t p,bool is_active)465 _memstat_proc_memlimit_is_fatal(proc_t p, bool is_active)
466 {
467 	const uint32_t flag = is_active ?
468 	    P_MEMSTAT_MEMLIMIT_ACTIVE_FATAL : P_MEMSTAT_MEMLIMIT_INACTIVE_FATAL;
469 	return p->p_memstat_state & flag;
470 }
471 
472 static inline bool
_memstat_proc_active_memlimit_is_fatal(proc_t p)473 _memstat_proc_active_memlimit_is_fatal(proc_t p)
474 {
475 	return _memstat_proc_memlimit_is_fatal(p, true);
476 }
477 
478 static inline bool
_memstat_proc_inactive_memlimit_is_fatal(proc_t p)479 _memstat_proc_inactive_memlimit_is_fatal(proc_t p)
480 {
481 	return _memstat_proc_memlimit_is_fatal(p, false);
482 }
483 
484 #pragma mark Jetsam
485 
486 /*
487  * @func memstat_evaluate_page_shortage
488  *
489  * @brief
490  * Evaluate page shortage conditions. Returns true if the jetsam thread should be woken up.
491  *
492  * @param should_enforce_memlimits
493  * Set to true if soft memory limits should be enforced
494  *
495  * @param should_idle_exit
496  * Set to true if idle processes should begin exiting
497  *
498  * @param should_jetsam
499  * Set to true if non-idle processes should be jetsammed
500  *
501  * @param should_reap
502  * Set to true if long-idle processes should be jetsammed
503  */
504 bool memstat_evaluate_page_shortage(
505 	bool *should_enforce_memlimits,
506 	bool *should_idle_exit,
507 	bool *should_jetsam,
508 	bool *should_reap);
509 
510 /*
511  * In nautical applications, ballast tanks are tanks on boats or submarines
512  * which can be filled with water. When flooded, they provide stability and
513  * reduce buoyancy. When drained (and filled with air), they provide buoyancy.
514  *
515  * In our analogy, the ballast tanks may be drained of unneeded weight (as
516  * occupied by idle processes or processes who have exceeded their memory
517  * limit) and filled with air (available memory). Userspace may toggle between
518  * these two states (filled/drained) depending on system requirements. For
519  * example, drained ballast tanks (i.e. evelated available memory pools) may
520  * have benefits to power and latency. However, applications with large
521  * working sets may need to flood the ballast tanks (i.e. with
522  * anonymous/wired memory) to avoid issues like jetsam loops of daemons that it
523  * has IPC relationships with.
524  *
525  * Mechanically, "draining" the ballast tanks means applying a configurable
526  * offset to the idle and soft available page shortage thresholds. This offset
527  * is then removed when the policy is disengaged.
528  *
529  * The ballast mechanism is intended to be used over long time periods and the
530  * ballast_offset should be sustainable for general applications. If response to
531  * transient spikes in memory demand is desired, the clear-the-decks policy
532  * should be used instead.
533  *
534  * Clients may toggle this behavior via sysctl: kern.memorystatus.ballast_drained
535  */
536 int memorystatus_ballast_control(bool drain);
537 
538 /* Synchronously kill a process due to sustained memory pressure */
539 bool memorystatus_kill_on_sustained_pressure(void);
540 
541 /* Synchronously kill an idle process */
542 bool memstat_kill_idle_process(memorystatus_kill_cause_t cause,
543     uint64_t *footprint_out);
544 
545 /*
546  * Attempt to kill the specified pid with the given reason.
547  * Consumes a reference on the jetsam_reason.
548  */
549 bool memstat_kill_with_jetsam_reason_sync(pid_t pid, os_reason_t jetsam_reason);
550 
551 /* Count the number of processes at priority <= max_bucket_index */
552 uint32_t memstat_get_proccnt_upto_priority(uint32_t max_bucket_index);
553 
554 /*
555  * @func memstat_get_idle_proccnt
556  * @brief Return the number of idle processes which may be terminated.
557  */
558 uint32_t memstat_get_idle_proccnt(void);
559 
560 /*
561  * @func memstat_get_reapable_proccnt
562  * @brief Return the number of idle, reapable processes which may be terminated.
563  */
564 uint32_t memstat_get_long_idle_proccnt(void);
565 
566 #pragma mark Freezer
567 #if CONFIG_FREEZE
568 /*
569  * Freezer data types
570  */
571 
572 /* An ordered list of freeze or demotion candidates */
573 struct memorystatus_freezer_candidate_list {
574 	memorystatus_properties_freeze_entry_v1 *mfcl_list;
575 	size_t mfcl_length;
576 };
577 
578 struct memorystatus_freeze_list_iterator {
579 	bool refreeze_only;
580 	proc_t last_p;
581 	size_t global_freeze_list_index;
582 };
583 
584 /*
585  * Freezer globals
586  */
587 extern struct memorystatus_freezer_stats_t memorystatus_freezer_stats;
588 extern int memorystatus_freezer_use_ordered_list;
589 extern struct memorystatus_freezer_candidate_list memorystatus_global_freeze_list;
590 extern struct memorystatus_freezer_candidate_list memorystatus_global_demote_list;
591 extern uint64_t memorystatus_freezer_thread_next_run_ts;
592 bool memorystatus_is_process_eligible_for_freeze(proc_t p);
593 bool memorystatus_freeze_proc_is_refreeze_eligible(proc_t p);
594 
595 proc_t memorystatus_freezer_candidate_list_get_proc(
596 	struct memorystatus_freezer_candidate_list *list,
597 	size_t index,
598 	uint64_t *pid_mismatch_counter);
599 /*
600  * Returns the leader of the p's jetsam coalition
601  * and the role of p in that coalition.
602  */
603 proc_t memorystatus_get_coalition_leader_and_role(proc_t p, int *role_in_coalition);
604 bool memorystatus_freeze_process_is_recommended(const proc_t p);
605 
606 /*
607  * Ordered iterator over all freeze candidates.
608  * The iterator should initially be zeroed out by the caller and
609  * can be zeroed out whenever the caller wishes to start from the beginning
610  * of the list again.
611  * Returns PROC_NULL when all candidates have been iterated over.
612  */
613 proc_t memorystatus_freeze_pick_process(struct memorystatus_freeze_list_iterator *iterator);
614 
615 /*
616  * Returns the number of processes that the freezer thread should try to freeze
617  * on this wakeup.
618  */
619 size_t memorystatus_pick_freeze_count_for_wakeup(void);
620 
621 /*
622  * Configure the freezer for app-based swap mode.
623  * Should be called at boot.
624  */
625 void memorystatus_freeze_configure_for_swap(void);
626 /*
627  * Undo memorystatus_freeze_configure_for_swap
628  */
629 void memorystatus_freeze_disable_swap(void);
630 
631 /*
632  * Cache of pids of most-recently thawed processes.
633  * Used to reduce excessive rapid thaw/refreeze cycles.
634  */
635 void memorystatus_freeze_record_process_thawed(proc_t p);
636 bool memorystatus_freeze_was_process_recently_thawed(proc_t p);
637 extern boolean_t     memorystatus_freeze_prevent_refreeze_of_recently_thawed;
638 
639 #endif /* CONFIG_FREEZE */
640 
641 #endif /* BSD_KERNEL_PRIVATE */
642 
643 #endif /* _KERN_MEMORYSTATUS_INTERNAL_H_ */
644