+ if (task->pidsuspended) {
+ kr = KERN_FAILURE;
+ goto out;
+ }
+
+ task->pidsuspended = TRUE;
+
+ kr = place_task_hold(task, TASK_HOLD_PIDSUSPEND);
+ if (kr != KERN_SUCCESS) {
+ task->pidsuspended = FALSE;
+ }
+out:
+ return(kr);
+}
+
+
+/*
+ * task_pidsuspend:
+ *
+ * Suspends a task by placing a hold on its threads.
+ *
+ * Conditions:
+ * The caller holds a reference to the task
+ */
+kern_return_t
+task_pidsuspend(
+ register task_t task)
+{
+ kern_return_t kr;
+
+ if (task == TASK_NULL || task == kernel_task)
+ return (KERN_INVALID_ARGUMENT);
+
+ task_lock(task);
+
+ kr = task_pidsuspend_locked(task);
+
+ task_unlock(task);
+
+ return (kr);
+}
+
+/* If enabled, we bring all the frozen pages back in prior to resumption; otherwise, they're faulted back in on demand */
+#define THAW_ON_RESUME 1
+
+/*
+ * task_pidresume:
+ * Resumes a previously suspended task.
+ *
+ * Conditions:
+ * The caller holds a reference to the task
+ */
+kern_return_t
+task_pidresume(
+ register task_t task)
+{
+ kern_return_t kr;
+
+ if (task == TASK_NULL || task == kernel_task)
+ return (KERN_INVALID_ARGUMENT);
+
+ task_lock(task);
+
+#if (CONFIG_FREEZE && THAW_ON_RESUME)
+
+ while (task->changing_freeze_state) {
+
+ assert_wait((event_t)&task->changing_freeze_state, THREAD_UNINT);
+ task_unlock(task);
+ thread_block(THREAD_CONTINUE_NULL);
+
+ task_lock(task);
+ }
+ task->changing_freeze_state = TRUE;
+#endif
+
+ kr = release_task_hold(task, TASK_HOLD_PIDSUSPEND);
+
+ task_unlock(task);
+
+#if (CONFIG_FREEZE && THAW_ON_RESUME)
+ if ((kr == KERN_SUCCESS) && (task->frozen == TRUE)) {
+
+ if (COMPRESSED_PAGER_IS_ACTIVE || DEFAULT_FREEZER_COMPRESSED_PAGER_IS_ACTIVE) {
+
+ kr = KERN_SUCCESS;
+ } else {
+
+ kr = vm_map_thaw(task->map);
+ }
+ }
+ task_lock(task);
+
+ if (kr == KERN_SUCCESS)
+ task->frozen = FALSE;
+ task->changing_freeze_state = FALSE;
+ thread_wakeup(&task->changing_freeze_state);
+
+ task_unlock(task);
+#endif
+
+ return (kr);
+}
+
+#if CONFIG_FREEZE
+
+/*
+ * task_freeze:
+ *
+ * Freeze a task.
+ *
+ * Conditions:
+ * The caller holds a reference to the task
+ */
+kern_return_t
+task_freeze(
+ register task_t task,
+ uint32_t *purgeable_count,
+ uint32_t *wired_count,
+ uint32_t *clean_count,
+ uint32_t *dirty_count,
+ uint32_t dirty_budget,
+ boolean_t *shared,
+ boolean_t walk_only)
+{
+ kern_return_t kr;
+
+ if (task == TASK_NULL || task == kernel_task)
+ return (KERN_INVALID_ARGUMENT);
+
+ task_lock(task);
+
+ while (task->changing_freeze_state) {
+
+ assert_wait((event_t)&task->changing_freeze_state, THREAD_UNINT);
+ task_unlock(task);
+ thread_block(THREAD_CONTINUE_NULL);
+
+ task_lock(task);
+ }
+ if (task->frozen) {
+ task_unlock(task);
+ return (KERN_FAILURE);
+ }
+ task->changing_freeze_state = TRUE;
+
+ task_unlock(task);
+
+ if (walk_only) {
+ kr = vm_map_freeze_walk(task->map, purgeable_count, wired_count, clean_count, dirty_count, dirty_budget, shared);
+ } else {
+ kr = vm_map_freeze(task->map, purgeable_count, wired_count, clean_count, dirty_count, dirty_budget, shared);
+ }
+
+ task_lock(task);
+
+ if (walk_only == FALSE && kr == KERN_SUCCESS)
+ task->frozen = TRUE;
+ task->changing_freeze_state = FALSE;
+ thread_wakeup(&task->changing_freeze_state);
+
+ task_unlock(task);
+
+ return (kr);
+}
+
+/*
+ * task_thaw:
+ *
+ * Thaw a currently frozen task.
+ *
+ * Conditions:
+ * The caller holds a reference to the task
+ */
+extern void
+vm_consider_waking_compactor_swapper(void);
+
+kern_return_t
+task_thaw(
+ register task_t task)
+{
+ kern_return_t kr;
+
+ if (task == TASK_NULL || task == kernel_task)
+ return (KERN_INVALID_ARGUMENT);
+
+ task_lock(task);
+
+ while (task->changing_freeze_state) {
+
+ assert_wait((event_t)&task->changing_freeze_state, THREAD_UNINT);
+ task_unlock(task);
+ thread_block(THREAD_CONTINUE_NULL);
+
+ task_lock(task);
+ }
+ if (!task->frozen) {
+ task_unlock(task);
+ return (KERN_FAILURE);
+ }
+ task->changing_freeze_state = TRUE;
+
+ if (DEFAULT_PAGER_IS_ACTIVE || DEFAULT_FREEZER_IS_ACTIVE) {
+ task_unlock(task);
+
+ kr = vm_map_thaw(task->map);
+
+ task_lock(task);
+
+ if (kr == KERN_SUCCESS)
+ task->frozen = FALSE;
+ } else {
+ task->frozen = FALSE;
+ kr = KERN_SUCCESS;
+ }
+
+ task->changing_freeze_state = FALSE;
+ thread_wakeup(&task->changing_freeze_state);
+
+ task_unlock(task);
+
+ if (COMPRESSED_PAGER_IS_ACTIVE || DEFAULT_FREEZER_COMPRESSED_PAGER_IS_ACTIVE) {
+ vm_consider_waking_compactor_swapper();
+ }
+
+ return (kr);
+}
+
+#endif /* CONFIG_FREEZE */
+
+kern_return_t
+host_security_set_task_token(
+ host_security_t host_security,
+ task_t task,
+ security_token_t sec_token,
+ audit_token_t audit_token,
+ host_priv_t host_priv)
+{
+ ipc_port_t host_port;
+ kern_return_t kr;
+
+ if (task == TASK_NULL)
+ return(KERN_INVALID_ARGUMENT);
+
+ if (host_security == HOST_NULL)
+ return(KERN_INVALID_SECURITY);
+
+ task_lock(task);
+ task->sec_token = sec_token;
+ task->audit_token = audit_token;
+
+ task_unlock(task);
+
+ if (host_priv != HOST_PRIV_NULL) {
+ kr = host_get_host_priv_port(host_priv, &host_port);
+ } else {
+ kr = host_get_host_port(host_priv_self(), &host_port);
+ }
+ assert(kr == KERN_SUCCESS);
+ kr = task_set_special_port(task, TASK_HOST_PORT, host_port);
+ return(kr);
+}
+
+/*
+ * This routine was added, pretty much exclusively, for registering the
+ * RPC glue vector for in-kernel short circuited tasks. Rather than
+ * removing it completely, I have only disabled that feature (which was
+ * the only feature at the time). It just appears that we are going to
+ * want to add some user data to tasks in the future (i.e. bsd info,
+ * task names, etc...), so I left it in the formal task interface.
+ */
+kern_return_t
+task_set_info(
+ task_t task,
+ task_flavor_t flavor,
+ __unused task_info_t task_info_in, /* pointer to IN array */
+ __unused mach_msg_type_number_t task_info_count)
+{
+ if (task == TASK_NULL)
+ return(KERN_INVALID_ARGUMENT);
+
+ switch (flavor) {
+ default:
+ return (KERN_INVALID_ARGUMENT);
+ }
+ return (KERN_SUCCESS);
+}
+
+kern_return_t
+task_info(
+ task_t task,
+ task_flavor_t flavor,
+ task_info_t task_info_out,
+ mach_msg_type_number_t *task_info_count)
+{
+ kern_return_t error = KERN_SUCCESS;
+
+ if (task == TASK_NULL)
+ return (KERN_INVALID_ARGUMENT);
+
+ task_lock(task);
+
+ if ((task != current_task()) && (!task->active)) {
+ task_unlock(task);
+ return (KERN_INVALID_ARGUMENT);
+ }
+
+ switch (flavor) {
+
+ case TASK_BASIC_INFO_32:
+ case TASK_BASIC2_INFO_32:
+ {
+ task_basic_info_32_t basic_info;
+ vm_map_t map;
+ clock_sec_t secs;
+ clock_usec_t usecs;
+
+ if (*task_info_count < TASK_BASIC_INFO_32_COUNT) {
+ error = KERN_INVALID_ARGUMENT;
+ break;
+ }
+
+ basic_info = (task_basic_info_32_t)task_info_out;
+
+ map = (task == kernel_task)? kernel_map: task->map;
+ basic_info->virtual_size = (typeof(basic_info->virtual_size))map->size;
+ if (flavor == TASK_BASIC2_INFO_32) {
+ /*
+ * The "BASIC2" flavor gets the maximum resident
+ * size instead of the current resident size...
+ */
+ basic_info->resident_size = pmap_resident_max(map->pmap);
+ } else {
+ basic_info->resident_size = pmap_resident_count(map->pmap);
+ }
+ basic_info->resident_size *= PAGE_SIZE;
+
+ basic_info->policy = ((task != kernel_task)?
+ POLICY_TIMESHARE: POLICY_RR);
+ basic_info->suspend_count = task->user_stop_count;
+
+ absolutetime_to_microtime(task->total_user_time, &secs, &usecs);
+ basic_info->user_time.seconds =
+ (typeof(basic_info->user_time.seconds))secs;
+ basic_info->user_time.microseconds = usecs;
+
+ absolutetime_to_microtime(task->total_system_time, &secs, &usecs);
+ basic_info->system_time.seconds =
+ (typeof(basic_info->system_time.seconds))secs;
+ basic_info->system_time.microseconds = usecs;
+
+ *task_info_count = TASK_BASIC_INFO_32_COUNT;
+ break;
+ }
+
+ case TASK_BASIC_INFO_64:
+ {
+ task_basic_info_64_t basic_info;
+ vm_map_t map;
+ clock_sec_t secs;
+ clock_usec_t usecs;
+
+ if (*task_info_count < TASK_BASIC_INFO_64_COUNT) {
+ error = KERN_INVALID_ARGUMENT;
+ break;
+ }
+
+ basic_info = (task_basic_info_64_t)task_info_out;
+
+ map = (task == kernel_task)? kernel_map: task->map;
+ basic_info->virtual_size = map->size;
+ basic_info->resident_size =
+ (mach_vm_size_t)(pmap_resident_count(map->pmap))
+ * PAGE_SIZE_64;
+
+ basic_info->policy = ((task != kernel_task)?
+ POLICY_TIMESHARE: POLICY_RR);
+ basic_info->suspend_count = task->user_stop_count;
+
+ absolutetime_to_microtime(task->total_user_time, &secs, &usecs);
+ basic_info->user_time.seconds =
+ (typeof(basic_info->user_time.seconds))secs;
+ basic_info->user_time.microseconds = usecs;
+
+ absolutetime_to_microtime(task->total_system_time, &secs, &usecs);
+ basic_info->system_time.seconds =
+ (typeof(basic_info->system_time.seconds))secs;
+ basic_info->system_time.microseconds = usecs;
+
+ *task_info_count = TASK_BASIC_INFO_64_COUNT;
+ break;
+ }
+
+ case MACH_TASK_BASIC_INFO:
+ {
+ mach_task_basic_info_t basic_info;
+ vm_map_t map;
+ clock_sec_t secs;
+ clock_usec_t usecs;
+
+ if (*task_info_count < MACH_TASK_BASIC_INFO_COUNT) {
+ error = KERN_INVALID_ARGUMENT;
+ break;
+ }
+
+ basic_info = (mach_task_basic_info_t)task_info_out;
+
+ map = (task == kernel_task) ? kernel_map : task->map;
+
+ basic_info->virtual_size = map->size;
+
+ basic_info->resident_size =
+ (mach_vm_size_t)(pmap_resident_count(map->pmap));
+ basic_info->resident_size *= PAGE_SIZE_64;
+
+ basic_info->resident_size_max =
+ (mach_vm_size_t)(pmap_resident_max(map->pmap));
+ basic_info->resident_size_max *= PAGE_SIZE_64;
+
+ basic_info->policy = ((task != kernel_task) ?
+ POLICY_TIMESHARE : POLICY_RR);
+
+ basic_info->suspend_count = task->user_stop_count;
+
+ absolutetime_to_microtime(task->total_user_time, &secs, &usecs);
+ basic_info->user_time.seconds =
+ (typeof(basic_info->user_time.seconds))secs;
+ basic_info->user_time.microseconds = usecs;
+
+ absolutetime_to_microtime(task->total_system_time, &secs, &usecs);
+ basic_info->system_time.seconds =
+ (typeof(basic_info->system_time.seconds))secs;
+ basic_info->system_time.microseconds = usecs;
+
+ *task_info_count = MACH_TASK_BASIC_INFO_COUNT;
+ break;
+ }
+
+ case TASK_THREAD_TIMES_INFO:
+ {
+ register task_thread_times_info_t times_info;
+ register thread_t thread;
+
+ if (*task_info_count < TASK_THREAD_TIMES_INFO_COUNT) {
+ error = KERN_INVALID_ARGUMENT;
+ break;
+ }
+
+ times_info = (task_thread_times_info_t) task_info_out;