+static boolean_t
+memorystatus_avail_pages_below_pressure(void)
+{
+#if CONFIG_EMBEDDED
+/*
+ * Instead of CONFIG_EMBEDDED for these *avail_pages* routines, we should
+ * key off of the system having dynamic swap support. With full swap support,
+ * the system shouldn't really need to worry about various page thresholds.
+ */
+ return (memorystatus_available_pages <= memorystatus_available_pages_pressure);
+#else /* CONFIG_EMBEDDED */
+ return FALSE;
+#endif /* CONFIG_EMBEDDED */
+}
+
+static boolean_t
+memorystatus_avail_pages_below_critical(void)
+{
+#if CONFIG_EMBEDDED
+ return (memorystatus_available_pages <= memorystatus_available_pages_critical);
+#else /* CONFIG_EMBEDDED */
+ return FALSE;
+#endif /* CONFIG_EMBEDDED */
+}
+
+static boolean_t
+memorystatus_post_snapshot(int32_t priority, uint32_t cause)
+{
+#if CONFIG_EMBEDDED
+#pragma unused(cause)
+ /*
+ * Don't generate logs for steady-state idle-exit kills,
+ * unless it is overridden for debug or by the device
+ * tree.
+ */
+
+ return ((priority != JETSAM_PRIORITY_IDLE) || memorystatus_idle_snapshot);
+
+#else /* CONFIG_EMBEDDED */
+ /*
+ * Don't generate logs for steady-state idle-exit kills,
+ * unless
+ * - it is overridden for debug or by the device
+ * tree.
+ * OR
+ * - the kill causes are important i.e. not kMemorystatusKilledIdleExit
+ */
+
+ boolean_t snapshot_eligible_kill_cause = (is_reason_thrashing(cause) || is_reason_zone_map_exhaustion(cause));
+ return ((priority != JETSAM_PRIORITY_IDLE) || memorystatus_idle_snapshot || snapshot_eligible_kill_cause);
+#endif /* CONFIG_EMBEDDED */
+}
+
+static boolean_t
+memorystatus_action_needed(void)
+{
+#if CONFIG_EMBEDDED
+ return (is_reason_thrashing(kill_under_pressure_cause) ||
+ is_reason_zone_map_exhaustion(kill_under_pressure_cause) ||
+ memorystatus_available_pages <= memorystatus_available_pages_pressure);
+#else /* CONFIG_EMBEDDED */
+ return (is_reason_thrashing(kill_under_pressure_cause) ||
+ is_reason_zone_map_exhaustion(kill_under_pressure_cause));
+#endif /* CONFIG_EMBEDDED */
+}
+
+static boolean_t
+memorystatus_act_on_hiwat_processes(uint32_t *errors, uint32_t *hwm_kill, boolean_t *post_snapshot, __unused boolean_t *is_critical)
+{
+ boolean_t killed = memorystatus_kill_hiwat_proc(errors);
+
+ if (killed) {
+ *hwm_kill = *hwm_kill + 1;
+ *post_snapshot = TRUE;
+ return TRUE;
+ } else {
+ memorystatus_hwm_candidates = FALSE;
+ }
+
+#if CONFIG_JETSAM
+ /* No highwater processes to kill. Continue or stop for now? */
+ if (!is_reason_thrashing(kill_under_pressure_cause) &&
+ !is_reason_zone_map_exhaustion(kill_under_pressure_cause) &&
+ (memorystatus_available_pages > memorystatus_available_pages_critical)) {
+ /*
+ * We are _not_ out of pressure but we are above the critical threshold and there's:
+ * - no compressor thrashing
+ * - enough zone memory
+ * - no more HWM processes left.
+ * For now, don't kill any other processes.
+ */
+
+ if (*hwm_kill == 0) {
+ memorystatus_thread_wasted_wakeup++;
+ }
+
+ *is_critical = FALSE;
+
+ return TRUE;
+ }
+#endif /* CONFIG_JETSAM */
+
+ return FALSE;
+}
+
+static boolean_t
+memorystatus_act_aggressive(uint32_t cause, os_reason_t jetsam_reason, int *jld_idle_kills, boolean_t *corpse_list_purged, boolean_t *post_snapshot)
+{
+ if (memorystatus_jld_enabled == TRUE) {
+
+ boolean_t killed;
+ uint32_t errors = 0;
+
+ /* Jetsam Loop Detection - locals */
+ memstat_bucket_t *bucket;
+ int jld_bucket_count = 0;
+ struct timeval jld_now_tstamp = {0,0};
+ uint64_t jld_now_msecs = 0;
+ int elevated_bucket_count = 0;
+
+ /* Jetsam Loop Detection - statics */
+ static uint64_t jld_timestamp_msecs = 0;
+ static int jld_idle_kill_candidates = 0; /* Number of available processes in band 0,1 at start */
+ static int jld_eval_aggressive_count = 0; /* Bumps the max priority in aggressive loop */
+ static int32_t jld_priority_band_max = JETSAM_PRIORITY_UI_SUPPORT;
+ /*
+ * Jetsam Loop Detection: attempt to detect
+ * rapid daemon relaunches in the lower bands.
+ */
+
+ microuptime(&jld_now_tstamp);
+
+ /*
+ * Ignore usecs in this calculation.
+ * msecs granularity is close enough.
+ */
+ jld_now_msecs = (jld_now_tstamp.tv_sec * 1000);
+
+ proc_list_lock();
+ switch (jetsam_aging_policy) {
+ case kJetsamAgingPolicyLegacy:
+ bucket = &memstat_bucket[JETSAM_PRIORITY_IDLE];
+ jld_bucket_count = bucket->count;
+ bucket = &memstat_bucket[JETSAM_PRIORITY_AGING_BAND1];
+ jld_bucket_count += bucket->count;
+ break;
+ case kJetsamAgingPolicySysProcsReclaimedFirst:
+ case kJetsamAgingPolicyAppsReclaimedFirst:
+ bucket = &memstat_bucket[JETSAM_PRIORITY_IDLE];
+ jld_bucket_count = bucket->count;
+ bucket = &memstat_bucket[system_procs_aging_band];
+ jld_bucket_count += bucket->count;
+ bucket = &memstat_bucket[applications_aging_band];
+ jld_bucket_count += bucket->count;
+ break;
+ case kJetsamAgingPolicyNone:
+ default:
+ bucket = &memstat_bucket[JETSAM_PRIORITY_IDLE];
+ jld_bucket_count = bucket->count;
+ break;
+ }
+
+ bucket = &memstat_bucket[JETSAM_PRIORITY_ELEVATED_INACTIVE];
+ elevated_bucket_count = bucket->count;
+
+ proc_list_unlock();
+
+ /*
+ * memorystatus_jld_eval_period_msecs is a tunable
+ * memorystatus_jld_eval_aggressive_count is a tunable
+ * memorystatus_jld_eval_aggressive_priority_band_max is a tunable
+ */
+ if ( (jld_bucket_count == 0) ||
+ (jld_now_msecs > (jld_timestamp_msecs + memorystatus_jld_eval_period_msecs))) {
+
+ /*
+ * Refresh evaluation parameters
+ */
+ jld_timestamp_msecs = jld_now_msecs;
+ jld_idle_kill_candidates = jld_bucket_count;
+ *jld_idle_kills = 0;
+ jld_eval_aggressive_count = 0;
+ jld_priority_band_max = JETSAM_PRIORITY_UI_SUPPORT;
+ }
+
+ if (*jld_idle_kills > jld_idle_kill_candidates) {
+ jld_eval_aggressive_count++;
+
+#if DEVELOPMENT || DEBUG
+ printf("memorystatus: aggressive%d: beginning of window: %lld ms, : timestamp now: %lld ms\n",
+ jld_eval_aggressive_count,
+ jld_timestamp_msecs,
+ jld_now_msecs);
+ printf("memorystatus: aggressive%d: idle candidates: %d, idle kills: %d\n",
+ jld_eval_aggressive_count,
+ jld_idle_kill_candidates,
+ *jld_idle_kills);
+#endif /* DEVELOPMENT || DEBUG */
+
+ if ((jld_eval_aggressive_count == memorystatus_jld_eval_aggressive_count) &&
+ (total_corpses_count() > 0) && (*corpse_list_purged == FALSE)) {
+ /*
+ * If we reach this aggressive cycle, corpses might be causing memory pressure.
+ * So, in an effort to avoid jetsams in the FG band, we will attempt to purge
+ * corpse memory prior to this final march through JETSAM_PRIORITY_UI_SUPPORT.
+ */
+ task_purge_all_corpses();
+ *corpse_list_purged = TRUE;
+ }
+ else if (jld_eval_aggressive_count > memorystatus_jld_eval_aggressive_count) {
+ /*
+ * Bump up the jetsam priority limit (eg: the bucket index)
+ * Enforce bucket index sanity.
+ */
+ if ((memorystatus_jld_eval_aggressive_priority_band_max < 0) ||
+ (memorystatus_jld_eval_aggressive_priority_band_max >= MEMSTAT_BUCKET_COUNT)) {
+ /*
+ * Do nothing. Stick with the default level.
+ */
+ } else {
+ jld_priority_band_max = memorystatus_jld_eval_aggressive_priority_band_max;
+ }
+ }
+
+ /* Visit elevated processes first */
+ while (elevated_bucket_count) {
+
+ elevated_bucket_count--;
+
+ /*
+ * memorystatus_kill_elevated_process() drops a reference,
+ * so take another one so we can continue to use this exit reason
+ * even after it returns.
+ */
+
+ os_reason_ref(jetsam_reason);
+ killed = memorystatus_kill_elevated_process(
+ cause,
+ jetsam_reason,
+ jld_eval_aggressive_count,
+ &errors);
+
+ if (killed) {
+ *post_snapshot = TRUE;
+ if (memorystatus_avail_pages_below_pressure()) {
+ /*
+ * Still under pressure.
+ * Find another pinned processes.
+ */
+ continue;
+ } else {
+ return TRUE;
+ }
+ } else {
+ /*
+ * No pinned processes left to kill.
+ * Abandon elevated band.
+ */
+ break;
+ }
+ }
+
+ /*
+ * memorystatus_kill_top_process_aggressive() allocates its own
+ * jetsam_reason so the kMemorystatusKilledVMThrashing cause
+ * is consistent throughout the aggressive march.
+ */
+ killed = memorystatus_kill_top_process_aggressive(
+ kMemorystatusKilledVMThrashing,
+ jld_eval_aggressive_count,
+ jld_priority_band_max,
+ &errors);
+
+ if (killed) {
+ /* Always generate logs after aggressive kill */
+ *post_snapshot = TRUE;
+ *jld_idle_kills = 0;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ }
+
+ return FALSE;
+}
+
+