2 * Copyright (c) 2006-2018 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
30 #include <kern/sched_prim.h>
31 #include <kern/kalloc.h>
32 #include <kern/assert.h>
33 #include <kern/debug.h>
34 #include <kern/locks.h>
35 #include <kern/task.h>
36 #include <kern/thread.h>
37 #include <kern/host.h>
38 #include <kern/policy_internal.h>
39 #include <kern/thread_group.h>
41 #include <IOKit/IOBSD.h>
43 #include <libkern/libkern.h>
44 #include <mach/coalition.h>
45 #include <mach/mach_time.h>
46 #include <mach/task.h>
47 #include <mach/host_priv.h>
48 #include <mach/mach_host.h>
50 #include <pexpert/pexpert.h>
51 #include <sys/coalition.h>
52 #include <sys/kern_event.h>
54 #include <sys/proc_info.h>
55 #include <sys/reason.h>
56 #include <sys/signal.h>
57 #include <sys/signalvar.h>
58 #include <sys/sysctl.h>
59 #include <sys/sysproto.h>
63 #include <vm/vm_pageout.h>
64 #include <vm/vm_protos.h>
65 #include <mach/machine/sdt.h>
66 #include <libkern/section_keywords.h>
67 #include <stdatomic.h>
70 #include <vm/vm_map.h>
71 #endif /* CONFIG_FREEZE */
73 #include <sys/kern_memorystatus.h>
74 #include <sys/kern_memorystatus_freeze.h>
75 #include <sys/kern_memorystatus_notify.h>
79 extern unsigned int memorystatus_available_pages
;
80 extern unsigned int memorystatus_available_pages_pressure
;
81 extern unsigned int memorystatus_available_pages_critical
;
82 extern unsigned int memorystatus_available_pages_critical_base
;
83 extern unsigned int memorystatus_available_pages_critical_idle_offset
;
85 #else /* CONFIG_JETSAM */
87 extern uint64_t memorystatus_available_pages
;
88 extern uint64_t memorystatus_available_pages_pressure
;
89 extern uint64_t memorystatus_available_pages_critical
;
91 #endif /* CONFIG_JETSAM */
93 unsigned int memorystatus_frozen_count
= 0;
94 unsigned int memorystatus_suspended_count
= 0;
95 unsigned long freeze_threshold_percentage
= 50;
99 lck_grp_attr_t
*freezer_lck_grp_attr
;
100 lck_grp_t
*freezer_lck_grp
;
101 static lck_mtx_t freezer_mutex
;
104 unsigned int memorystatus_freeze_threshold
= 0;
105 unsigned int memorystatus_freeze_pages_min
= 0;
106 unsigned int memorystatus_freeze_pages_max
= 0;
107 unsigned int memorystatus_freeze_suspended_threshold
= FREEZE_SUSPENDED_THRESHOLD_DEFAULT
;
108 unsigned int memorystatus_freeze_daily_mb_max
= FREEZE_DAILY_MB_MAX_DEFAULT
;
109 uint64_t memorystatus_freeze_budget_pages_remaining
= 0; //remaining # of pages that can be frozen to disk
110 boolean_t memorystatus_freeze_degradation
= FALSE
; //protected by the freezer mutex. Signals we are in a degraded freeze mode.
112 unsigned int memorystatus_max_frozen_demotions_daily
= 0;
113 unsigned int memorystatus_thaw_count_demotion_threshold
= 0;
115 boolean_t memorystatus_freeze_enabled
= FALSE
;
116 int memorystatus_freeze_wakeup
= 0;
117 int memorystatus_freeze_jetsam_band
= 0; /* the jetsam band which will contain P_MEMSTAT_FROZEN processes */
119 #define MAX_XPC_SERVICE_PIDS 10 /* Max. # of XPC services per coalition we'll consider freezing. */
121 #ifdef XNU_KERNEL_PRIVATE
123 unsigned int memorystatus_frozen_processes_max
= 0;
124 unsigned int memorystatus_frozen_shared_mb
= 0;
125 unsigned int memorystatus_frozen_shared_mb_max
= 0;
126 unsigned int memorystatus_freeze_shared_mb_per_process_max
= 0; /* Max. MB allowed per process to be freezer-eligible. */
127 unsigned int memorystatus_freeze_private_shared_pages_ratio
= 2; /* Ratio of private:shared pages for a process to be freezer-eligible. */
128 unsigned int memorystatus_thaw_count
= 0;
129 unsigned int memorystatus_refreeze_eligible_count
= 0; /* # of processes currently thawed i.e. have state on disk & in-memory */
131 #endif /* XNU_KERNEL_PRIVATE */
133 static inline boolean_t
memorystatus_can_freeze_processes(void);
134 static boolean_t
memorystatus_can_freeze(boolean_t
*memorystatus_freeze_swap_low
);
135 static boolean_t
memorystatus_is_process_eligible_for_freeze(proc_t p
);
136 static void memorystatus_freeze_thread(void *param __unused
, wait_result_t wr __unused
);
138 void memorystatus_disable_freeze(void);
141 static uint64_t memorystatus_freeze_pageouts
= 0;
144 #define DEGRADED_WINDOW_MINS (30)
145 #define NORMAL_WINDOW_MINS (24 * 60)
147 static throttle_interval_t throttle_intervals
[] = {
148 { DEGRADED_WINDOW_MINS
, 1, 0, 0, { 0, 0 }},
149 { NORMAL_WINDOW_MINS
, 1, 0, 0, { 0, 0 }},
151 throttle_interval_t
*degraded_throttle_window
= &throttle_intervals
[0];
152 throttle_interval_t
*normal_throttle_window
= &throttle_intervals
[1];
154 extern uint64_t vm_swap_get_free_space(void);
155 extern boolean_t
vm_swap_max_budget(uint64_t *);
156 extern int i_coal_jetsam_get_taskrole(coalition_t coal
, task_t task
);
158 static void memorystatus_freeze_update_throttle(uint64_t *budget_pages_allowed
);
159 static void memorystatus_demote_frozen_processes(boolean_t force_one
);
161 static uint64_t memorystatus_freezer_thread_next_run_ts
= 0;
163 /* Sysctls needed for aggd stats */
165 SYSCTL_UINT(_kern
, OID_AUTO
, memorystatus_freeze_count
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &memorystatus_frozen_count
, 0, "");
166 SYSCTL_UINT(_kern
, OID_AUTO
, memorystatus_thaw_count
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &memorystatus_thaw_count
, 0, "");
167 SYSCTL_QUAD(_kern
, OID_AUTO
, memorystatus_freeze_pageouts
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &memorystatus_freeze_pageouts
, "");
168 SYSCTL_QUAD(_kern
, OID_AUTO
, memorystatus_freeze_budget_pages_remaining
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &memorystatus_freeze_budget_pages_remaining
, "");
171 #if DEVELOPMENT || DEBUG
173 SYSCTL_UINT(_kern
, OID_AUTO
, memorystatus_freeze_jetsam_band
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &memorystatus_freeze_jetsam_band
, 0, "");
174 SYSCTL_UINT(_kern
, OID_AUTO
, memorystatus_freeze_daily_mb_max
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &memorystatus_freeze_daily_mb_max
, 0, "");
175 SYSCTL_UINT(_kern
, OID_AUTO
, memorystatus_freeze_degraded_mode
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &memorystatus_freeze_degradation
, 0, "");
176 SYSCTL_UINT(_kern
, OID_AUTO
, memorystatus_freeze_threshold
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &memorystatus_freeze_threshold
, 0, "");
177 SYSCTL_UINT(_kern
, OID_AUTO
, memorystatus_freeze_pages_min
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &memorystatus_freeze_pages_min
, 0, "");
178 SYSCTL_UINT(_kern
, OID_AUTO
, memorystatus_freeze_pages_max
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &memorystatus_freeze_pages_max
, 0, "");
179 SYSCTL_UINT(_kern
, OID_AUTO
, memorystatus_refreeze_eligible_count
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &memorystatus_refreeze_eligible_count
, 0, "");
180 SYSCTL_UINT(_kern
, OID_AUTO
, memorystatus_freeze_processes_max
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &memorystatus_frozen_processes_max
, 0, "");
183 * Max. shared-anonymous memory in MB that can be held by frozen processes in the high jetsam band.
184 * "0" means no limit.
185 * Default is 10% of system-wide task limit.
188 SYSCTL_UINT(_kern
, OID_AUTO
, memorystatus_freeze_shared_mb_max
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &memorystatus_frozen_shared_mb_max
, 0, "");
189 SYSCTL_UINT(_kern
, OID_AUTO
, memorystatus_freeze_shared_mb
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &memorystatus_frozen_shared_mb
, 0, "");
191 SYSCTL_UINT(_kern
, OID_AUTO
, memorystatus_freeze_shared_mb_per_process_max
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &memorystatus_freeze_shared_mb_per_process_max
, 0, "");
192 SYSCTL_UINT(_kern
, OID_AUTO
, memorystatus_freeze_private_shared_pages_ratio
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &memorystatus_freeze_private_shared_pages_ratio
, 0, "");
194 SYSCTL_UINT(_kern
, OID_AUTO
, memorystatus_freeze_min_processes
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &memorystatus_freeze_suspended_threshold
, 0, "");
197 * max. # of frozen process demotions we will allow in our daily cycle.
199 SYSCTL_UINT(_kern
, OID_AUTO
, memorystatus_max_freeze_demotions_daily
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &memorystatus_max_frozen_demotions_daily
, 0, "");
201 * min # of thaws needed by a process to protect it from getting demoted into the IDLE band.
203 SYSCTL_UINT(_kern
, OID_AUTO
, memorystatus_thaw_count_demotion_threshold
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &memorystatus_thaw_count_demotion_threshold
, 0, "");
205 boolean_t memorystatus_freeze_throttle_enabled
= TRUE
;
206 SYSCTL_UINT(_kern
, OID_AUTO
, memorystatus_freeze_throttle_enabled
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &memorystatus_freeze_throttle_enabled
, 0, "");
209 * When set to true, this keeps frozen processes in the compressor pool in memory, instead of swapping them out to disk.
210 * Exposed via the sysctl kern.memorystatus_freeze_to_memory.
212 boolean_t memorystatus_freeze_to_memory
= FALSE
;
213 SYSCTL_UINT(_kern
, OID_AUTO
, memorystatus_freeze_to_memory
, CTLFLAG_RW
| CTLFLAG_LOCKED
, &memorystatus_freeze_to_memory
, 0, "");
215 #define VM_PAGES_FOR_ALL_PROCS (2)
217 * Manual trigger of freeze and thaw for dev / debug kernels only.
220 sysctl_memorystatus_freeze SYSCTL_HANDLER_ARGS
222 #pragma unused(arg1, arg2)
225 int freezer_error_code
= 0;
226 pid_t pid_list
[MAX_XPC_SERVICE_PIDS
];
228 coalition_t coal
= COALITION_NULL
;
230 if (memorystatus_freeze_enabled
== FALSE
) {
231 printf("sysctl_freeze: Freeze is DISABLED\n");
235 error
= sysctl_handle_int(oidp
, &pid
, 0, req
);
236 if (error
|| !req
->newptr
) {
240 if (pid
== VM_PAGES_FOR_ALL_PROCS
) {
241 vm_pageout_anonymous_pages();
246 lck_mtx_lock(&freezer_mutex
);
251 uint32_t purgeable
, wired
, clean
, dirty
, shared
;
252 uint32_t max_pages
= 0, state
= 0;
254 if (VM_CONFIG_FREEZER_SWAP_IS_ACTIVE
) {
256 * Freezer backed by the compressor and swap file(s)
257 * will hold compressed data.
259 * Set the sysctl kern.memorystatus_freeze_to_memory to true to keep compressed data from
260 * being swapped out to disk. Note that this disables freezer swap support globally,
261 * not just for the process being frozen.
264 * We don't care about the global freezer budget or the process's (min/max) budget here.
265 * The freeze sysctl is meant to force-freeze a process.
267 * We also don't update any global or process stats on this path, so that the jetsam/ freeze
268 * logic remains unaffected. The tasks we're performing here are: freeze the process, set the
269 * P_MEMSTAT_FROZEN bit, and elevate the process to a higher band (if the freezer is active).
271 max_pages
= memorystatus_freeze_pages_max
;
274 * We only have the compressor without any swap.
276 max_pages
= UINT32_MAX
- 1;
280 state
= p
->p_memstat_state
;
284 * The jetsam path also verifies that the process is a suspended App. We don't care about that here.
285 * We simply ensure that jetsam is not already working on the process and that the process has not
286 * explicitly disabled freezing.
288 if (state
& (P_MEMSTAT_TERMINATED
| P_MEMSTAT_LOCKED
| P_MEMSTAT_FREEZE_DISABLED
)) {
289 printf("sysctl_freeze: p_memstat_state check failed, process is%s%s%s\n",
290 (state
& P_MEMSTAT_TERMINATED
) ? " terminated" : "",
291 (state
& P_MEMSTAT_LOCKED
) ? " locked" : "",
292 (state
& P_MEMSTAT_FREEZE_DISABLED
) ? " unfreezable" : "");
295 lck_mtx_unlock(&freezer_mutex
);
299 error
= task_freeze(p
->task
, &purgeable
, &wired
, &clean
, &dirty
, max_pages
, &shared
, &freezer_error_code
, FALSE
/* eval only */);
303 if (freezer_error_code
== FREEZER_ERROR_EXCESS_SHARED_MEMORY
) {
304 strlcpy(reason
, "too much shared memory", 128);
307 if (freezer_error_code
== FREEZER_ERROR_LOW_PRIVATE_SHARED_RATIO
) {
308 strlcpy(reason
, "low private-shared pages ratio", 128);
311 if (freezer_error_code
== FREEZER_ERROR_NO_COMPRESSOR_SPACE
) {
312 strlcpy(reason
, "no compressor space", 128);
315 if (freezer_error_code
== FREEZER_ERROR_NO_SWAP_SPACE
) {
316 strlcpy(reason
, "no swap space", 128);
319 printf("sysctl_freeze: task_freeze failed: %s\n", reason
);
321 if (error
== KERN_NO_SPACE
) {
322 /* Make it easy to distinguish between failures due to low compressor/ swap space and other failures. */
329 if ((p
->p_memstat_state
& P_MEMSTAT_FROZEN
) == 0) {
330 p
->p_memstat_state
|= P_MEMSTAT_FROZEN
;
331 memorystatus_frozen_count
++;
333 p
->p_memstat_frozen_count
++;
338 if (VM_CONFIG_FREEZER_SWAP_IS_ACTIVE
) {
340 * We elevate only if we are going to swap out the data.
342 error
= memorystatus_update_inactive_jetsam_priority_band(pid
, MEMORYSTATUS_CMD_ELEVATED_INACTIVEJETSAMPRIORITY_ENABLE
,
343 memorystatus_freeze_jetsam_band
, TRUE
);
346 printf("sysctl_freeze: Elevating frozen process to higher jetsam band failed with %d\n", error
);
351 if ((error
== 0) && (coal
== NULL
)) {
353 * We froze a process and so we check to see if it was
354 * a coalition leader and if it has XPC services that
355 * might need freezing.
356 * Only one leader can be frozen at a time and so we shouldn't
357 * enter this block more than once per call. Hence the
358 * check that 'coal' has to be NULL. We should make this an
359 * assert() or panic() once we have a much more concrete way
360 * to detect an app vs a daemon.
363 task_t curr_task
= NULL
;
365 curr_task
= proc_task(p
);
366 coal
= task_get_coalition(curr_task
, COALITION_TYPE_JETSAM
);
367 if (coalition_is_leader(curr_task
, coal
)) {
368 ntasks
= coalition_get_pid_list(coal
, COALITION_ROLEMASK_XPC
,
369 COALITION_SORT_DEFAULT
, pid_list
, MAX_XPC_SERVICE_PIDS
);
371 if (ntasks
> MAX_XPC_SERVICE_PIDS
) {
372 ntasks
= MAX_XPC_SERVICE_PIDS
;
380 pid
= pid_list
[--ntasks
];
384 lck_mtx_unlock(&freezer_mutex
);
387 printf("sysctl_freeze: Invalid process\n");
391 lck_mtx_unlock(&freezer_mutex
);
395 SYSCTL_PROC(_kern
, OID_AUTO
, memorystatus_freeze
, CTLTYPE_INT
| CTLFLAG_WR
| CTLFLAG_LOCKED
| CTLFLAG_MASKED
,
396 0, 0, &sysctl_memorystatus_freeze
, "I", "");
399 * Manual trigger of agressive frozen demotion for dev / debug kernels only.
402 sysctl_memorystatus_demote_frozen_process SYSCTL_HANDLER_ARGS
404 #pragma unused(arg1, arg2, oidp, req)
405 memorystatus_demote_frozen_processes(false);
409 SYSCTL_PROC(_kern
, OID_AUTO
, memorystatus_demote_frozen_processes
, CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_LOCKED
| CTLFLAG_MASKED
, 0, 0, &sysctl_memorystatus_demote_frozen_process
, "I", "");
412 sysctl_memorystatus_available_pages_thaw SYSCTL_HANDLER_ARGS
414 #pragma unused(arg1, arg2)
419 if (memorystatus_freeze_enabled
== FALSE
) {
423 error
= sysctl_handle_int(oidp
, &pid
, 0, req
);
424 if (error
|| !req
->newptr
) {
428 if (pid
== VM_PAGES_FOR_ALL_PROCS
) {
429 do_fastwake_warmup_all();
434 error
= task_thaw(p
->task
);
440 * task_thaw() succeeded.
442 * We increment memorystatus_frozen_count on the sysctl freeze path.
443 * And so we need the P_MEMSTAT_FROZEN to decrement the frozen count
444 * when this process exits.
447 * p->p_memstat_state &= ~P_MEMSTAT_FROZEN;
448 * proc_list_unlock();
459 SYSCTL_PROC(_kern
, OID_AUTO
, memorystatus_thaw
, CTLTYPE_INT
| CTLFLAG_WR
| CTLFLAG_LOCKED
| CTLFLAG_MASKED
,
460 0, 0, &sysctl_memorystatus_available_pages_thaw
, "I", "");
463 typedef struct _global_freezable_status
{
464 boolean_t freeze_pages_threshold_crossed
;
465 boolean_t freeze_eligible_procs_available
;
466 boolean_t freeze_scheduled_in_future
;
467 }global_freezable_status_t
;
469 typedef struct _proc_freezable_status
{
470 boolean_t freeze_has_memstat_state
;
471 boolean_t freeze_has_pages_min
;
472 int freeze_has_probability
;
473 int freeze_leader_eligible
;
474 boolean_t freeze_attempted
;
475 uint32_t p_memstat_state
;
477 int p_freeze_error_code
;
480 char p_name
[MAXCOMLEN
+ 1];
481 }proc_freezable_status_t
;
483 #define MAX_FREEZABLE_PROCESSES 200 /* Total # of processes in band 0 that we evaluate for freezability */
486 * For coalition based freezing evaluations, we proceed as follows:
487 * - detect that the process is a coalition member and a XPC service
488 * - mark its 'freeze_leader_eligible' field with FREEZE_PROC_LEADER_FREEZABLE_UNKNOWN
489 * - continue its freezability evaluation assuming its leader will be freezable too
491 * Once we are done evaluating all processes, we do a quick run thru all
492 * processes and for a coalition member XPC service we look up the 'freezable'
493 * status of its leader and iff:
494 * - the xpc service is freezable i.e. its individual freeze evaluation worked
495 * - and, its leader is also marked freezable
496 * we update its 'freeze_leader_eligible' to FREEZE_PROC_LEADER_FREEZABLE_SUCCESS.
499 #define FREEZE_PROC_LEADER_FREEZABLE_UNKNOWN (-1)
500 #define FREEZE_PROC_LEADER_FREEZABLE_SUCCESS (1)
501 #define FREEZE_PROC_LEADER_FREEZABLE_FAILURE (2)
504 memorystatus_freezer_get_status(user_addr_t buffer
, size_t buffer_size
, int32_t *retval
)
506 uint32_t proc_count
= 0, freeze_eligible_proc_considered
= 0, band
= 0, xpc_index
= 0, leader_index
= 0;
507 global_freezable_status_t
*list_head
;
508 proc_freezable_status_t
*list_entry
, *list_entry_start
;
509 size_t list_size
= 0;
510 proc_t p
, leader_proc
;
511 memstat_bucket_t
*bucket
;
512 uint32_t state
= 0, pages
= 0, entry_count
= 0;
513 boolean_t try_freeze
= TRUE
, xpc_skip_size_probability_check
= FALSE
;
514 int error
= 0, probability_of_use
= 0;
515 pid_t leader_pid
= 0;
518 if (VM_CONFIG_FREEZER_SWAP_IS_ACTIVE
== FALSE
) {
522 list_size
= sizeof(global_freezable_status_t
) + (sizeof(proc_freezable_status_t
) * MAX_FREEZABLE_PROCESSES
);
524 if (buffer_size
< list_size
) {
528 list_head
= (global_freezable_status_t
*)kalloc(list_size
);
529 if (list_head
== NULL
) {
533 memset(list_head
, 0, list_size
);
535 list_size
= sizeof(global_freezable_status_t
);
539 uint64_t curr_time
= mach_absolute_time();
541 list_head
->freeze_pages_threshold_crossed
= (memorystatus_available_pages
< memorystatus_freeze_threshold
);
542 list_head
->freeze_eligible_procs_available
= ((memorystatus_suspended_count
- memorystatus_frozen_count
) > memorystatus_freeze_suspended_threshold
);
543 list_head
->freeze_scheduled_in_future
= (curr_time
< memorystatus_freezer_thread_next_run_ts
);
545 list_entry_start
= (proc_freezable_status_t
*) ((uintptr_t)list_head
+ sizeof(global_freezable_status_t
));
546 list_entry
= list_entry_start
;
548 bucket
= &memstat_bucket
[JETSAM_PRIORITY_IDLE
];
550 entry_count
= (memorystatus_global_probabilities_size
/ sizeof(memorystatus_internal_probabilities_t
));
552 p
= memorystatus_get_first_proc_locked(&band
, FALSE
);
555 while ((proc_count
<= MAX_FREEZABLE_PROCESSES
) &&
557 (list_size
< buffer_size
)) {
560 * Daemon:- We will consider freezing it iff:
561 * - it belongs to a coalition and the leader is freeze-eligible (delayed evaluation)
562 * - its role in the coalition is XPC service.
564 * We skip memory size requirements in this case.
567 coalition_t coal
= COALITION_NULL
;
568 task_t leader_task
= NULL
, curr_task
= NULL
;
569 int task_role_in_coalition
= 0;
571 curr_task
= proc_task(p
);
572 coal
= task_get_coalition(curr_task
, COALITION_TYPE_JETSAM
);
574 if (coal
== COALITION_NULL
|| coalition_is_leader(curr_task
, coal
)) {
576 * By default, XPC services without an app
577 * will be the leader of their own single-member
580 goto skip_ineligible_xpc
;
583 leader_task
= coalition_get_leader(coal
);
584 if (leader_task
== TASK_NULL
) {
586 * This jetsam coalition is currently leader-less.
587 * This could happen if the app died, but XPC services
588 * have not yet exited.
590 goto skip_ineligible_xpc
;
593 leader_proc
= (proc_t
)get_bsdtask_info(leader_task
);
594 task_deallocate(leader_task
);
596 if (leader_proc
== PROC_NULL
) {
597 /* leader task is exiting */
598 goto skip_ineligible_xpc
;
601 task_role_in_coalition
= i_coal_jetsam_get_taskrole(coal
, curr_task
);
603 if (task_role_in_coalition
== COALITION_TASKROLE_XPC
) {
604 xpc_skip_size_probability_check
= TRUE
;
605 leader_pid
= leader_proc
->p_pid
;
610 p
= memorystatus_get_next_proc_locked(&band
, p
, FALSE
);
616 strlcpy(list_entry
->p_name
, p
->p_name
, MAXCOMLEN
+ 1);
618 list_entry
->p_pid
= p
->p_pid
;
620 state
= p
->p_memstat_state
;
622 if ((state
& (P_MEMSTAT_TERMINATED
| P_MEMSTAT_LOCKED
| P_MEMSTAT_FREEZE_DISABLED
| P_MEMSTAT_FREEZE_IGNORE
)) ||
623 !(state
& P_MEMSTAT_SUSPENDED
)) {
624 try_freeze
= list_entry
->freeze_has_memstat_state
= FALSE
;
626 try_freeze
= list_entry
->freeze_has_memstat_state
= TRUE
;
629 list_entry
->p_memstat_state
= state
;
631 if (xpc_skip_size_probability_check
== TRUE
) {
633 * Assuming the coalition leader is freezable
634 * we don't care re. minimum pages and probability
635 * as long as the process isn't marked P_MEMSTAT_FREEZE_DISABLED.
636 * XPC services have to be explicity opted-out of the disabled
637 * state. And we checked that state above.
639 list_entry
->freeze_has_pages_min
= TRUE
;
640 list_entry
->p_pages
= -1;
641 list_entry
->freeze_has_probability
= -1;
643 list_entry
->freeze_leader_eligible
= FREEZE_PROC_LEADER_FREEZABLE_UNKNOWN
;
644 list_entry
->p_leader_pid
= leader_pid
;
646 xpc_skip_size_probability_check
= FALSE
;
648 list_entry
->freeze_leader_eligible
= FREEZE_PROC_LEADER_FREEZABLE_SUCCESS
; /* Apps are freeze eligible and their own leaders. */
649 list_entry
->p_leader_pid
= 0; /* Setting this to 0 signifies this isn't a coalition driven freeze. */
651 memorystatus_get_task_page_counts(p
->task
, &pages
, NULL
, NULL
);
652 if (pages
< memorystatus_freeze_pages_min
) {
653 try_freeze
= list_entry
->freeze_has_pages_min
= FALSE
;
655 list_entry
->freeze_has_pages_min
= TRUE
;
658 list_entry
->p_pages
= pages
;
662 for (j
= 0; j
< entry_count
; j
++) {
663 if (strncmp(memorystatus_global_probabilities_table
[j
].proc_name
,
665 MAXCOMLEN
+ 1) == 0) {
666 probability_of_use
= memorystatus_global_probabilities_table
[j
].use_probability
;
671 list_entry
->freeze_has_probability
= probability_of_use
;
673 try_freeze
= ((probability_of_use
> 0) && try_freeze
);
675 list_entry
->freeze_has_probability
= -1;
680 uint32_t purgeable
, wired
, clean
, dirty
, shared
;
681 uint32_t max_pages
= 0;
682 int freezer_error_code
= 0;
684 error
= task_freeze(p
->task
, &purgeable
, &wired
, &clean
, &dirty
, max_pages
, &shared
, &freezer_error_code
, TRUE
/* eval only */);
687 list_entry
->p_freeze_error_code
= freezer_error_code
;
690 list_entry
->freeze_attempted
= TRUE
;
694 freeze_eligible_proc_considered
++;
696 list_size
+= sizeof(proc_freezable_status_t
);
698 p
= memorystatus_get_next_proc_locked(&band
, p
, FALSE
);
704 list_entry
= list_entry_start
;
706 for (xpc_index
= 0; xpc_index
< freeze_eligible_proc_considered
; xpc_index
++) {
707 if (list_entry
[xpc_index
].freeze_leader_eligible
== FREEZE_PROC_LEADER_FREEZABLE_UNKNOWN
) {
708 leader_pid
= list_entry
[xpc_index
].p_leader_pid
;
710 leader_proc
= proc_find(leader_pid
);
713 if (leader_proc
->p_memstat_state
& P_MEMSTAT_FROZEN
) {
715 * Leader has already been frozen.
717 list_entry
[xpc_index
].freeze_leader_eligible
= FREEZE_PROC_LEADER_FREEZABLE_SUCCESS
;
718 proc_rele(leader_proc
);
721 proc_rele(leader_proc
);
724 for (leader_index
= 0; leader_index
< freeze_eligible_proc_considered
; leader_index
++) {
725 if (list_entry
[leader_index
].p_pid
== leader_pid
) {
726 if (list_entry
[leader_index
].freeze_attempted
&& list_entry
[leader_index
].p_freeze_error_code
== 0) {
727 list_entry
[xpc_index
].freeze_leader_eligible
= FREEZE_PROC_LEADER_FREEZABLE_SUCCESS
;
729 list_entry
[xpc_index
].freeze_leader_eligible
= FREEZE_PROC_LEADER_FREEZABLE_FAILURE
;
730 list_entry
[xpc_index
].p_freeze_error_code
= FREEZER_ERROR_GENERIC
;
737 * Didn't find the leader entry. This might be likely because
738 * the leader never made it down to band 0.
740 if (leader_index
== freeze_eligible_proc_considered
) {
741 list_entry
[xpc_index
].freeze_leader_eligible
= FREEZE_PROC_LEADER_FREEZABLE_FAILURE
;
742 list_entry
[xpc_index
].p_freeze_error_code
= FREEZER_ERROR_GENERIC
;
747 buffer_size
= list_size
;
749 error
= copyout(list_head
, buffer
, buffer_size
);
751 *retval
= buffer_size
;
756 list_size
= sizeof(global_freezable_status_t
) + (sizeof(proc_freezable_status_t
) * MAX_FREEZABLE_PROCESSES
);
757 kfree(list_head
, list_size
);
759 MEMORYSTATUS_DEBUG(1, "memorystatus_freezer_get_status: returning %d (%lu - size)\n", error
, (unsigned long)*list_size
);
765 memorystatus_freezer_control(int32_t flags
, user_addr_t buffer
, size_t buffer_size
, int32_t *retval
)
769 if (flags
== FREEZER_CONTROL_GET_STATUS
) {
770 err
= memorystatus_freezer_get_status(buffer
, buffer_size
, retval
);
776 #endif /* DEVELOPMENT || DEBUG */
778 extern void vm_swap_consider_defragmenting(int);
779 extern boolean_t
memorystatus_kill_elevated_process(uint32_t, os_reason_t
, unsigned int, int, uint32_t *, uint64_t *);
782 * This routine will _jetsam_ all frozen processes
783 * and reclaim the swap space immediately.
785 * So freeze has to be DISABLED when we call this routine.
789 memorystatus_disable_freeze(void)
791 memstat_bucket_t
*bucket
;
792 int bucket_count
= 0, retries
= 0;
793 boolean_t retval
= FALSE
, killed
= FALSE
;
794 uint32_t errors
= 0, errors_over_prev_iteration
= 0;
795 os_reason_t jetsam_reason
= 0;
796 unsigned int band
= 0;
797 proc_t p
= PROC_NULL
, next_p
= PROC_NULL
;
798 uint64_t memory_reclaimed
= 0, footprint
= 0;
800 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_MEMSTAT
, BSD_MEMSTAT_FREEZE_DISABLE
) | DBG_FUNC_START
,
801 memorystatus_available_pages
, 0, 0, 0, 0);
803 assert(memorystatus_freeze_enabled
== FALSE
);
805 jetsam_reason
= os_reason_create(OS_REASON_JETSAM
, JETSAM_REASON_MEMORY_DISK_SPACE_SHORTAGE
);
806 if (jetsam_reason
== OS_REASON_NULL
) {
807 printf("memorystatus_disable_freeze: failed to allocate jetsam reason\n");
811 * Let's relocate all frozen processes into band 8. Demoted frozen processes
812 * are sitting in band 0 currently and it's possible to have a frozen process
813 * in the FG band being actively used. We don't reset its frozen state when
814 * it is resumed because it has state on disk.
816 * We choose to do this relocation rather than implement a new 'kill frozen'
817 * process function for these reasons:
818 * - duplication of code: too many kill functions exist and we need to rework them better.
819 * - disk-space-shortage kills are rare
820 * - not having the 'real' jetsam band at time of the this frozen kill won't preclude us
821 * from answering any imp. questions re. jetsam policy/effectiveness.
823 * This is essentially what memorystatus_update_inactive_jetsam_priority_band() does while
824 * avoiding the application of memory limits.
830 band
= JETSAM_PRIORITY_IDLE
;
834 next_p
= memorystatus_get_first_proc_locked(&band
, TRUE
);
837 next_p
= memorystatus_get_next_proc_locked(&band
, p
, TRUE
);
839 if (p
->p_memstat_effectivepriority
> JETSAM_PRIORITY_FOREGROUND
) {
843 if ((p
->p_memstat_state
& P_MEMSTAT_FROZEN
) == FALSE
) {
847 if (p
->p_memstat_state
& P_MEMSTAT_ERROR
) {
848 p
->p_memstat_state
&= ~P_MEMSTAT_ERROR
;
851 if (p
->p_memstat_effectivepriority
== memorystatus_freeze_jetsam_band
) {
856 * We explicitly add this flag here so the process looks like a normal
857 * frozen process i.e. P_MEMSTAT_FROZEN and P_MEMSTAT_USE_ELEVATED_INACTIVE_BAND.
858 * We don't bother with assigning the 'active' memory
859 * limits at this point because we are going to be killing it soon below.
861 p
->p_memstat_state
|= P_MEMSTAT_USE_ELEVATED_INACTIVE_BAND
;
862 memorystatus_invalidate_idle_demotion_locked(p
, TRUE
);
864 memorystatus_update_priority_locked(p
, memorystatus_freeze_jetsam_band
, FALSE
, TRUE
);
867 bucket
= &memstat_bucket
[memorystatus_freeze_jetsam_band
];
868 bucket_count
= bucket
->count
;
872 * Bucket count is already stale at this point. But, we don't expect
873 * freezing to continue since we have already disabled the freeze functionality.
874 * However, an existing freeze might be in progress. So we might miss that process
875 * in the first go-around. We hope to catch it in the next.
878 errors_over_prev_iteration
= 0;
879 while (bucket_count
) {
883 * memorystatus_kill_elevated_process() drops a reference,
884 * so take another one so we can continue to use this exit reason
885 * even after it returns.
888 os_reason_ref(jetsam_reason
);
889 retval
= memorystatus_kill_elevated_process(
890 kMemorystatusKilledDiskSpaceShortage
,
892 memorystatus_freeze_jetsam_band
,
893 0, /* the iteration of aggressive jetsam..ignored here */
898 printf("memorystatus_disable_freeze: memorystatus_kill_elevated_process returned %d error(s)\n", errors
);
899 errors_over_prev_iteration
+= errors
;
905 * No frozen processes left to kill.
911 memory_reclaimed
+= footprint
;
916 if (memorystatus_frozen_count
) {
918 * A frozen process snuck in and so
919 * go back around to kill it. That
920 * process may have been resumed and
921 * put into the FG band too. So we
922 * have to do the relocation again.
924 assert(memorystatus_freeze_enabled
== FALSE
);
931 #if DEVELOPMENT || DEBUG
932 panic("memorystatus_disable_freeze: Failed to kill all frozen processes, memorystatus_frozen_count = %d, errors = %d",
933 memorystatus_frozen_count
, errors_over_prev_iteration
);
934 #endif /* DEVELOPMENT || DEBUG */
938 os_reason_free(jetsam_reason
);
941 vm_swap_consider_defragmenting(VM_SWAP_FLAGS_FORCE_DEFRAG
| VM_SWAP_FLAGS_FORCE_RECLAIM
);
944 size_t snapshot_size
= sizeof(memorystatus_jetsam_snapshot_t
) +
945 sizeof(memorystatus_jetsam_snapshot_entry_t
) * (memorystatus_jetsam_snapshot_count
);
946 uint64_t timestamp_now
= mach_absolute_time();
947 memorystatus_jetsam_snapshot
->notification_time
= timestamp_now
;
948 memorystatus_jetsam_snapshot
->js_gencount
++;
949 if (memorystatus_jetsam_snapshot_count
> 0 && (memorystatus_jetsam_snapshot_last_timestamp
== 0 ||
950 timestamp_now
> memorystatus_jetsam_snapshot_last_timestamp
+ memorystatus_jetsam_snapshot_timeout
)) {
952 int ret
= memorystatus_send_note(kMemorystatusSnapshotNote
, &snapshot_size
, sizeof(snapshot_size
));
955 memorystatus_jetsam_snapshot_last_timestamp
= timestamp_now
;
963 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_MEMSTAT
, BSD_MEMSTAT_FREEZE_DISABLE
) | DBG_FUNC_END
,
964 memorystatus_available_pages
, memory_reclaimed
, 0, 0, 0);
969 __private_extern__
void
970 memorystatus_freeze_init(void)
972 kern_return_t result
;
975 freezer_lck_grp_attr
= lck_grp_attr_alloc_init();
976 freezer_lck_grp
= lck_grp_alloc_init("freezer", freezer_lck_grp_attr
);
978 lck_mtx_init(&freezer_mutex
, freezer_lck_grp
, NULL
);
981 * This is just the default value if the underlying
982 * storage device doesn't have any specific budget.
983 * We check with the storage layer in memorystatus_freeze_update_throttle()
984 * before we start our freezing the first time.
986 memorystatus_freeze_budget_pages_remaining
= (memorystatus_freeze_daily_mb_max
* 1024 * 1024) / PAGE_SIZE
;
988 result
= kernel_thread_start(memorystatus_freeze_thread
, NULL
, &thread
);
989 if (result
== KERN_SUCCESS
) {
990 proc_set_thread_policy(thread
, TASK_POLICY_INTERNAL
, TASK_POLICY_IO
, THROTTLE_LEVEL_COMPRESSOR_TIER2
);
991 proc_set_thread_policy(thread
, TASK_POLICY_INTERNAL
, TASK_POLICY_PASSIVE_IO
, TASK_POLICY_ENABLE
);
992 thread_set_thread_name(thread
, "VM_freezer");
994 thread_deallocate(thread
);
996 panic("Could not create memorystatus_freeze_thread");
1001 memorystatus_is_process_eligible_for_freeze(proc_t p
)
1004 * Called with proc_list_lock held.
1007 LCK_MTX_ASSERT(proc_list_mlock
, LCK_MTX_ASSERT_OWNED
);
1009 boolean_t should_freeze
= FALSE
;
1010 uint32_t state
= 0, entry_count
= 0, pages
= 0, i
= 0;
1011 int probability_of_use
= 0;
1013 state
= p
->p_memstat_state
;
1015 if (state
& (P_MEMSTAT_TERMINATED
| P_MEMSTAT_LOCKED
| P_MEMSTAT_FREEZE_DISABLED
| P_MEMSTAT_FREEZE_IGNORE
)) {
1021 * Daemon:- We consider freezing it if:
1022 * - it belongs to a coalition and the leader is frozen, and,
1023 * - its role in the coalition is XPC service.
1025 * We skip memory size requirements in this case.
1028 coalition_t coal
= COALITION_NULL
;
1029 task_t leader_task
= NULL
, curr_task
= NULL
;
1030 proc_t leader_proc
= NULL
;
1031 int task_role_in_coalition
= 0;
1033 curr_task
= proc_task(p
);
1034 coal
= task_get_coalition(curr_task
, COALITION_TYPE_JETSAM
);
1036 if (coal
== NULL
|| coalition_is_leader(curr_task
, coal
)) {
1038 * By default, XPC services without an app
1039 * will be the leader of their own single-member
1045 leader_task
= coalition_get_leader(coal
);
1046 if (leader_task
== TASK_NULL
) {
1048 * This jetsam coalition is currently leader-less.
1049 * This could happen if the app died, but XPC services
1050 * have not yet exited.
1055 leader_proc
= (proc_t
)get_bsdtask_info(leader_task
);
1056 task_deallocate(leader_task
);
1058 if (leader_proc
== PROC_NULL
) {
1059 /* leader task is exiting */
1063 if (!(leader_proc
->p_memstat_state
& P_MEMSTAT_FROZEN
)) {
1067 task_role_in_coalition
= i_coal_jetsam_get_taskrole(coal
, curr_task
);
1069 if (task_role_in_coalition
== COALITION_TASKROLE_XPC
) {
1070 should_freeze
= TRUE
;
1076 * Application. In addition to the above states we need to make
1077 * sure we only consider suspended applications for freezing.
1079 if (!(state
& P_MEMSTAT_SUSPENDED
)) {
1085 /* Only freeze applications meeting our minimum resident page criteria */
1086 memorystatus_get_task_page_counts(p
->task
, &pages
, NULL
, NULL
);
1087 if (pages
< memorystatus_freeze_pages_min
) {
1091 /* Don't freeze processes that are already exiting on core. It may have started exiting
1092 * after we chose it for freeze, but before we obtained the proc_list_lock.
1093 * NB: This is only possible if we're coming in from memorystatus_freeze_process_sync.
1094 * memorystatus_freeze_top_process holds the proc_list_lock while it traverses the bands.
1096 if ((p
->p_listflag
& P_LIST_EXITED
) != 0) {
1100 entry_count
= (memorystatus_global_probabilities_size
/ sizeof(memorystatus_internal_probabilities_t
));
1103 for (i
= 0; i
< entry_count
; i
++) {
1104 if (strncmp(memorystatus_global_probabilities_table
[i
].proc_name
,
1106 MAXCOMLEN
+ 1) == 0) {
1107 probability_of_use
= memorystatus_global_probabilities_table
[i
].use_probability
;
1112 if (probability_of_use
== 0) {
1117 should_freeze
= TRUE
;
1119 return should_freeze
;
1123 * Synchronously freeze the passed proc. Called with a reference to the proc held.
1125 * Doesn't deal with:
1126 * - re-freezing because this is called on a specific process and
1127 * not by the freezer thread. If that changes, we'll have to teach it about
1128 * refreezing a frozen process.
1130 * - grouped/coalition freezing because we are hoping to deprecate this
1131 * interface as it was used by user-space to freeze particular processes. But
1132 * we have moved away from that approach to having the kernel choose the optimal
1133 * candidates to be frozen.
1135 * Returns EINVAL or the value returned by task_freeze().
1138 memorystatus_freeze_process_sync(proc_t p
)
1142 boolean_t memorystatus_freeze_swap_low
= FALSE
;
1143 int freezer_error_code
= 0;
1145 lck_mtx_lock(&freezer_mutex
);
1148 printf("memorystatus_freeze_process_sync: Invalid process\n");
1152 if (memorystatus_freeze_enabled
== FALSE
) {
1153 printf("memorystatus_freeze_process_sync: Freezing is DISABLED\n");
1157 if (!memorystatus_can_freeze(&memorystatus_freeze_swap_low
)) {
1158 printf("memorystatus_freeze_process_sync: Low compressor and/or low swap space...skipping freeze\n");
1162 memorystatus_freeze_update_throttle(&memorystatus_freeze_budget_pages_remaining
);
1163 if (!memorystatus_freeze_budget_pages_remaining
) {
1164 printf("memorystatus_freeze_process_sync: exit with NO available budget\n");
1171 uint32_t purgeable
, wired
, clean
, dirty
, shared
;
1172 uint32_t max_pages
, i
;
1176 /* Ensure the process is eligible for freezing */
1177 if (memorystatus_is_process_eligible_for_freeze(p
) == FALSE
) {
1182 if (VM_CONFIG_FREEZER_SWAP_IS_ACTIVE
) {
1183 max_pages
= MIN(memorystatus_freeze_pages_max
, memorystatus_freeze_budget_pages_remaining
);
1186 * We only have the compressor without any swap.
1188 max_pages
= UINT32_MAX
- 1;
1191 /* Mark as locked temporarily to avoid kill */
1192 p
->p_memstat_state
|= P_MEMSTAT_LOCKED
;
1195 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_MEMSTAT
, BSD_MEMSTAT_FREEZE
) | DBG_FUNC_START
,
1196 memorystatus_available_pages
, 0, 0, 0, 0);
1198 ret
= task_freeze(p
->task
, &purgeable
, &wired
, &clean
, &dirty
, max_pages
, &shared
, &freezer_error_code
, FALSE
/* eval only */);
1200 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_MEMSTAT
, BSD_MEMSTAT_FREEZE
) | DBG_FUNC_END
,
1201 memorystatus_available_pages
, aPid
, 0, 0, 0);
1203 DTRACE_MEMORYSTATUS6(memorystatus_freeze
, proc_t
, p
, unsigned int, memorystatus_available_pages
, boolean_t
, purgeable
, unsigned int, wired
, uint32_t, clean
, uint32_t, dirty
);
1205 MEMORYSTATUS_DEBUG(1, "memorystatus_freeze_process_sync: task_freeze %s for pid %d [%s] - "
1206 "memorystatus_pages: %d, purgeable: %d, wired: %d, clean: %d, dirty: %d, max_pages %d, shared %d\n",
1207 (ret
== KERN_SUCCESS
) ? "SUCCEEDED" : "FAILED", aPid
, (*p
->p_name
? p
->p_name
: "(unknown)"),
1208 memorystatus_available_pages
, purgeable
, wired
, clean
, dirty
, max_pages
, shared
);
1212 if (ret
== KERN_SUCCESS
) {
1213 memorystatus_freeze_entry_t data
= { aPid
, TRUE
, dirty
};
1215 p
->p_memstat_freeze_sharedanon_pages
+= shared
;
1217 memorystatus_frozen_shared_mb
+= shared
;
1219 if ((p
->p_memstat_state
& P_MEMSTAT_FROZEN
) == 0) {
1220 p
->p_memstat_state
|= P_MEMSTAT_FROZEN
;
1221 memorystatus_frozen_count
++;
1224 p
->p_memstat_frozen_count
++;
1227 * Still keeping the P_MEMSTAT_LOCKED bit till we are actually done elevating this frozen process
1228 * to its higher jetsam band.
1232 memorystatus_send_note(kMemorystatusFreezeNote
, &data
, sizeof(data
));
1234 if (VM_CONFIG_FREEZER_SWAP_IS_ACTIVE
) {
1235 ret
= memorystatus_update_inactive_jetsam_priority_band(p
->p_pid
, MEMORYSTATUS_CMD_ELEVATED_INACTIVEJETSAMPRIORITY_ENABLE
,
1236 memorystatus_freeze_jetsam_band
, TRUE
);
1239 printf("Elevating the frozen process failed with %d\n", ret
);
1247 for (i
= 0; i
< sizeof(throttle_intervals
) / sizeof(struct throttle_interval_t
); i
++) {
1248 throttle_intervals
[i
].pageouts
+= dirty
;
1254 memorystatus_freeze_pageouts
+= dirty
;
1256 if (memorystatus_frozen_count
== (memorystatus_frozen_processes_max
- 1)) {
1258 * Add some eviction logic here? At some point should we
1259 * jetsam a process to get back its swap space so that we
1260 * can freeze a more eligible process at this moment in time?
1264 memorystatus_freeze_update_throttle(&memorystatus_freeze_budget_pages_remaining
);
1265 os_log_with_startup_serial(OS_LOG_DEFAULT
, "memorystatus: freezing (specific) pid %d [%s] done memorystatus_freeze_budget_pages_remaining %llu froze %u pages",
1266 aPid
, ((p
&& *p
->p_name
) ? p
->p_name
: "unknown"), memorystatus_freeze_budget_pages_remaining
, dirty
);
1269 if (freezer_error_code
== FREEZER_ERROR_EXCESS_SHARED_MEMORY
) {
1270 strlcpy(reason
, "too much shared memory", 128);
1273 if (freezer_error_code
== FREEZER_ERROR_LOW_PRIVATE_SHARED_RATIO
) {
1274 strlcpy(reason
, "low private-shared pages ratio", 128);
1277 if (freezer_error_code
== FREEZER_ERROR_NO_COMPRESSOR_SPACE
) {
1278 strlcpy(reason
, "no compressor space", 128);
1281 if (freezer_error_code
== FREEZER_ERROR_NO_SWAP_SPACE
) {
1282 strlcpy(reason
, "no swap space", 128);
1285 os_log_with_startup_serial(OS_LOG_DEFAULT
, "memorystatus: freezing (specific) pid %d [%s]...skipped (%s)",
1286 aPid
, ((p
&& *p
->p_name
) ? p
->p_name
: "unknown"), reason
);
1287 p
->p_memstat_state
|= P_MEMSTAT_FREEZE_IGNORE
;
1290 p
->p_memstat_state
&= ~P_MEMSTAT_LOCKED
;
1291 wakeup(&p
->p_memstat_state
);
1296 lck_mtx_unlock(&freezer_mutex
);
1302 memorystatus_freeze_top_process(void)
1304 pid_t aPid
= 0, coal_xpc_pid
= 0;
1306 proc_t p
= PROC_NULL
, next_p
= PROC_NULL
;
1308 unsigned int band
= JETSAM_PRIORITY_IDLE
;
1309 boolean_t refreeze_processes
= FALSE
;
1310 task_t curr_task
= NULL
;
1311 coalition_t coal
= COALITION_NULL
;
1312 pid_t pid_list
[MAX_XPC_SERVICE_PIDS
];
1313 unsigned int ntasks
= 0;
1315 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_MEMSTAT
, BSD_MEMSTAT_FREEZE_SCAN
) | DBG_FUNC_START
, memorystatus_available_pages
, 0, 0, 0, 0);
1319 if (memorystatus_frozen_count
>= memorystatus_frozen_processes_max
) {
1321 * Freezer is already full but we are here and so let's
1322 * try to refreeze any processes we might have thawed
1323 * in the past and push out their compressed state out.
1325 refreeze_processes
= TRUE
;
1326 band
= (unsigned int) memorystatus_freeze_jetsam_band
;
1331 next_p
= memorystatus_get_first_proc_locked(&band
, FALSE
);
1334 uint32_t purgeable
, wired
, clean
, dirty
, shared
;
1335 uint32_t max_pages
= 0;
1336 int freezer_error_code
= 0;
1341 next_p
= memorystatus_get_next_proc_locked(&band
, p
, FALSE
);
1344 * We have frozen a coalition leader and now are
1345 * dealing with its XPC services. We get our
1346 * next_p for each XPC service from the pid_list
1347 * acquired after a successful task_freeze call
1348 * on the coalition leader.
1352 coal_xpc_pid
= pid_list
[--ntasks
];
1353 next_p
= proc_findinternal(coal_xpc_pid
, 1 /* proc_list_lock held */);
1355 * We grab a reference when we are about to freeze the process. So, drop
1356 * the reference that proc_findinternal() grabbed for us.
1357 * We also have the proc_list_lock and so this process is stable.
1360 proc_rele_locked(next_p
);
1369 if (p
->p_memstat_effectivepriority
!= (int32_t) band
) {
1371 * We shouldn't be freezing processes outside the
1377 /* Ensure the process is eligible for (re-)freezing */
1378 if (refreeze_processes
) {
1380 * Has to have been frozen once before.
1382 if ((p
->p_memstat_state
& P_MEMSTAT_FROZEN
) == FALSE
) {
1387 * Has to have been resumed once before.
1389 if ((p
->p_memstat_state
& P_MEMSTAT_REFREEZE_ELIGIBLE
) == FALSE
) {
1394 * Not currently being looked at for something.
1396 if (p
->p_memstat_state
& P_MEMSTAT_LOCKED
) {
1401 * We are going to try and refreeze and so re-evaluate
1402 * the process. We don't want to double count the shared
1403 * memory. So deduct the old snapshot here.
1405 memorystatus_frozen_shared_mb
-= p
->p_memstat_freeze_sharedanon_pages
;
1406 p
->p_memstat_freeze_sharedanon_pages
= 0;
1408 p
->p_memstat_state
&= ~P_MEMSTAT_REFREEZE_ELIGIBLE
;
1409 memorystatus_refreeze_eligible_count
--;
1411 if (memorystatus_is_process_eligible_for_freeze(p
) == FALSE
) {
1412 continue; // with lock held
1416 if (VM_CONFIG_FREEZER_SWAP_IS_ACTIVE
) {
1418 * Freezer backed by the compressor and swap file(s)
1419 * will hold compressed data.
1422 max_pages
= MIN(memorystatus_freeze_pages_max
, memorystatus_freeze_budget_pages_remaining
);
1425 * We only have the compressor pool.
1427 max_pages
= UINT32_MAX
- 1;
1430 /* Mark as locked temporarily to avoid kill */
1431 p
->p_memstat_state
|= P_MEMSTAT_LOCKED
;
1433 p
= proc_ref_locked(p
);
1440 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_MEMSTAT
, BSD_MEMSTAT_FREEZE
) | DBG_FUNC_START
,
1441 memorystatus_available_pages
, 0, 0, 0, 0);
1443 kr
= task_freeze(p
->task
, &purgeable
, &wired
, &clean
, &dirty
, max_pages
, &shared
, &freezer_error_code
, FALSE
/* eval only */);
1445 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_MEMSTAT
, BSD_MEMSTAT_FREEZE
) | DBG_FUNC_END
,
1446 memorystatus_available_pages
, aPid
, 0, 0, 0);
1448 MEMORYSTATUS_DEBUG(1, "memorystatus_freeze_top_process: task_freeze %s for pid %d [%s] - "
1449 "memorystatus_pages: %d, purgeable: %d, wired: %d, clean: %d, dirty: %d, max_pages %d, shared %d\n",
1450 (kr
== KERN_SUCCESS
) ? "SUCCEEDED" : "FAILED", aPid
, (*p
->p_name
? p
->p_name
: "(unknown)"),
1451 memorystatus_available_pages
, purgeable
, wired
, clean
, dirty
, max_pages
, shared
);
1456 if (KERN_SUCCESS
== kr
) {
1457 memorystatus_freeze_entry_t data
= { aPid
, TRUE
, dirty
};
1459 p
->p_memstat_freeze_sharedanon_pages
+= shared
;
1461 memorystatus_frozen_shared_mb
+= shared
;
1463 if ((p
->p_memstat_state
& P_MEMSTAT_FROZEN
) == 0) {
1464 p
->p_memstat_state
|= P_MEMSTAT_FROZEN
;
1465 memorystatus_frozen_count
++;
1468 p
->p_memstat_frozen_count
++;
1471 * Still keeping the P_MEMSTAT_LOCKED bit till we are actually done elevating this frozen process
1472 * to its higher jetsam band.
1476 memorystatus_send_note(kMemorystatusFreezeNote
, &data
, sizeof(data
));
1478 if (VM_CONFIG_FREEZER_SWAP_IS_ACTIVE
) {
1479 ret
= memorystatus_update_inactive_jetsam_priority_band(p
->p_pid
, MEMORYSTATUS_CMD_ELEVATED_INACTIVEJETSAMPRIORITY_ENABLE
, memorystatus_freeze_jetsam_band
, TRUE
);
1482 printf("Elevating the frozen process failed with %d\n", ret
);
1490 for (i
= 0; i
< sizeof(throttle_intervals
) / sizeof(struct throttle_interval_t
); i
++) {
1491 throttle_intervals
[i
].pageouts
+= dirty
;
1497 memorystatus_freeze_pageouts
+= dirty
;
1499 if (memorystatus_frozen_count
== (memorystatus_frozen_processes_max
- 1)) {
1501 * Add some eviction logic here? At some point should we
1502 * jetsam a process to get back its swap space so that we
1503 * can freeze a more eligible process at this moment in time?
1507 memorystatus_freeze_update_throttle(&memorystatus_freeze_budget_pages_remaining
);
1508 os_log_with_startup_serial(OS_LOG_DEFAULT
, "memorystatus: %sfreezing (%s) pid %d [%s] done, memorystatus_freeze_budget_pages_remaining %llu %sfroze %u pages\n",
1509 refreeze_processes
? "re" : "", (coal
== NULL
? "general" : "coalition-driven"), aPid
, ((p
&& *p
->p_name
) ? p
->p_name
: "unknown"), memorystatus_freeze_budget_pages_remaining
, refreeze_processes
? "Re" : "", dirty
);
1511 /* Return KERN_SUCCESS */
1515 * We froze a process successfully. We can stop now
1516 * and see if that helped if this process isn't part
1520 * - if it is a leader, get the list of XPC services
1521 * that need to be frozen.
1522 * - if it is a XPC service whose leader was frozen
1523 * here, continue on to the next XPC service in the list.
1527 curr_task
= proc_task(p
);
1528 coal
= task_get_coalition(curr_task
, COALITION_TYPE_JETSAM
);
1529 if (coalition_is_leader(curr_task
, coal
)) {
1530 ntasks
= coalition_get_pid_list(coal
, COALITION_ROLEMASK_XPC
,
1531 COALITION_SORT_DEFAULT
, pid_list
, MAX_XPC_SERVICE_PIDS
);
1533 if (ntasks
> MAX_XPC_SERVICE_PIDS
) {
1534 ntasks
= MAX_XPC_SERVICE_PIDS
;
1542 * Start off with our first next_p in this list.
1544 coal_xpc_pid
= pid_list
[--ntasks
];
1545 next_p
= proc_findinternal(coal_xpc_pid
, 1 /* proc_list_lock held */);
1548 * We grab a reference when we are about to freeze the process. So drop
1549 * the reference that proc_findinternal() grabbed for us.
1550 * We also have the proc_list_lock and so this process is stable.
1553 proc_rele_locked(next_p
);
1558 p
->p_memstat_state
&= ~P_MEMSTAT_LOCKED
;
1559 wakeup(&p
->p_memstat_state
);
1560 proc_rele_locked(p
);
1562 if (coal
&& next_p
) {
1567 * No coalition leader was frozen. So we don't
1568 * need to evaluate any XPC services.
1572 * We have frozen all eligible XPC services for
1573 * the current coalition leader.
1575 * Either way, we can break here and see if freezing
1581 p
->p_memstat_state
&= ~P_MEMSTAT_LOCKED
;
1582 wakeup(&p
->p_memstat_state
);
1584 if (refreeze_processes
== TRUE
) {
1585 if ((freezer_error_code
== FREEZER_ERROR_EXCESS_SHARED_MEMORY
) ||
1586 (freezer_error_code
== FREEZER_ERROR_LOW_PRIVATE_SHARED_RATIO
)) {
1588 * Keeping this prior-frozen process in this high band when
1589 * we failed to re-freeze it due to bad shared memory usage
1590 * could cause excessive pressure on the lower bands.
1591 * We need to demote it for now. It'll get re-evaluated next
1592 * time because we don't set the P_MEMSTAT_FREEZE_IGNORE
1596 p
->p_memstat_state
&= ~P_MEMSTAT_USE_ELEVATED_INACTIVE_BAND
;
1597 memorystatus_invalidate_idle_demotion_locked(p
, TRUE
);
1598 memorystatus_update_priority_locked(p
, JETSAM_PRIORITY_IDLE
, TRUE
, TRUE
);
1601 p
->p_memstat_state
|= P_MEMSTAT_FREEZE_IGNORE
;
1605 if (freezer_error_code
== FREEZER_ERROR_EXCESS_SHARED_MEMORY
) {
1606 strlcpy(reason
, "too much shared memory", 128);
1609 if (freezer_error_code
== FREEZER_ERROR_LOW_PRIVATE_SHARED_RATIO
) {
1610 strlcpy(reason
, "low private-shared pages ratio", 128);
1613 if (freezer_error_code
== FREEZER_ERROR_NO_COMPRESSOR_SPACE
) {
1614 strlcpy(reason
, "no compressor space", 128);
1617 if (freezer_error_code
== FREEZER_ERROR_NO_SWAP_SPACE
) {
1618 strlcpy(reason
, "no swap space", 128);
1621 os_log_with_startup_serial(OS_LOG_DEFAULT
, "memorystatus: freezing (%s) pid %d [%s]...skipped (%s)\n",
1622 (coal
== NULL
? "general" : "coalition-driven"), aPid
, ((p
&& *p
->p_name
) ? p
->p_name
: "unknown"), reason
);
1624 proc_rele_locked(p
);
1626 if (vm_compressor_low_on_space() || vm_swap_low_on_space()) {
1633 (memorystatus_refreeze_eligible_count
>= MIN_THAW_REFREEZE_THRESHOLD
) &&
1634 (refreeze_processes
== FALSE
)) {
1636 * We failed to freeze a process from the IDLE
1637 * band AND we have some thawed processes
1638 * AND haven't tried refreezing as yet.
1639 * Let's try and re-freeze processes in the
1640 * frozen band that have been resumed in the past
1641 * and so have brought in state from disk.
1644 band
= (unsigned int) memorystatus_freeze_jetsam_band
;
1646 refreeze_processes
= TRUE
;
1648 goto freeze_process
;
1653 KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_MEMSTAT
, BSD_MEMSTAT_FREEZE_SCAN
) | DBG_FUNC_END
, memorystatus_available_pages
, aPid
, 0, 0, 0);
1658 static inline boolean_t
1659 memorystatus_can_freeze_processes(void)
1665 if (memorystatus_suspended_count
) {
1666 memorystatus_freeze_suspended_threshold
= MIN(memorystatus_freeze_suspended_threshold
, FREEZE_SUSPENDED_THRESHOLD_DEFAULT
);
1668 if ((memorystatus_suspended_count
- memorystatus_frozen_count
) > memorystatus_freeze_suspended_threshold
) {
1683 memorystatus_can_freeze(boolean_t
*memorystatus_freeze_swap_low
)
1685 boolean_t can_freeze
= TRUE
;
1687 /* Only freeze if we're sufficiently low on memory; this holds off freeze right
1688 * after boot, and is generally is a no-op once we've reached steady state. */
1689 if (memorystatus_available_pages
> memorystatus_freeze_threshold
) {
1693 /* Check minimum suspended process threshold. */
1694 if (!memorystatus_can_freeze_processes()) {
1697 assert(VM_CONFIG_COMPRESSOR_IS_PRESENT
);
1699 if (!VM_CONFIG_FREEZER_SWAP_IS_ACTIVE
) {
1701 * In-core compressor used for freezing WITHOUT on-disk swap support.
1703 if (vm_compressor_low_on_space()) {
1704 if (*memorystatus_freeze_swap_low
) {
1705 *memorystatus_freeze_swap_low
= TRUE
;
1710 if (*memorystatus_freeze_swap_low
) {
1711 *memorystatus_freeze_swap_low
= FALSE
;
1718 * Freezing WITH on-disk swap support.
1720 * In-core compressor fronts the swap.
1722 if (vm_swap_low_on_space()) {
1723 if (*memorystatus_freeze_swap_low
) {
1724 *memorystatus_freeze_swap_low
= TRUE
;
1735 * This function evaluates if the currently frozen processes deserve
1736 * to stay in the higher jetsam band. There are 2 modes:
1737 * - 'force one == TRUE': (urgent mode)
1738 * We are out of budget and can't refreeze a process. The process's
1739 * state, if it was resumed, will stay in compressed memory. If we let it
1740 * remain up in the higher frozen jetsam band, it'll put a lot of pressure on
1741 * the lower bands. So we force-demote the least-recently-used-and-thawed
1744 * - 'force_one == FALSE': (normal mode)
1745 * If the # of thaws of a process is below our threshold, then we
1746 * will demote that process into the IDLE band.
1747 * We don't immediately kill the process here because it already has
1748 * state on disk and so it might be worth giving it another shot at
1749 * getting thawed/resumed and used.
1752 memorystatus_demote_frozen_processes(boolean_t force_one
)
1754 unsigned int band
= (unsigned int) memorystatus_freeze_jetsam_band
;
1755 unsigned int demoted_proc_count
= 0;
1756 proc_t p
= PROC_NULL
, next_p
= PROC_NULL
;
1757 /* We demote to IDLE unless someone has asserted a higher priority on this process. */
1758 int maxpriority
= JETSAM_PRIORITY_IDLE
;
1762 if (memorystatus_freeze_enabled
== FALSE
) {
1764 * Freeze has been disabled likely to
1765 * reclaim swap space. So don't change
1766 * any state on the frozen processes.
1772 next_p
= memorystatus_get_first_proc_locked(&band
, FALSE
);
1775 next_p
= memorystatus_get_next_proc_locked(&band
, p
, FALSE
);
1777 if ((p
->p_memstat_state
& P_MEMSTAT_FROZEN
) == FALSE
) {
1781 if (p
->p_memstat_state
& P_MEMSTAT_LOCKED
) {
1785 if (force_one
== TRUE
) {
1786 if ((p
->p_memstat_state
& P_MEMSTAT_REFREEZE_ELIGIBLE
) == 0) {
1788 * This process hasn't been thawed recently and so most of
1789 * its state sits on NAND and so we skip it -- jetsamming it
1790 * won't help with memory pressure.
1795 if (p
->p_memstat_thaw_count
>= memorystatus_thaw_count_demotion_threshold
) {
1797 * This process has met / exceeded our thaw count demotion threshold
1798 * and so we let it live in the higher bands.
1804 p
->p_memstat_state
&= ~P_MEMSTAT_USE_ELEVATED_INACTIVE_BAND
;
1805 memorystatus_invalidate_idle_demotion_locked(p
, TRUE
);
1807 maxpriority
= MAX(p
->p_memstat_assertionpriority
, maxpriority
);
1808 memorystatus_update_priority_locked(p
, maxpriority
, FALSE
, FALSE
);
1809 #if DEVELOPMENT || DEBUG
1810 os_log_with_startup_serial(OS_LOG_DEFAULT
, "memorystatus_demote_frozen_process(%s) pid %d [%s]",
1811 (force_one
? "urgent" : "normal"), (p
? p
->p_pid
: -1), ((p
&& *p
->p_name
) ? p
->p_name
: "unknown"));
1812 #endif /* DEVELOPMENT || DEBUG */
1815 * The freezer thread will consider this a normal app to be frozen
1816 * because it is in the IDLE band. So we don't need the
1817 * P_MEMSTAT_REFREEZE_ELIGIBLE state here. Also, if it gets resumed
1818 * we'll correctly count it as eligible for re-freeze again.
1820 * We don't drop the frozen count because this process still has
1821 * state on disk. So there's a chance it gets resumed and then it
1822 * should land in the higher jetsam band. For that it needs to
1823 * remain marked frozen.
1825 if (p
->p_memstat_state
& P_MEMSTAT_REFREEZE_ELIGIBLE
) {
1826 p
->p_memstat_state
&= ~P_MEMSTAT_REFREEZE_ELIGIBLE
;
1827 memorystatus_refreeze_eligible_count
--;
1830 demoted_proc_count
++;
1832 if ((force_one
== TRUE
) || (demoted_proc_count
== memorystatus_max_frozen_demotions_daily
)) {
1837 if (force_one
== FALSE
) {
1839 * We use this counter to track daily thaws.
1840 * So we only reset it to 0 under the normal
1843 memorystatus_thaw_count
= 0;
1851 * This function will do 4 things:
1853 * 1) check to see if we are currently in a degraded freezer mode, and if so:
1854 * - check to see if our window has expired and we should exit this mode, OR,
1855 * - return a budget based on the degraded throttle window's max. pageouts vs current pageouts.
1857 * 2) check to see if we are in a NEW normal window and update the normal throttle window's params.
1859 * 3) check what the current normal window allows for a budget.
1861 * 4) calculate the current rate of pageouts for DEGRADED_WINDOW_MINS duration. If that rate is below
1862 * what we would normally expect, then we are running low on our daily budget and need to enter
1863 * degraded perf. mode.
1867 memorystatus_freeze_update_throttle(uint64_t *budget_pages_allowed
)
1873 unsigned int freeze_daily_pageouts_max
= 0;
1875 #if DEVELOPMENT || DEBUG
1876 if (!memorystatus_freeze_throttle_enabled
) {
1878 * No throttling...we can use the full budget everytime.
1880 *budget_pages_allowed
= UINT64_MAX
;
1885 clock_get_system_nanotime(&sec
, &nsec
);
1889 struct throttle_interval_t
*interval
= NULL
;
1891 if (memorystatus_freeze_degradation
== TRUE
) {
1892 interval
= degraded_throttle_window
;
1894 if (CMP_MACH_TIMESPEC(&ts
, &interval
->ts
) >= 0) {
1895 memorystatus_freeze_degradation
= FALSE
;
1896 interval
->pageouts
= 0;
1897 interval
->max_pageouts
= 0;
1899 *budget_pages_allowed
= interval
->max_pageouts
- interval
->pageouts
;
1903 interval
= normal_throttle_window
;
1905 if (CMP_MACH_TIMESPEC(&ts
, &interval
->ts
) >= 0) {
1907 * New throttle window.
1908 * Rollover any unused budget.
1909 * Also ask the storage layer what the new budget needs to be.
1911 uint64_t freeze_daily_budget
= 0;
1912 unsigned int daily_budget_pageouts
= 0;
1914 if (vm_swap_max_budget(&freeze_daily_budget
)) {
1915 memorystatus_freeze_daily_mb_max
= (freeze_daily_budget
/ (1024 * 1024));
1916 os_log_with_startup_serial(OS_LOG_DEFAULT
, "memorystatus: memorystatus_freeze_daily_mb_max set to %dMB\n", memorystatus_freeze_daily_mb_max
);
1919 freeze_daily_pageouts_max
= memorystatus_freeze_daily_mb_max
* (1024 * 1024 / PAGE_SIZE
);
1921 daily_budget_pageouts
= (interval
->burst_multiple
* (((uint64_t)interval
->mins
* freeze_daily_pageouts_max
) / NORMAL_WINDOW_MINS
));
1922 interval
->max_pageouts
= (interval
->max_pageouts
- interval
->pageouts
) + daily_budget_pageouts
;
1924 interval
->ts
.tv_sec
= interval
->mins
* 60;
1925 interval
->ts
.tv_nsec
= 0;
1926 ADD_MACH_TIMESPEC(&interval
->ts
, &ts
);
1927 /* Since we update the throttle stats pre-freeze, adjust for overshoot here */
1928 if (interval
->pageouts
> interval
->max_pageouts
) {
1929 interval
->pageouts
-= interval
->max_pageouts
;
1931 interval
->pageouts
= 0;
1933 *budget_pages_allowed
= interval
->max_pageouts
;
1935 memorystatus_demote_frozen_processes(FALSE
); /* normal mode...don't force a demotion */
1938 * Current throttle window.
1939 * Deny freezing if we have no budget left.
1940 * Try graceful degradation if we are within 25% of:
1941 * - the daily budget, and
1942 * - the current budget left is below our normal budget expectations.
1945 #if DEVELOPMENT || DEBUG
1947 * This can only happen in the INTERNAL configs because we allow modifying the daily budget for testing.
1950 if (freeze_daily_pageouts_max
> interval
->max_pageouts
) {
1952 * We just bumped the daily budget. Re-evaluate our normal window params.
1954 interval
->max_pageouts
= (interval
->burst_multiple
* (((uint64_t)interval
->mins
* freeze_daily_pageouts_max
) / NORMAL_WINDOW_MINS
));
1955 memorystatus_freeze_degradation
= FALSE
; //we'll re-evaluate this below...
1957 #endif /* DEVELOPMENT || DEBUG */
1959 if (memorystatus_freeze_degradation
== FALSE
) {
1960 if (interval
->pageouts
>= interval
->max_pageouts
) {
1961 *budget_pages_allowed
= 0;
1963 int budget_left
= interval
->max_pageouts
- interval
->pageouts
;
1964 int budget_threshold
= (freeze_daily_pageouts_max
* FREEZE_DEGRADATION_BUDGET_THRESHOLD
) / 100;
1966 mach_timespec_t time_left
= {0, 0};
1968 time_left
.tv_sec
= interval
->ts
.tv_sec
;
1969 time_left
.tv_nsec
= 0;
1971 SUB_MACH_TIMESPEC(&time_left
, &ts
);
1973 if (budget_left
<= budget_threshold
) {
1975 * For the current normal window, calculate how much we would pageout in a DEGRADED_WINDOW_MINS duration.
1976 * And also calculate what we would pageout for the same DEGRADED_WINDOW_MINS duration if we had the full
1977 * daily pageout budget.
1980 unsigned int current_budget_rate_allowed
= ((budget_left
/ time_left
.tv_sec
) / 60) * DEGRADED_WINDOW_MINS
;
1981 unsigned int normal_budget_rate_allowed
= (freeze_daily_pageouts_max
/ NORMAL_WINDOW_MINS
) * DEGRADED_WINDOW_MINS
;
1984 * The current rate of pageouts is below what we would expect for
1985 * the normal rate i.e. we have below normal budget left and so...
1988 if (current_budget_rate_allowed
< normal_budget_rate_allowed
) {
1989 memorystatus_freeze_degradation
= TRUE
;
1990 degraded_throttle_window
->max_pageouts
= current_budget_rate_allowed
;
1991 degraded_throttle_window
->pageouts
= 0;
1994 * Switch over to the degraded throttle window so the budget
1995 * doled out is based on that window.
1997 interval
= degraded_throttle_window
;
2001 *budget_pages_allowed
= interval
->max_pageouts
- interval
->pageouts
;
2006 MEMORYSTATUS_DEBUG(1, "memorystatus_freeze_update_throttle_interval: throttle updated - %d frozen (%d max) within %dm; %dm remaining; throttle %s\n",
2007 interval
->pageouts
, interval
->max_pageouts
, interval
->mins
, (interval
->ts
.tv_sec
- ts
->tv_sec
) / 60,
2008 interval
->throttle
? "on" : "off");
2012 memorystatus_freeze_thread(void *param __unused
, wait_result_t wr __unused
)
2014 static boolean_t memorystatus_freeze_swap_low
= FALSE
;
2016 lck_mtx_lock(&freezer_mutex
);
2018 if (memorystatus_freeze_enabled
) {
2019 if ((memorystatus_frozen_count
< memorystatus_frozen_processes_max
) ||
2020 (memorystatus_refreeze_eligible_count
>= MIN_THAW_REFREEZE_THRESHOLD
)) {
2021 if (memorystatus_can_freeze(&memorystatus_freeze_swap_low
)) {
2022 /* Only freeze if we've not exceeded our pageout budgets.*/
2023 memorystatus_freeze_update_throttle(&memorystatus_freeze_budget_pages_remaining
);
2025 if (memorystatus_freeze_budget_pages_remaining
) {
2026 memorystatus_freeze_top_process();
2028 memorystatus_demote_frozen_processes(TRUE
); /* urgent mode..force one demotion */
2035 * We use memorystatus_apps_idle_delay_time because if/when we adopt aging for applications,
2036 * it'll tie neatly into running the freezer once we age an application.
2038 * Till then, it serves as a good interval that can be tuned via a sysctl too.
2040 memorystatus_freezer_thread_next_run_ts
= mach_absolute_time() + memorystatus_apps_idle_delay_time
;
2042 assert_wait((event_t
) &memorystatus_freeze_wakeup
, THREAD_UNINT
);
2043 lck_mtx_unlock(&freezer_mutex
);
2045 thread_block((thread_continue_t
) memorystatus_freeze_thread
);
2049 memorystatus_freeze_thread_should_run(void)
2052 * No freezer_mutex held here...see why near call-site
2053 * within memorystatus_pages_update().
2056 boolean_t should_run
= FALSE
;
2058 if (memorystatus_freeze_enabled
== FALSE
) {
2062 if (memorystatus_available_pages
> memorystatus_freeze_threshold
) {
2066 if ((memorystatus_frozen_count
>= memorystatus_frozen_processes_max
) &&
2067 (memorystatus_refreeze_eligible_count
< MIN_THAW_REFREEZE_THRESHOLD
)) {
2071 if (memorystatus_frozen_shared_mb_max
&& (memorystatus_frozen_shared_mb
>= memorystatus_frozen_shared_mb_max
)) {
2075 uint64_t curr_time
= mach_absolute_time();
2077 if (curr_time
< memorystatus_freezer_thread_next_run_ts
) {
2088 memorystatus_get_process_is_freezable(pid_t pid
, int *is_freezable
)
2090 proc_t p
= PROC_NULL
;
2102 * Only allow this on the current proc for now.
2103 * We can check for privileges and allow targeting another process in the future.
2105 if (p
!= current_proc()) {
2111 *is_freezable
= ((p
->p_memstat_state
& P_MEMSTAT_FREEZE_DISABLED
) ? 0 : 1);
2112 proc_rele_locked(p
);
2119 memorystatus_set_process_is_freezable(pid_t pid
, boolean_t is_freezable
)
2121 proc_t p
= PROC_NULL
;
2128 * To enable freezable status, you need to be root or an entitlement.
2131 !kauth_cred_issuser(kauth_cred_get()) &&
2132 !IOTaskHasEntitlement(current_task(), MEMORYSTATUS_ENTITLEMENT
)) {
2142 * A process can change its own status. A coalition leader can
2143 * change the status of coalition members.
2145 if (p
!= current_proc()) {
2146 coalition_t coal
= task_get_coalition(proc_task(p
), COALITION_TYPE_JETSAM
);
2147 if (!coalition_is_leader(proc_task(current_proc()), coal
)) {
2154 if (is_freezable
== FALSE
) {
2155 /* Freeze preference set to FALSE. Set the P_MEMSTAT_FREEZE_DISABLED bit. */
2156 p
->p_memstat_state
|= P_MEMSTAT_FREEZE_DISABLED
;
2157 printf("memorystatus_set_process_is_freezable: disabling freeze for pid %d [%s]\n",
2158 p
->p_pid
, (*p
->p_name
? p
->p_name
: "unknown"));
2160 p
->p_memstat_state
&= ~P_MEMSTAT_FREEZE_DISABLED
;
2161 printf("memorystatus_set_process_is_freezable: enabling freeze for pid %d [%s]\n",
2162 p
->p_pid
, (*p
->p_name
? p
->p_name
: "unknown"));
2164 proc_rele_locked(p
);
2171 sysctl_memorystatus_do_fastwake_warmup_all SYSCTL_HANDLER_ARGS
2173 #pragma unused(oidp, arg1, arg2)
2179 /* Need to be root or have entitlement */
2180 if (!kauth_cred_issuser(kauth_cred_get()) && !IOTaskHasEntitlement(current_task(), MEMORYSTATUS_ENTITLEMENT
)) {
2184 if (memorystatus_freeze_enabled
== FALSE
) {
2188 do_fastwake_warmup_all();
2193 SYSCTL_PROC(_kern
, OID_AUTO
, memorystatus_do_fastwake_warmup_all
, CTLTYPE_INT
| CTLFLAG_WR
| CTLFLAG_LOCKED
| CTLFLAG_MASKED
,
2194 0, 0, &sysctl_memorystatus_do_fastwake_warmup_all
, "I", "");
2196 #endif /* CONFIG_FREEZE */