- proc_t p, next_p;
- unsigned int b = 0, i = 0;
-
- memorystatus_jetsam_snapshot_t *snapshot = NULL;
- memorystatus_jetsam_snapshot_entry_t *snapshot_list = NULL;
- unsigned int snapshot_max = 0;
-
- if (od_snapshot) {
- /*
- * This is an on_demand snapshot
- */
- snapshot = od_snapshot;
- snapshot_list = od_snapshot->entries;
- snapshot_max = ods_list_count;
- } else {
- /*
- * This is a jetsam event snapshot
- */
- snapshot = memorystatus_jetsam_snapshot;
- snapshot_list = memorystatus_jetsam_snapshot->entries;
- snapshot_max = memorystatus_jetsam_snapshot_max;
- }
-
- /*
- * Init the snapshot header information
- */
- memorystatus_init_snapshot_vmstats(snapshot);
- snapshot->snapshot_time = mach_absolute_time();
- snapshot->notification_time = 0;
- snapshot->js_gencount = 0;
-
- next_p = memorystatus_get_first_proc_locked(&b, TRUE);
- while (next_p) {
- p = next_p;
- next_p = memorystatus_get_next_proc_locked(&b, p, TRUE);
-
- if (FALSE == memorystatus_init_jetsam_snapshot_entry_locked(p, &snapshot_list[i], snapshot->js_gencount)) {
- continue;
- }
-
- MEMORYSTATUS_DEBUG(0, "jetsam snapshot pid %d, uuid = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
- p->p_pid,
- p->p_uuid[0], p->p_uuid[1], p->p_uuid[2], p->p_uuid[3], p->p_uuid[4], p->p_uuid[5], p->p_uuid[6], p->p_uuid[7],
- p->p_uuid[8], p->p_uuid[9], p->p_uuid[10], p->p_uuid[11], p->p_uuid[12], p->p_uuid[13], p->p_uuid[14], p->p_uuid[15]);
-
- if (++i == snapshot_max) {
- break;
- }
- }
-
- snapshot->entry_count = i;
-
- if (!od_snapshot) {
- /* update the system buffer count */
- memorystatus_jetsam_snapshot_count = i;
- }
-}
-
-#if DEVELOPMENT || DEBUG
-
-static int
-memorystatus_cmd_set_panic_bits(user_addr_t buffer, uint32_t buffer_size) {
- int ret;
- memorystatus_jetsam_panic_options_t debug;
-
- if (buffer_size != sizeof(memorystatus_jetsam_panic_options_t)) {
- return EINVAL;
- }
-
- ret = copyin(buffer, &debug, buffer_size);
- if (ret) {
- return ret;
- }
-
- /* Panic bits match kMemorystatusKilled* enum */
- memorystatus_jetsam_panic_debug = (memorystatus_jetsam_panic_debug & ~debug.mask) | (debug.data & debug.mask);
-
- /* Copyout new value */
- debug.data = memorystatus_jetsam_panic_debug;
- ret = copyout(&debug, buffer, sizeof(memorystatus_jetsam_panic_options_t));
-
- return ret;
-}
-
-/*
- * Triggers a sort_order on a specified jetsam priority band.
- * This is for testing only, used to force a path through the sort
- * function.
- */
-static int
-memorystatus_cmd_test_jetsam_sort(int priority, int sort_order) {
-
- int error = 0;
-
- unsigned int bucket_index = 0;
-
- if (priority == -1) {
- /* Use as shorthand for default priority */
- bucket_index = JETSAM_PRIORITY_DEFAULT;
- } else {
- bucket_index = (unsigned int)priority;
- }
-
- error = memorystatus_sort_bucket(bucket_index, sort_order);
-
- return (error);
-}
-
-#endif /* DEVELOPMENT || DEBUG */
-
-/*
- * Jetsam the first process in the queue.
- */
-static boolean_t
-memorystatus_kill_top_process(boolean_t any, boolean_t sort_flag, uint32_t cause, os_reason_t jetsam_reason,
- int32_t *priority, uint32_t *errors)
-{
- pid_t aPid;
- proc_t p = PROC_NULL, next_p = PROC_NULL;
- boolean_t new_snapshot = FALSE, killed = FALSE;
- int kill_count = 0;
- unsigned int i = 0;
- uint32_t aPid_ep;
- uint64_t killtime = 0;
- clock_sec_t tv_sec;
- clock_usec_t tv_usec;
- uint32_t tv_msec;
-
-#ifndef CONFIG_FREEZE
-#pragma unused(any)
-#endif
-
- KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_MEMSTAT, BSD_MEMSTAT_JETSAM) | DBG_FUNC_START,
- memorystatus_available_pages, 0, 0, 0, 0);
-
-
- if (sort_flag == TRUE) {
- (void)memorystatus_sort_bucket(JETSAM_PRIORITY_FOREGROUND, JETSAM_SORT_DEFAULT);
- }
-
- proc_list_lock();
-
- next_p = memorystatus_get_first_proc_locked(&i, TRUE);
- while (next_p) {
-#if DEVELOPMENT || DEBUG
- int activeProcess;
- int procSuspendedForDiagnosis;
-#endif /* DEVELOPMENT || DEBUG */
-
- p = next_p;
- next_p = memorystatus_get_next_proc_locked(&i, p, TRUE);
-
-#if DEVELOPMENT || DEBUG
- activeProcess = p->p_memstat_state & P_MEMSTAT_FOREGROUND;
- procSuspendedForDiagnosis = p->p_memstat_state & P_MEMSTAT_DIAG_SUSPENDED;
-#endif /* DEVELOPMENT || DEBUG */
-
- aPid = p->p_pid;
- aPid_ep = p->p_memstat_effectivepriority;
-
- if (p->p_memstat_state & (P_MEMSTAT_ERROR | P_MEMSTAT_TERMINATED)) {
- continue; /* with lock held */
- }
-
-#if DEVELOPMENT || DEBUG
- if ((memorystatus_jetsam_policy & kPolicyDiagnoseActive) && procSuspendedForDiagnosis) {
- printf("jetsam: continuing after ignoring proc suspended already for diagnosis - %d\n", aPid);
- continue;
- }
-#endif /* DEVELOPMENT || DEBUG */
-
- if (cause == kMemorystatusKilledVnodes)
- {
- /*
- * If the system runs out of vnodes, we systematically jetsam
- * processes in hopes of stumbling onto a vnode gain that helps
- * the system recover. The process that happens to trigger
- * this path has no known relationship to the vnode consumption.
- * We attempt to safeguard that process e.g: do not jetsam it.
- */
-
- if (p == current_proc()) {
- /* do not jetsam the current process */
- continue;
- }
- }
-
-#if CONFIG_FREEZE
- boolean_t skip;
- boolean_t reclaim_proc = !(p->p_memstat_state & (P_MEMSTAT_LOCKED | P_MEMSTAT_NORECLAIM));
- if (any || reclaim_proc) {
- skip = FALSE;
- } else {
- skip = TRUE;
- }
-
- if (skip) {
- continue;
- } else
-#endif
- {
- /*
- * Capture a snapshot if none exists and:
- * - priority was not requested (this is something other than an ambient kill)
- * - the priority was requested *and* the targeted process is not at idle priority
- */
- if ((memorystatus_jetsam_snapshot_count == 0) &&
- (memorystatus_idle_snapshot || ((!priority) || (priority && (aPid_ep != JETSAM_PRIORITY_IDLE))))) {
- memorystatus_init_jetsam_snapshot_locked(NULL,0);
- new_snapshot = TRUE;
- }
-
- /*
- * Mark as terminated so that if exit1() indicates success, but the process (for example)
- * is blocked in task_exception_notify(), it'll be skipped if encountered again - see
- * <rdar://problem/13553476>. This is cheaper than examining P_LEXIT, which requires the
- * acquisition of the proc lock.
- */
- p->p_memstat_state |= P_MEMSTAT_TERMINATED;
-
- killtime = mach_absolute_time();
- absolutetime_to_microtime(killtime, &tv_sec, &tv_usec);
- tv_msec = tv_usec / 1000;
-
-#if DEVELOPMENT || DEBUG
- if ((memorystatus_jetsam_policy & kPolicyDiagnoseActive) && activeProcess) {
- MEMORYSTATUS_DEBUG(1, "jetsam: suspending pid %d [%s] (active) for diagnosis - memory_status_level: %d\n",
- aPid, (*p->p_name ? p->p_name: "(unknown)"), memorystatus_level);
- memorystatus_update_jetsam_snapshot_entry_locked(p, kMemorystatusKilledDiagnostic, killtime);
- p->p_memstat_state |= P_MEMSTAT_DIAG_SUSPENDED;
- if (memorystatus_jetsam_policy & kPolicyDiagnoseFirst) {
- jetsam_diagnostic_suspended_one_active_proc = 1;
- printf("jetsam: returning after suspending first active proc - %d\n", aPid);
- }
-
- p = proc_ref_locked(p);
- proc_list_unlock();
- if (p) {
- task_suspend(p->task);
- if (priority) {
- *priority = aPid_ep;
- }
- proc_rele(p);
- killed = TRUE;
- }
-
- goto exit;
- } else
-#endif /* DEVELOPMENT || DEBUG */
- {
- /* Shift queue, update stats */
- memorystatus_update_jetsam_snapshot_entry_locked(p, cause, killtime);
-
- if (proc_ref_locked(p) == p) {
- proc_list_unlock();
- printf("%lu.%02d memorystatus: %s %d [%s] (%s %d) - memorystatus_available_pages: %d\n",
- (unsigned long)tv_sec, tv_msec,
- ((aPid_ep == JETSAM_PRIORITY_IDLE) ? "idle exiting pid" : "jetsam killing top process pid"),
- aPid, (*p->p_name ? p->p_name : "(unknown)"),
- jetsam_kill_cause_name[cause], aPid_ep, memorystatus_available_pages);
-
- /*
- * memorystatus_do_kill() drops a reference, so take another one so we can
- * continue to use this exit reason even after memorystatus_do_kill()
- * returns.
- */
- os_reason_ref(jetsam_reason);
-
- killed = memorystatus_do_kill(p, cause, jetsam_reason);
-
- /* Success? */
- if (killed) {
- if (priority) {
- *priority = aPid_ep;
- }
- proc_rele(p);
- kill_count++;
- goto exit;
- }
-
- /*
- * Failure - first unwind the state,
- * then fall through to restart the search.
- */
- proc_list_lock();
- proc_rele_locked(p);
- p->p_memstat_state &= ~P_MEMSTAT_TERMINATED;
- p->p_memstat_state |= P_MEMSTAT_ERROR;
- *errors += 1;
- }
-
- /*
- * Failure - restart the search.
- *
- * We might have raced with "p" exiting on another core, resulting in no
- * ref on "p". Or, we may have failed to kill "p".
- *
- * Either way, we fall thru to here, leaving the proc in the
- * P_MEMSTAT_TERMINATED state.
- *
- * And, we hold the the proc_list_lock at this point.
- */
-
- i = 0;
- next_p = memorystatus_get_first_proc_locked(&i, TRUE);
- }
- }
- }
-
- proc_list_unlock();
-
-exit:
- os_reason_free(jetsam_reason);
-
- /* Clear snapshot if freshly captured and no target was found */
- if (new_snapshot && !killed) {
- proc_list_lock();
- memorystatus_jetsam_snapshot->entry_count = memorystatus_jetsam_snapshot_count = 0;
- proc_list_unlock();
- }
-
- KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_MEMSTAT, BSD_MEMSTAT_JETSAM) | DBG_FUNC_END,
- memorystatus_available_pages, killed ? aPid : 0, kill_count, 0, 0);
-
- return killed;
-}
-
-/*
- * Jetsam aggressively
- */
-static boolean_t
-memorystatus_kill_top_process_aggressive(boolean_t any, uint32_t cause, os_reason_t jetsam_reason, int aggr_count,
- int32_t priority_max, uint32_t *errors)
-{
- pid_t aPid;
- proc_t p = PROC_NULL, next_p = PROC_NULL;
- boolean_t new_snapshot = FALSE, killed = FALSE;
- int kill_count = 0;
- unsigned int i = 0;
- int32_t aPid_ep = 0;
- unsigned int memorystatus_level_snapshot = 0;
- uint64_t killtime = 0;
- clock_sec_t tv_sec;
- clock_usec_t tv_usec;
- uint32_t tv_msec;
-
-#pragma unused(any)
-
- KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_MEMSTAT, BSD_MEMSTAT_JETSAM) | DBG_FUNC_START,
- memorystatus_available_pages, priority_max, 0, 0, 0);
-
- memorystatus_sort_bucket(JETSAM_PRIORITY_FOREGROUND, JETSAM_SORT_DEFAULT);
-
- proc_list_lock();
-
- next_p = memorystatus_get_first_proc_locked(&i, TRUE);
- while (next_p) {
-#if DEVELOPMENT || DEBUG
- int activeProcess;
- int procSuspendedForDiagnosis;
-#endif /* DEVELOPMENT || DEBUG */
-
- if ((unsigned int)(next_p->p_memstat_effectivepriority) != i) {
-
- /*
- * We have raced with next_p running on another core, as it has
- * moved to a different jetsam priority band. This means we have
- * lost our place in line while traversing the jetsam list. We
- * attempt to recover by rewinding to the beginning of the band
- * we were already traversing. By doing this, we do not guarantee
- * that no process escapes this aggressive march, but we can make
- * skipping an entire range of processes less likely. (PR-21069019)
- */
-
- MEMORYSTATUS_DEBUG(1, "memorystatus: aggressive%d: rewinding %s moved from band %d --> %d\n",
- aggr_count, (*next_p->p_name ? next_p->p_name : "unknown"), i, next_p->p_memstat_effectivepriority);
-
- next_p = memorystatus_get_first_proc_locked(&i, TRUE);
- continue;
- }
-
- p = next_p;
- next_p = memorystatus_get_next_proc_locked(&i, p, TRUE);
-
- if (p->p_memstat_effectivepriority > priority_max) {
- /*
- * Bail out of this killing spree if we have
- * reached beyond the priority_max jetsam band.
- * That is, we kill up to and through the
- * priority_max jetsam band.
- */
- proc_list_unlock();
- goto exit;
- }
-
-#if DEVELOPMENT || DEBUG
- activeProcess = p->p_memstat_state & P_MEMSTAT_FOREGROUND;
- procSuspendedForDiagnosis = p->p_memstat_state & P_MEMSTAT_DIAG_SUSPENDED;
-#endif /* DEVELOPMENT || DEBUG */
-
- aPid = p->p_pid;
- aPid_ep = p->p_memstat_effectivepriority;
-
- if (p->p_memstat_state & (P_MEMSTAT_ERROR | P_MEMSTAT_TERMINATED)) {
- continue;
- }
-
-#if DEVELOPMENT || DEBUG
- if ((memorystatus_jetsam_policy & kPolicyDiagnoseActive) && procSuspendedForDiagnosis) {
- printf("jetsam: continuing after ignoring proc suspended already for diagnosis - %d\n", aPid);
- continue;
- }
-#endif /* DEVELOPMENT || DEBUG */
-
- /*
- * Capture a snapshot if none exists.
- */
- if (memorystatus_jetsam_snapshot_count == 0) {
- memorystatus_init_jetsam_snapshot_locked(NULL,0);
- new_snapshot = TRUE;
- }
-
- /*
- * Mark as terminated so that if exit1() indicates success, but the process (for example)
- * is blocked in task_exception_notify(), it'll be skipped if encountered again - see
- * <rdar://problem/13553476>. This is cheaper than examining P_LEXIT, which requires the
- * acquisition of the proc lock.
- */
- p->p_memstat_state |= P_MEMSTAT_TERMINATED;
-
- killtime = mach_absolute_time();
- absolutetime_to_microtime(killtime, &tv_sec, &tv_usec);
- tv_msec = tv_usec / 1000;
-
- /* Shift queue, update stats */
- memorystatus_update_jetsam_snapshot_entry_locked(p, cause, killtime);
-
- /*
- * In order to kill the target process, we will drop the proc_list_lock.
- * To guaranteee that p and next_p don't disappear out from under the lock,
- * we must take a ref on both.
- * If we cannot get a reference, then it's likely we've raced with
- * that process exiting on another core.
- */
- if (proc_ref_locked(p) == p) {
- if (next_p) {
- while (next_p && (proc_ref_locked(next_p) != next_p)) {
- proc_t temp_p;
-
- /*
- * We must have raced with next_p exiting on another core.
- * Recover by getting the next eligible process in the band.
- */
-
- MEMORYSTATUS_DEBUG(1, "memorystatus: aggressive%d: skipping %d [%s] (exiting?)\n",
- aggr_count, next_p->p_pid, (*next_p->p_name ? next_p->p_name : "(unknown)"));
-
- temp_p = next_p;
- next_p = memorystatus_get_next_proc_locked(&i, temp_p, TRUE);
- }
- }
- proc_list_unlock();
-
- printf("%lu.%01d memorystatus: aggressive%d: %s %d [%s] (%s %d) - memorystatus_available_pages: %d\n",
- (unsigned long)tv_sec, tv_msec, aggr_count,
- ((aPid_ep == JETSAM_PRIORITY_IDLE) ? "idle exiting pid" : "jetsam killing pid"),
- aPid, (*p->p_name ? p->p_name : "(unknown)"),
- jetsam_kill_cause_name[cause], aPid_ep, memorystatus_available_pages);
-
- memorystatus_level_snapshot = memorystatus_level;
-
- /*
- * memorystatus_do_kill() drops a reference, so take another one so we can
- * continue to use this exit reason even after memorystatus_do_kill()
- * returns.
- */
- os_reason_ref(jetsam_reason);
- killed = memorystatus_do_kill(p, cause, jetsam_reason);
-
- /* Success? */
- if (killed) {
- proc_rele(p);
- kill_count++;
- p = NULL;
- killed = FALSE;
-
- /*
- * Continue the killing spree.
- */
- proc_list_lock();
- if (next_p) {
- proc_rele_locked(next_p);
- }
-
- if (aPid_ep == JETSAM_PRIORITY_FOREGROUND && memorystatus_aggressive_jetsam_lenient == TRUE) {
- if (memorystatus_level > memorystatus_level_snapshot && ((memorystatus_level - memorystatus_level_snapshot) >= AGGRESSIVE_JETSAM_LENIENT_MODE_THRESHOLD)) {
-#if DEVELOPMENT || DEBUG
- printf("Disabling Lenient mode after one-time deployment.\n");
-#endif /* DEVELOPMENT || DEBUG */
- memorystatus_aggressive_jetsam_lenient = FALSE;
- break;
- }
- }
-
- continue;
- }
-
- /*
- * Failure - first unwind the state,
- * then fall through to restart the search.
- */
- proc_list_lock();
- proc_rele_locked(p);
- if (next_p) {
- proc_rele_locked(next_p);
- }
- p->p_memstat_state &= ~P_MEMSTAT_TERMINATED;
- p->p_memstat_state |= P_MEMSTAT_ERROR;
- *errors += 1;
- p = NULL;
- }
-
- /*
- * Failure - restart the search at the beginning of
- * the band we were already traversing.
- *
- * We might have raced with "p" exiting on another core, resulting in no
- * ref on "p". Or, we may have failed to kill "p".
- *
- * Either way, we fall thru to here, leaving the proc in the
- * P_MEMSTAT_TERMINATED or P_MEMSTAT_ERROR state.
- *
- * And, we hold the the proc_list_lock at this point.
- */
-
- next_p = memorystatus_get_first_proc_locked(&i, TRUE);
- }
-
- proc_list_unlock();
-
-exit:
- os_reason_free(jetsam_reason);
-
- /* Clear snapshot if freshly captured and no target was found */
- if (new_snapshot && (kill_count == 0)) {
- memorystatus_jetsam_snapshot->entry_count = memorystatus_jetsam_snapshot_count = 0;
- }
-
- KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_MEMSTAT, BSD_MEMSTAT_JETSAM) | DBG_FUNC_END,
- memorystatus_available_pages, killed ? aPid : 0, kill_count, 0, 0);
-
- if (kill_count > 0) {
- return(TRUE);
- }
- else {
- return(FALSE);
- }
-}
-
-static boolean_t
-memorystatus_kill_hiwat_proc(uint32_t *errors)
-{
- pid_t aPid = 0;
- proc_t p = PROC_NULL, next_p = PROC_NULL;
- boolean_t new_snapshot = FALSE, killed = FALSE;
- int kill_count = 0;
- unsigned int i = 0;
- uint32_t aPid_ep;
- uint64_t killtime = 0;
- clock_sec_t tv_sec;
- clock_usec_t tv_usec;
- uint32_t tv_msec;
- os_reason_t jetsam_reason = OS_REASON_NULL;
- KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_MEMSTAT, BSD_MEMSTAT_JETSAM_HIWAT) | DBG_FUNC_START,
- memorystatus_available_pages, 0, 0, 0, 0);
-
- jetsam_reason = os_reason_create(OS_REASON_JETSAM, JETSAM_REASON_MEMORY_HIGHWATER);
- if (jetsam_reason == OS_REASON_NULL) {
- printf("memorystatus_kill_hiwat_proc: failed to allocate exit reason\n");
- }
-
- proc_list_lock();
-
- next_p = memorystatus_get_first_proc_locked(&i, TRUE);
- while (next_p) {
- uint64_t footprint_in_bytes = 0;
- uint64_t memlimit_in_bytes = 0;
- boolean_t skip = 0;
-
- p = next_p;
- next_p = memorystatus_get_next_proc_locked(&i, p, TRUE);
-
- aPid = p->p_pid;
- aPid_ep = p->p_memstat_effectivepriority;
-
- if (p->p_memstat_state & (P_MEMSTAT_ERROR | P_MEMSTAT_TERMINATED)) {
- continue;
- }
-
- /* skip if no limit set */
- if (p->p_memstat_memlimit <= 0) {
- continue;
- }
-
-#if 0
- /*
- * No need to consider P_MEMSTAT_MEMLIMIT_BACKGROUND anymore.
- * Background limits are described via the inactive limit slots.
- * Their fatal/non-fatal setting will drive whether or not to be
- * considered in this kill path.
- */
-
- /* skip if a currently inapplicable limit is encountered */
- if ((p->p_memstat_state & P_MEMSTAT_MEMLIMIT_BACKGROUND) && (p->p_memstat_effectivepriority >= JETSAM_PRIORITY_FOREGROUND)) {
- continue;
- }
-#endif
- footprint_in_bytes = get_task_phys_footprint(p->task);
- memlimit_in_bytes = (((uint64_t)p->p_memstat_memlimit) * 1024ULL * 1024ULL); /* convert MB to bytes */
- skip = (footprint_in_bytes <= memlimit_in_bytes);
-
-#if DEVELOPMENT || DEBUG
- if (!skip && (memorystatus_jetsam_policy & kPolicyDiagnoseActive)) {
- if (p->p_memstat_state & P_MEMSTAT_DIAG_SUSPENDED) {
- continue;
- }
- }
-#endif /* DEVELOPMENT || DEBUG */
-
-#if CONFIG_FREEZE
- if (!skip) {
- if (p->p_memstat_state & P_MEMSTAT_LOCKED) {
- skip = TRUE;
- } else {
- skip = FALSE;
- }
- }
-#endif
-
- if (skip) {
- continue;
- } else {
-#if DEVELOPMENT || DEBUG
- MEMORYSTATUS_DEBUG(1, "jetsam: %s pid %d [%s] - %lld Mb > 1 (%d Mb)\n",
- (memorystatus_jetsam_policy & kPolicyDiagnoseActive) ? "suspending": "killing",
- aPid, (*p->p_name ? p->p_name : "unknown"),
- (footprint_in_bytes / (1024ULL * 1024ULL)), /* converted bytes to MB */
- p->p_memstat_memlimit);
-#endif /* DEVELOPMENT || DEBUG */
-
- if (memorystatus_jetsam_snapshot_count == 0) {
- memorystatus_init_jetsam_snapshot_locked(NULL,0);
- new_snapshot = TRUE;
- }
-
- p->p_memstat_state |= P_MEMSTAT_TERMINATED;
-
- killtime = mach_absolute_time();
- absolutetime_to_microtime(killtime, &tv_sec, &tv_usec);
- tv_msec = tv_usec / 1000;
-
-#if DEVELOPMENT || DEBUG
- if (memorystatus_jetsam_policy & kPolicyDiagnoseActive) {
- MEMORYSTATUS_DEBUG(1, "jetsam: pid %d suspended for diagnosis - memorystatus_available_pages: %d\n", aPid, memorystatus_available_pages);
- memorystatus_update_jetsam_snapshot_entry_locked(p, kMemorystatusKilledDiagnostic, killtime);
- p->p_memstat_state |= P_MEMSTAT_DIAG_SUSPENDED;
-
- p = proc_ref_locked(p);
- proc_list_unlock();
- if (p) {
- task_suspend(p->task);
- proc_rele(p);
- killed = TRUE;
- }
-
- goto exit;
- } else
-#endif /* DEVELOPMENT || DEBUG */
- {
- memorystatus_update_jetsam_snapshot_entry_locked(p, kMemorystatusKilledHiwat, killtime);
-
- if (proc_ref_locked(p) == p) {
- proc_list_unlock();
-
- printf("%lu.%02d memorystatus: jetsam killing pid %d [%s] (highwater %d) - memorystatus_available_pages: %d\n",
- (unsigned long)tv_sec, tv_msec, aPid, (*p->p_name ? p->p_name : "(unknown)"), aPid_ep, memorystatus_available_pages);
-
- /*
- * memorystatus_do_kill drops a reference, so take another one so we can
- * continue to use this exit reason even after memorystatus_do_kill()
- * returns
- */
- os_reason_ref(jetsam_reason);
-
- killed = memorystatus_do_kill(p, kMemorystatusKilledHiwat, jetsam_reason);
-
- /* Success? */
- if (killed) {
- proc_rele(p);
- kill_count++;
- goto exit;
- }
-
- /*
- * Failure - first unwind the state,
- * then fall through to restart the search.
- */
- proc_list_lock();
- proc_rele_locked(p);
- p->p_memstat_state &= ~P_MEMSTAT_TERMINATED;
- p->p_memstat_state |= P_MEMSTAT_ERROR;
- *errors += 1;
- }
-
- /*
- * Failure - restart the search.
- *
- * We might have raced with "p" exiting on another core, resulting in no
- * ref on "p". Or, we may have failed to kill "p".
- *
- * Either way, we fall thru to here, leaving the proc in the
- * P_MEMSTAT_TERMINATED state.
- *
- * And, we hold the the proc_list_lock at this point.
- */
-
- i = 0;
- next_p = memorystatus_get_first_proc_locked(&i, TRUE);
- }
- }
- }
-
- proc_list_unlock();
-
-exit:
- os_reason_free(jetsam_reason);
-
- /* Clear snapshot if freshly captured and no target was found */
- if (new_snapshot && !killed) {
- proc_list_lock();
- memorystatus_jetsam_snapshot->entry_count = memorystatus_jetsam_snapshot_count = 0;
- proc_list_unlock();
- }
-
- KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_MEMSTAT, BSD_MEMSTAT_JETSAM_HIWAT) | DBG_FUNC_END,
- memorystatus_available_pages, killed ? aPid : 0, kill_count, 0, 0);
-
- return killed;
-}
-
-/*
- * Jetsam a process pinned in the elevated band.
- *
- * Return: true -- at least one pinned process was jetsammed
- * false -- no pinned process was jetsammed
- */
-static boolean_t
-memorystatus_kill_elevated_process(uint32_t cause, os_reason_t jetsam_reason, int aggr_count, uint32_t *errors)
-{
- pid_t aPid = 0;
- proc_t p = PROC_NULL, next_p = PROC_NULL;
- boolean_t new_snapshot = FALSE, killed = FALSE;
- int kill_count = 0;
- unsigned int i = JETSAM_PRIORITY_ELEVATED_INACTIVE;
- uint32_t aPid_ep;
- uint64_t killtime = 0;
- clock_sec_t tv_sec;
- clock_usec_t tv_usec;
- uint32_t tv_msec;
-
-
- KERNEL_DEBUG_CONSTANT(BSDDBG_CODE(DBG_BSD_MEMSTAT, BSD_MEMSTAT_JETSAM) | DBG_FUNC_START,
- memorystatus_available_pages, 0, 0, 0, 0);
-
- proc_list_lock();
-
- next_p = memorystatus_get_first_proc_locked(&i, FALSE);
- while (next_p) {
-
- p = next_p;
- next_p = memorystatus_get_next_proc_locked(&i, p, FALSE);
-
- aPid = p->p_pid;
- aPid_ep = p->p_memstat_effectivepriority;
-
- /*
- * Only pick a process pinned in this elevated band
- */
- if (!(p->p_memstat_state & P_MEMSTAT_USE_ELEVATED_INACTIVE_BAND)) {
- continue;
- }
-
- if (p->p_memstat_state & (P_MEMSTAT_ERROR | P_MEMSTAT_TERMINATED)) {
- continue;
- }
-
-#if CONFIG_FREEZE
- if (p->p_memstat_state & P_MEMSTAT_LOCKED) {
- continue;
- }
-#endif
-
-#if DEVELOPMENT || DEBUG
- MEMORYSTATUS_DEBUG(1, "jetsam: elevated%d process pid %d [%s] - memorystatus_available_pages: %d\n",
- aggr_count,
- aPid, (*p->p_name ? p->p_name : "unknown"),
- memorystatus_available_pages);
-#endif /* DEVELOPMENT || DEBUG */
-
- if (memorystatus_jetsam_snapshot_count == 0) {
- memorystatus_init_jetsam_snapshot_locked(NULL,0);
- new_snapshot = TRUE;