X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/ff6e181ae92fc6f1e89841290f461d1f2f9badd9..bd504ef0e0b883cdd7917b73b3574eb9ce669905:/osfmk/kern/task_policy.c diff --git a/osfmk/kern/task_policy.c b/osfmk/kern/task_policy.c index f97d9db53..2cbb2daa2 100644 --- a/osfmk/kern/task_policy.c +++ b/osfmk/kern/task_policy.c @@ -1,14 +1,19 @@ /* * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER @@ -18,7 +23,7 @@ * Please see the License for the specific language governing rights and * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ #include @@ -26,12 +31,130 @@ #include #include +#include +#include +#include +#include +#include +#include +#if CONFIG_EMBEDDED +#include +#include +#endif /* CONFIG_EMBEDDED */ +#include + +#if CONFIG_MEMORYSTATUS +extern void memorystatus_on_suspend(int pid); +extern void memorystatus_on_resume(int pid); +#endif + +static int proc_apply_bgtaskpolicy_internal(task_t, int, int); +static int proc_restore_bgtaskpolicy_internal(task_t, int, int, int); +static int task_get_cpuusage(task_t task, uint32_t * percentagep, uint64_t * intervalp, uint64_t * deadlinep); +int task_set_cpuusage(task_t task, uint64_t percentage, uint64_t interval, uint64_t deadline, int scope); +static int task_clear_cpuusage_locked(task_t task); +static int task_apply_resource_actions(task_t task, int type); +static void task_priority(task_t task, integer_t priority, integer_t max_priority); +static kern_return_t task_role_default_handler(task_t task, task_role_t role); +void task_action_cpuusage(thread_call_param_t param0, thread_call_param_t param1); +static int proc_apply_bgthreadpolicy_locked(thread_t thread, int selfset); +static void restore_bgthreadpolicy_locked(thread_t thread, int selfset, int importance); +static int proc_get_task_selfdiskacc_internal(task_t task, thread_t thread); +extern void unthrottle_thread(void * uthread); + +#if CONFIG_EMBEDDED +static void set_thread_appbg(thread_t thread, int setbg,int importance); +static void apply_bgthreadpolicy_external(thread_t thread); +static void add_taskwatch_locked(task_t task, task_watch_t * twp); +static void remove_taskwatch_locked(task_t task, task_watch_t * twp); +static void task_watch_lock(void); +static void task_watch_unlock(void); +static void apply_appstate_watchers(task_t task, int setbg); +void proc_apply_task_networkbg_internal(void *, thread_t); +void proc_restore_task_networkbg_internal(void *, thread_t); +int proc_pid(void * proc); + +typedef struct thread_watchlist { + thread_t thread; /* thread being worked on for taskwatch action */ + int importance; /* importance to be restored if thread is being made active */ +} thread_watchlist_t; + +#endif /* CONFIG_EMBEDDED */ + + +process_policy_t default_task_proc_policy = {0, + 0, + TASK_POLICY_RESOURCE_ATTRIBUTE_NONE, + TASK_POLICY_RESOURCE_ATTRIBUTE_NONE, + TASK_POLICY_RESOURCE_ATTRIBUTE_NONE, + TASK_POLICY_RESOURCE_ATTRIBUTE_NONE, + TASK_POLICY_RESOURCE_ATTRIBUTE_NONE, + TASK_POLICY_RESOURCE_ATTRIBUTE_NONE, + TASK_POLICY_RESOURCE_ATTRIBUTE_NONE, + 0, + TASK_POLICY_HWACCESS_CPU_ATTRIBUTE_FULLACCESS, + TASK_POLICY_HWACCESS_NET_ATTRIBUTE_FULLACCESS, + TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_FULLACCESS, + TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_NORMAL, + TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL + }; + +process_policy_t default_task_null_policy = {0, + 0, + TASK_POLICY_RESOURCE_ATTRIBUTE_NONE, + TASK_POLICY_RESOURCE_ATTRIBUTE_NONE, + TASK_POLICY_RESOURCE_ATTRIBUTE_NONE, + TASK_POLICY_RESOURCE_ATTRIBUTE_NONE, + TASK_POLICY_RESOURCE_ATTRIBUTE_NONE, + TASK_POLICY_RESOURCE_ATTRIBUTE_NONE, + TASK_POLICY_RESOURCE_ATTRIBUTE_NONE, + 0, + TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NONE, + TASK_POLICY_HWACCESS_NET_ATTRIBUTE_NONE, + TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NONE, + TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_NORMAL, + TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE + }; + + + +/* + * This routine should always be called with the task lock held. + * This routine handles Default operations for TASK_FOREGROUND_APPLICATION + * and TASK_BACKGROUND_APPLICATION of task with no special app type. + */ +static kern_return_t +task_role_default_handler(task_t task, task_role_t role) +{ + kern_return_t result = KERN_SUCCESS; + + switch (task->role) { + case TASK_FOREGROUND_APPLICATION: + case TASK_BACKGROUND_APPLICATION: + case TASK_UNSPECIFIED: + /* if there are no process wide backgrounding ... */ + if ((task->ext_appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) && + (task->appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE)) { + task_priority(task, + ((role == TASK_FOREGROUND_APPLICATION)? + BASEPRI_FOREGROUND: BASEPRI_BACKGROUND), + task->max_priority); + } + task->role = role; + break; + + case TASK_CONTROL_APPLICATION: + case TASK_RENICED: + /* else fail silently */ + break; + + default: + result = KERN_INVALID_ARGUMENT; + break; + } + return(result); +} -static void -task_priority( - task_t task, - integer_t priority, - integer_t max_priority); kern_return_t task_policy_set( @@ -41,6 +164,8 @@ task_policy_set( mach_msg_type_number_t count) { kern_return_t result = KERN_SUCCESS; + void * bsdinfo = NULL; + int setbg = 0; if (task == TASK_NULL || task == kernel_task) return (KERN_INVALID_ARGUMENT); @@ -49,62 +174,112 @@ task_policy_set( case TASK_CATEGORY_POLICY: { - task_category_policy_t info = (task_category_policy_t)policy_info; + task_category_policy_t info = (task_category_policy_t)policy_info; if (count < TASK_CATEGORY_POLICY_COUNT) return (KERN_INVALID_ARGUMENT); +#if CONFIG_EMBEDDED + if ((current_task() == task) && (info != NULL) && + (info->role != TASK_THROTTLE_APPLICATION)) + return (KERN_INVALID_ARGUMENT); +#endif + task_lock(task); + switch(info->role) { + case TASK_FOREGROUND_APPLICATION : { + if (task->ext_appliedstate.apptype == PROC_POLICY_OSX_APPTYPE_NONE) { + result = task_role_default_handler(task, info->role); + } else { + switch (task->ext_appliedstate.apptype) { +#if !CONFIG_EMBEDDED + case PROC_POLICY_OSX_APPTYPE_TAL: + /* Move the app to foreground with no DarwinBG */ + proc_restore_bgtaskpolicy_internal(task, 1, 1, BASEPRI_FOREGROUND); + bsdinfo = task->bsd_info; + setbg = 0; + break; - if ( info->role == TASK_FOREGROUND_APPLICATION || - info->role == TASK_BACKGROUND_APPLICATION ) { - switch (task->role) { - - case TASK_FOREGROUND_APPLICATION: - case TASK_BACKGROUND_APPLICATION: - case TASK_UNSPECIFIED: - task_priority(task, - ((info->role == TASK_FOREGROUND_APPLICATION)? - BASEPRI_FOREGROUND: BASEPRI_BACKGROUND), - task->max_priority); - task->role = info->role; - break; + case PROC_POLICY_OSX_APPTYPE_DBCLIENT: + /* reset the apptype so enforcement on background/foregound */ + task->ext_appliedstate.apptype = PROC_POLICY_OSX_APPTYPE_NONE; + /* Internal application and make it foreground pri */ + proc_restore_bgtaskpolicy_internal(task, 1, 0, BASEPRI_FOREGROUND); + bsdinfo = task->bsd_info; + setbg = 0; + break; +#endif /* !CONFIG_EMBEDDED */ - case TASK_CONTROL_APPLICATION: - case TASK_RENICED: - /* fail silently */ - break; + default: + /* the app types cannot be in CONTROL, GRAPHICS STATE, so it will de default state here */ + task_priority(task, BASEPRI_FOREGROUND, task->max_priority); + break; - default: - result = KERN_INVALID_ARGUMENT; - break; + } /* switch (task->ext_appliedstate.apptype) */ + task->role = TASK_FOREGROUND_APPLICATION; + } } - } - else - if (info->role == TASK_CONTROL_APPLICATION) { - if ( task != current_task() || - task->sec_token.val[0] != 0 ) + break; + + case TASK_BACKGROUND_APPLICATION : { + if (task->ext_appliedstate.apptype == PROC_POLICY_OSX_APPTYPE_NONE) { + result = task_role_default_handler(task, info->role); + } else { /* apptype != PROC_POLICY_OSX_APPTYPE_NONE */ + switch (task->ext_appliedstate.apptype) { +#if !CONFIG_EMBEDDED + case PROC_POLICY_OSX_APPTYPE_TAL: + /* TAL apps will get Darwin backgrounded if not already set */ + if (task->ext_appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) { + proc_apply_bgtaskpolicy_internal(task, 1, 1); + bsdinfo = task->bsd_info; + setbg = 1; + } + break; +#endif /* !CONFIG_EMBEDDED */ + default: + task_priority(task, BASEPRI_BACKGROUND, task->max_priority); + break; + } /* switch (task->ext_appliedstate.apptype) */ + task->role = TASK_BACKGROUND_APPLICATION; + } + } + break; + + case TASK_CONTROL_APPLICATION: + if (task != current_task()|| + task->sec_token.val[0] != 0) result = KERN_INVALID_ARGUMENT; else { task_priority(task, BASEPRI_CONTROL, task->max_priority); task->role = info->role; } - } - else - if (info->role == TASK_GRAPHICS_SERVER) { - if ( task != current_task() || - task->sec_token.val[0] != 0 ) + break; + + case TASK_GRAPHICS_SERVER: + if (task != current_task() || + task->sec_token.val[0] != 0) result = KERN_INVALID_ARGUMENT; else { task_priority(task, MAXPRI_RESERVED - 3, MAXPRI_RESERVED); task->role = info->role; } - } - else + break; + case TASK_DEFAULT_APPLICATION: + task_priority(task, BASEPRI_DEFAULT, MAXPRI_USER); + task->role = info->role; + break; + + default : result = KERN_INVALID_ARGUMENT; + break; + } /* switch (info->role) */ task_unlock(task); + /* if backgrounding action ... */ + if (bsdinfo != NULL) + proc_set_task_networkbg(bsdinfo, setbg); + break; } @@ -210,3 +385,1920 @@ task_policy_get( return (KERN_SUCCESS); } + +/* task Darwin BG enforcement/settings related routines */ +int +proc_get_task_bg_policy(task_t task) +{ + + int selfset = 0; + int val = 0; + + if (current_task() == task) + selfset = 1; + + if (selfset == 0) { + val = task->ext_policystate.hw_bg; + } else { + val = task->policystate.hw_bg; + } + + return(val); +} + + +int +proc_get_thread_bg_policy(task_t task, uint64_t tid) +{ + int selfset = 0; + thread_t self = current_thread(); + thread_t thread = THREAD_NULL; + int val = 0; + + if (tid == self->thread_id) + selfset = 1; + + if (selfset == 0) { + task_lock(task); + thread = task_findtid(task, tid); + if (thread != NULL) + val = thread->ext_policystate.hw_bg; + task_unlock(task); + } else { + val = self->policystate.hw_bg; + } + + return(val); +} + +int +proc_get_self_isbackground(void) +{ + task_t task = current_task();; + thread_t thread = current_thread(); + + if ((task->ext_appliedstate.hw_bg != TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) || + (task->appliedstate.hw_bg != TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) || + (thread->ext_appliedstate.hw_bg != TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) || + (thread->appliedstate.hw_bg != TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE)) + return(1); + else + return(0); + +} + +int proc_get_selfthread_isbackground(void) +{ + thread_t thread = current_thread(); + + if ((thread->ext_appliedstate.hw_bg != TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) || + (thread->appliedstate.hw_bg != TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE)) + return(1); + else + return(0); +} + + +int +proc_set_bgtaskpolicy(task_t task, int intval) +{ + + int selfset = 0; + + if (current_task() == task) + selfset = 1; + + task_lock(task); + + if (selfset == 0) { + /* allready set? */ + if (task->ext_policystate.hw_bg != intval) + task->ext_policystate.hw_bg = intval; + } else { + if (task->policystate.hw_bg != intval) + task->policystate.hw_bg = intval; + } + + task_unlock(task); + return(0); +} + +/* set and apply as well , handles reset of NONUI due to setprio() task app state implmn side effect */ +int +proc_set_and_apply_bgtaskpolicy(task_t task, int prio) +{ + int error = 0; + + if (prio == PRIO_DARWIN_BG) { + error = proc_set_bgtaskpolicy(task, TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL); + if (error == 0) { + error = proc_apply_bgtaskpolicy(task); +#if CONFIG_EMBEDDED + /* XXX: till SB uses newer SPIs */ + apply_appstate_watchers(task, 1); +#endif /* CONFIG_EMBEDDED */ + } + } else { + error = proc_restore_bgtaskpolicy(task); + if (error == 0) { + /* since prior impl of non UI was overloaded with bg state, need to reset */ + error = proc_apply_task_gpuacc(task, TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_DEFAULT); +#if CONFIG_EMBEDDED + /* XXX: till SB uses newer SPIs */ + apply_appstate_watchers(task, 0); +#endif /* CONFIG_EMBEDDED */ + } + + } + + return(error); +} + + +int +proc_set_bgthreadpolicy(task_t task, uint64_t tid, int prio) +{ + int selfset = 0; + thread_t self = current_thread(); + thread_t thread = THREAD_NULL; + int reset; + + if (prio == 0) + reset = 1; + if (tid == self->thread_id) + selfset = 1; + + task_lock(task); + if (selfset == 0) { + thread = task_findtid(task, tid); + if (thread != NULL) + thread->ext_policystate.hw_bg = prio; + } else { + self->policystate.hw_bg = prio; + } + + task_unlock(task); + + return(0); +} + +int +proc_set_and_apply_bgthreadpolicy(task_t task, uint64_t tid, int prio) +{ + int error = 0; + + if (prio == PRIO_DARWIN_BG) { + error = proc_set_bgthreadpolicy(task, tid, TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL); + if (error == 0) + error = proc_apply_bgthreadpolicy(task, tid); + } else { + error = proc_restore_bgthreadpolicy(task, tid); + } + + return(error); +} + +int +proc_add_bgtaskpolicy(task_t task, int val) +{ + int selfset = 0; + + if (current_task() == task) + selfset = 1; + + task_lock(task); + + if (selfset == 0) { + task->policystate.hw_bg |= val; + } else { + task->ext_policystate.hw_bg |= val; + } + + task_unlock(task); + return(0); +} + +int +proc_add_bgthreadpolicy(task_t task, uint64_t tid, int val) +{ + int selfset = 0; + thread_t self = current_thread(); + thread_t thread = THREAD_NULL; + int reset; + + if (val == 0) + reset = 1; + if (tid == self->thread_id) + selfset = 1; + + task_lock(task); + if (selfset == 0) { + thread = task_findtid(task, tid); + if (thread != NULL) + thread->ext_policystate.hw_bg |= val; + } else { + self->policystate.hw_bg |= val; + } + + task_unlock(task); + + return(val); +} + +int +proc_remove_bgtaskpolicy(task_t task, int intval) +{ + int selfset = 0; + + if (current_task() == task) + selfset = 1; + + task_lock(task); + + if (selfset == 0) { + task->policystate.hw_bg &= ~intval; + } else { + task->ext_policystate.hw_bg &= ~intval; + } + + task_unlock(task); + return(0); +} + +int +proc_remove_bgthreadpolicy(task_t task, uint64_t tid, int val) +{ + int selfset = 0; + thread_t self = current_thread(); + thread_t thread = THREAD_NULL; + int reset; + + if (val == 0) + reset = 1; + if (tid == self->thread_id) + selfset = 1; + + task_lock(task); + if (selfset == 0) { + thread = task_findtid(task, tid); + if (thread != NULL) + thread->ext_policystate.hw_bg &= ~val; + } else { + self->policystate.hw_bg &= ~val; + } + + task_unlock(task); + + return(val); +} + +int +proc_apply_bgtask_selfpolicy(void) +{ + return(proc_apply_bgtaskpolicy(current_task())); +} + +int +proc_apply_bgtaskpolicy(task_t task) +{ + int external = 1; + + if (task == current_task()) + external = 0; + return(proc_apply_bgtaskpolicy_internal(task, 0, external)); +} + +int +proc_apply_bgtaskpolicy_external(task_t task) +{ + return(proc_apply_bgtaskpolicy_internal(task, 0, 1)); +} + +static int +proc_apply_bgtaskpolicy_internal(task_t task, int locked, int external) +{ + + if (locked == 0) + task_lock(task); + + /* if the process is exiting, no action to be done */ + if (task->proc_terminate != 0) + goto out; + + if (external != 0) { + /* allready set? */ + if (task->ext_appliedstate.hw_bg != task->ext_policystate.hw_bg) { + task->ext_appliedstate.hw_bg = task->ext_policystate.hw_bg; + task_priority(task, MAXPRI_THROTTLE, MAXPRI_THROTTLE); + /* background state applied */ + } + } else { + if (task->appliedstate.hw_bg != task->policystate.hw_bg) { + task->appliedstate.hw_bg = task->policystate.hw_bg; + task_priority(task, MAXPRI_THROTTLE, MAXPRI_THROTTLE); + } + } +out: + if (locked == 0) + task_unlock(task); + return(0); +} + +/* apply the self backgrounding even if the thread is not current thread */ +int +proc_apply_workq_bgthreadpolicy(thread_t thread) +{ + int error; + task_t wqtask = TASK_NULL; + + if (thread != THREAD_NULL) { + wqtask = thread->task; + task_lock(wqtask); + /* apply the background as selfset internal one */ + error = proc_apply_bgthreadpolicy_locked(thread, 1); + task_unlock(wqtask); + } else + error = ESRCH; + + return(error); +} + +int +proc_apply_bgthreadpolicy(task_t task, uint64_t tid) +{ + int selfset = 0, error = 0; + thread_t self = current_thread(); + thread_t thread = THREAD_NULL; + task_t localtask = TASK_NULL; + + if (tid == self->thread_id) { + selfset = 1; + localtask = current_task(); + } else + localtask = task; + + task_lock(localtask); + if (selfset != 0) { + thread = self; + } else { + thread = task_findtid(localtask, tid); + } + + error = proc_apply_bgthreadpolicy_locked(thread, selfset); + + task_unlock(localtask); + + return(error); +} + +static int +proc_apply_bgthreadpolicy_locked(thread_t thread, int selfset) +{ + int set = 0; + thread_precedence_policy_data_t policy; + + + if (thread != NULL) { + /* if the process is exiting, no action to be done */ + if (thread->task->proc_terminate != 0) + goto out; + + if (selfset != 0) { + /* internal application */ + if (thread->appliedstate.hw_bg != thread->policystate.hw_bg) { + thread->appliedstate.hw_bg = thread->policystate.hw_bg; + if (thread->ext_appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) + set = 1; + + } + } else { + /* external application */ + if (thread->ext_appliedstate.hw_bg != thread->ext_policystate.hw_bg) { + thread->ext_appliedstate.hw_bg = thread->ext_policystate.hw_bg; + if (thread->appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) + set = 1; + } + } + + if (set != 0) { +#if CONFIG_EMBEDDED + if (thread->task->ext_appliedstate.apptype == PROC_POLICY_IOS_APPLE_DAEMON) { + thread->saved_importance = thread->importance; + } +#endif /* CONFIG_EMBEDDED */ + /* set thread priority (we did not save previous value) */ + policy.importance = INT_MIN; + + thread_policy_set_internal(thread, THREAD_PRECEDENCE_POLICY, + (thread_policy_t)&policy, + THREAD_PRECEDENCE_POLICY_COUNT ); + + } + } else + return(ESRCH); + +out: + return(0); +} + +#if CONFIG_EMBEDDED +/* set external application of background */ +static void +apply_bgthreadpolicy_external(thread_t thread) +{ +int set = 0; +thread_precedence_policy_data_t policy; + + /* if the process is exiting, no action to be done */ + if (thread->task->proc_terminate != 0) + return; + + thread->ext_policystate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL; + + if (thread->ext_appliedstate.hw_bg != thread->ext_policystate.hw_bg) { + thread->ext_appliedstate.hw_bg = thread->ext_policystate.hw_bg; + if (thread->appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) + set = 1; + } + + if (set != 0) { + /* set thread priority (we did not save previous value) */ + policy.importance = INT_MIN; + + thread_policy_set_internal(thread, THREAD_PRECEDENCE_POLICY, + (thread_policy_t)&policy, + THREAD_PRECEDENCE_POLICY_COUNT ); + } + +} +#endif /* CONFIG_EMBEDDED */ + +int +proc_apply_bgthread_selfpolicy(void) +{ + return(proc_apply_bgthreadpolicy(current_task(), current_thread()->thread_id)); +} + + +int +proc_restore_bgtaskpolicy(task_t task) +{ + int external = 1; + + if (current_task() == task) + external = 0; + return(proc_restore_bgtaskpolicy_internal(task, 0, external, BASEPRI_DEFAULT)); +} + +static int +proc_restore_bgtaskpolicy_internal(task_t task, int locked, int external, int pri) +{ + if (locked == 0) + task_lock(task); + + /* if the process is exiting, no action to be done */ + if (task->proc_terminate != 0) + goto out; + + if (external != 0) { + task->ext_appliedstate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE; + /* self BG in flight? */ + if (task->appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) { + task_priority(task, pri, MAXPRI_USER); +#if CONFIG_EMBEDDED + task->role = TASK_DEFAULT_APPLICATION; +#endif /* CONFIG_EMBEDDED */ + } + } else { + task->appliedstate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE; + /* external BG in flight? */ + if (task->ext_appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) { + task_priority(task, pri, MAXPRI_USER); +#if CONFIG_EMBEDDED + task->role = TASK_DEFAULT_APPLICATION; +#endif /* CONFIG_EMBEDDED */ + } + } +out: + if (locked == 0) + task_unlock(task); + + return(0); +} + +/* restore the self backgrounding even if the thread is not current thread */ +int +proc_restore_workq_bgthreadpolicy(thread_t thread) +{ + int error = 0; + task_t wqtask = TASK_NULL; + int importance = 0; + + if (thread != THREAD_NULL) { + wqtask = thread->task; + task_lock(wqtask); + /* remove the background and restore default importance as self(internal) removal */ +#if CONFIG_EMBEDDED + if (thread->task->ext_appliedstate.apptype == PROC_POLICY_IOS_APPLE_DAEMON) { + /* restore prev set importnace */ + importance = thread->saved_importance; + thread->saved_importance = 0; + } +#endif /* CONFIG_EMBEDDED */ + restore_bgthreadpolicy_locked(thread, 1, importance); + task_unlock(wqtask); + } else + error = ESRCH; + + return(error); +} + +int +proc_restore_bgthread_selfpolicy(void) +{ + return(proc_restore_bgthreadpolicy(current_task(), thread_tid(current_thread()))); +} + +int +proc_restore_bgthreadpolicy(task_t task, uint64_t tid) +{ + + int selfset = 0; + thread_t self = current_thread(); + thread_t thread = THREAD_NULL; + int importance = 0; + + if (tid == self->thread_id) + selfset = 1; + + task_lock(task); + if (selfset == 0) { + thread = task_findtid(task, tid); + } else { + thread = self; + } + + if (thread != NULL) { +#if CONFIG_EMBEDDED + if (thread->task->ext_appliedstate.apptype == PROC_POLICY_IOS_APPLE_DAEMON) { + /* restore prev set importnace */ + importance = thread->saved_importance; + thread->saved_importance = 0; + } +#endif /* CONFIG_EMBEDDED */ + restore_bgthreadpolicy_locked(thread, selfset, importance); + } + task_unlock(task); + + if (thread != NULL) + return(0); + else + return(1); +} + +static void +restore_bgthreadpolicy_locked(thread_t thread, int selfset, int importance) +{ + thread_precedence_policy_data_t policy; + int reset = 0; + + if (thread != NULL) { + /* if the process is exiting, no action to be done */ + if (thread->task->proc_terminate != 0) + return; + + if (selfset != 0) { + thread->appliedstate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE; + /* external BG in flight? */ + if (thread->ext_appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) + reset = 1; + + } else { + thread->ext_appliedstate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE; + /* self BG in flight? */ + if (thread->appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_NONE) + reset = 1; + } + + if (reset != 0) { + /* reset thread priority (we did not save previous value) */ + policy.importance = importance; + thread_policy_set_internal(thread, THREAD_PRECEDENCE_POLICY, + (thread_policy_t)&policy, + THREAD_PRECEDENCE_POLICY_COUNT ); + } + } +} + +void +#if CONFIG_EMBEDDED +proc_set_task_apptype(task_t task, int type, thread_t thread) +#else +proc_set_task_apptype(task_t task, int type, __unused thread_t thread) +#endif +{ +#if CONFIG_EMBEDDED + thread_t th = THREAD_NULL; +#endif /* CONFIG_EMBEDDED */ + + switch (type) { +#if CONFIG_EMBEDDED + case PROC_POLICY_IOS_RESV1_APPTYPE: + task->ext_policystate.apptype = type; + task->policystate.apptype = type; + proc_apply_bgtaskpolicy_external(task); + /* indicate that BG is set and next foreground needs to reset */ + task->ext_appliedstate.apptype = type; + break; + + case PROC_POLICY_IOS_APPLE_DAEMON: + task->ext_policystate.apptype = type; + task->policystate.apptype = type; + task->ext_appliedstate.apptype = type; + /* posix spawn will already have thread created, so backround it */ + if (thread == NULL) + th = current_thread(); + else + th = thread; + if (th->appliedstate.hw_bg != TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL) { + /* apply self backgrounding if not already set */ + task_lock(th->task); + proc_apply_bgthreadpolicy_locked(th, 1); + task_unlock(th->task); + } + break; + + case PROC_POLICY_IOS_APPTYPE: + task->ext_policystate.apptype = type; + task->policystate.apptype = type; + break; + case PROC_POLICY_IOS_NONUITYPE: + task->ext_policystate.apptype = type; + task->policystate.apptype = type; + /* set to deny access to gpu */ + task->ext_appliedstate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS; + task->ext_policystate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS; + break; +#else /* CONFIG_EMBEDDED */ + case PROC_POLICY_OSX_APPTYPE_TAL: + task->ext_policystate.apptype = type; + task->policystate.apptype = type; + proc_apply_bgtaskpolicy_external(task); + /* indicate that BG is set and next foreground needs to reset */ + task->ext_appliedstate.apptype = type; + break; + + case PROC_POLICY_OSX_APPTYPE_DBCLIENT: + task->ext_policystate.apptype = type; + task->policystate.apptype = type; + proc_apply_bgtaskpolicy_internal(task, 0, 0); + break; + +#endif /* CONFIG_EMBEDDED */ + + default: + break; + } +} + +/* update the darwin backdground action state in the flags field for libproc */ +#define PROC_FLAG_DARWINBG 0x8000 /* process in darwin background */ +#define PROC_FLAG_EXT_DARWINBG 0x10000 /* process in darwin background - external enforcement */ +#define PROC_FLAG_IOS_APPLEDAEMON 0x20000 /* process is apple ios daemon */ + +int +proc_get_darwinbgstate(task_t task, uint32_t * flagsp) +{ + if (task->ext_appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL){ + *flagsp |= PROC_FLAG_EXT_DARWINBG; + } + if (task->appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL){ + *flagsp |= PROC_FLAG_DARWINBG; + } +#if CONFIG_EMBEDDED + if (task->ext_appliedstate.apptype == PROC_POLICY_IOS_APPLE_DAEMON) { + *flagsp |= PROC_FLAG_IOS_APPLEDAEMON; + } +#endif /* CONFIG_EMBEDDED */ + + return(0); +} + +/* + * HW disk access realted routines, they need to return + * IOPOL_XXX equivalents for spec_xxx/throttle updates. + */ + +int +proc_get_task_disacc(task_t task) +{ +#if CONFIG_EMBEDDED + if ((task->ext_appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0) + return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE); +#else /* CONFIG_EMBEDDED */ + if ((task->ext_appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0) { + /* if it is a TAL or DBClient and not self throttled, return Utility */ + if ((task->ext_appliedstate.apptype == PROC_POLICY_OSX_APPTYPE_TAL) || (task->ext_appliedstate.apptype == PROC_POLICY_OSX_APPTYPE_DBCLIENT)) { + /* any setting for DBG, we need to honor that */ + if ((task->ext_appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE) && + ((task->appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE)!= 0) && + (task->appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE)) { + return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_UTILITY); + } else + return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE); + } else + return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE); + } +#endif /* CONFIG_EMBEDDED */ + if (task->ext_appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS) + return(task->ext_appliedstate.hw_disk); + if ((task->appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0) + return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE); + if (task->appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS) + return(task->appliedstate.hw_disk); + return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS); +} + +int +proc_get_task_selfdiskacc_internal(task_t task, thread_t thread) +{ + /* if the task is marked for proc_terminate, no throttling for it */ + if (task->proc_terminate != 0) + goto out; + /* + * As per defined iopolicysys behavior, thread trumps task. + * Do we need to follow that for external enforcements of BG or hw access? + * Status quo for now.. + */ + + if((thread->ext_appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0) + return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE); + if (thread->ext_appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS) + return(thread->ext_appliedstate.hw_disk); + if((thread->appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0) + return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE); + if (thread->appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS) + return(thread->appliedstate.hw_disk); + +#if CONFIG_EMBEDDED + if ((task->ext_appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0) + return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE); +#else /* CONFIG_EMBEDDED */ + if ((task->ext_appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0) { + /* if it is a TAL or DBClient and not self throttled, return Utility */ + if ((task->ext_appliedstate.apptype == PROC_POLICY_OSX_APPTYPE_TAL) || (task->ext_appliedstate.apptype == PROC_POLICY_OSX_APPTYPE_DBCLIENT)) { + /* any setting for DBG, we need to honor that */ + if ((task->ext_appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE) && + ((task->appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE)!= 0) && + (task->appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE)) { + return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_UTILITY); + } else + return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE); + } else + return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE); + } +#endif /* CONFIG_EMBEDDED */ + if (task->ext_appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS) + return(task->ext_appliedstate.hw_disk); + if ((task->appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0) + return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE); + if (task->appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS) + return(task->appliedstate.hw_disk); +out: + return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS); +} + + +int +proc_get_task_selfdiskacc(void) +{ + return(proc_get_task_selfdiskacc_internal(current_task(), current_thread())); +} + + +int +proc_get_diskacc(thread_t thread) +{ + return(proc_get_task_selfdiskacc_internal(thread->task, thread)); +} + + +int +proc_get_thread_selfdiskacc(void) +{ + thread_t thread = current_thread(); + + if((thread->ext_appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0) + return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE); + if (thread->ext_appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS) + return(thread->ext_appliedstate.hw_disk); + if((thread->appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_DISKTHROTTLE) != 0) + return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_THROTTLE); + if (thread->appliedstate.hw_disk != TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS) + return(thread->appliedstate.hw_disk); + return(TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS); +} + +int +proc_apply_task_diskacc(task_t task, int policy) +{ + task_t self = current_task(); + + task_lock(task); + if (task == self) { + task->appliedstate.hw_disk = policy; + task->policystate.hw_disk = policy; + } else { + task->ext_appliedstate.hw_disk = policy; + task->ext_policystate.hw_disk = policy; + } + task_unlock(task); + return(0); +} + +int +proc_apply_thread_diskacc(task_t task, uint64_t tid, int policy) +{ + thread_t thread; + + if (tid == TID_NULL) { + thread = current_thread(); + proc_apply_thread_selfdiskacc(policy); + } else { + task_lock(task); + thread = task_findtid(task, tid); + if (thread != NULL) { + thread->ext_appliedstate.hw_disk = policy; + thread->ext_policystate.hw_disk = policy; + } + task_unlock(task); + } + if (thread != NULL) + return(0); + else + return(0); +} + +void +proc_task_remove_throttle(task_t task) +{ + thread_t thread; + int importance = 0; + + task_lock(task); + + + /* remove processwide internal DBG applicationn */ + proc_restore_bgtaskpolicy_internal(task, 1, 0, BASEPRI_DEFAULT); + /* remove processwide external DBG applicationn */ + proc_restore_bgtaskpolicy_internal(task, 1, 1, BASEPRI_DEFAULT); + + for (thread = (thread_t)queue_first(&task->threads); + !queue_end(&task->threads, (queue_entry_t)thread); ) { +#if CONFIG_EMBEDDED + if (thread->task->ext_appliedstate.apptype == PROC_POLICY_IOS_APPLE_DAEMON) { + /* restore prev set importnace */ + importance = thread->saved_importance; + thread->saved_importance = 0; + } +#endif /* CONFIG_EMBEDDED */ + /* remove thread level internal DBG application */ + restore_bgthreadpolicy_locked(thread, 1, importance); + /* remove thread level external DBG application */ + restore_bgthreadpolicy_locked(thread, 0, importance); + /* reset thread io policy */ + thread->ext_appliedstate.hw_disk = TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS; + thread->appliedstate.hw_disk = TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS; + unthrottle_thread(thread->uthread); + thread = (thread_t)queue_next(&thread->task_threads); + } + + /* reset task iopolicy */ + task->ext_appliedstate.hw_disk = TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS; + task->appliedstate.hw_disk = TASK_POLICY_HWACCESS_DISK_ATTRIBUTE_FULLACCESS; + task->proc_terminate = 1; + + task_unlock(task); +} + + + +int +proc_apply_thread_selfdiskacc(int policy) +{ + task_t task = current_task(); + thread_t thread = current_thread(); + + task_lock(task); + thread->appliedstate.hw_disk = policy; + thread->policystate.hw_disk = policy; + task_unlock(task); + return(0); +} + +int +proc_denyinherit_policy(__unused task_t task) +{ + return(0); +} + +int +proc_denyselfset_policy(__unused task_t task) +{ + return(0); +} + +/* HW GPU access related routines */ +int +proc_get_task_selfgpuacc_deny(void) +{ + task_t task = current_task(); +#ifdef NOTYET + thread_t thread = current_thread(); +#endif /* NOTYET */ + + if (((task->ext_appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_NOGPU) != 0) || (task->ext_appliedstate.hw_gpu == TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS)) + return(TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS); + if (((task->appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_NOGPU) != 0) || (task->appliedstate.hw_gpu == TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS)) + return(TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS); +#ifdef NOTYET + /* + * Since background dispatch items run in a thread can also be + * denied access, we need to make sure there are no unintended + * consequences of background dispatch usage. So till this is + * hashed out, disable thread level checking. + */ + if (((thread->ext_appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_NOGPU) != 0) || (thread->ext_appliedstate.hw_gpu == TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS)) + return(TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS); + if (((thread->appliedstate.hw_bg & TASK_POLICY_BACKGROUND_ATTRIBUTE_NOGPU) != 0) || (thread->appliedstate.hw_gpu == TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS)) + return(TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS); + +#endif /* NOTYET */ + return(TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_FULLACCESS); +} + +int +proc_apply_task_gpuacc(task_t task, int policy) +{ + + task_t self = current_task(); + + task_lock(task); + if (task == self) { + task->appliedstate.hw_gpu = policy; + task->policystate.hw_gpu = policy; + } else { + task->ext_appliedstate.hw_gpu = policy; + task->ext_policystate.hw_gpu = policy; + } + task_unlock(task); + + return(0); +} + +/* Resource usage , CPU realted routines */ +int +proc_get_task_ruse_cpu(task_t task, uint32_t * policyp, uint32_t * percentagep, uint64_t * intervalp, uint64_t * deadlinep) +{ + + int error = 0; + + task_lock(task); + if (task != current_task()) { + *policyp = task->ext_policystate.ru_cpu; + } else { + *policyp = task->policystate.ru_cpu; + } + + error = task_get_cpuusage(task, percentagep, intervalp, deadlinep); + + return(error); +} + +/* + * Currently supported configurations for CPU limits. + * + * Deadline-based CPU limit Percentage-based CPU limit + * PROC_POLICY_RSRCACT_THROTTLE ENOTSUP Task-wide scope only + * PROC_POLICY_RSRCACT_SUSPEND Task-wide scope only ENOTSUP + * PROC_POLICY_RSRCACT_TERMINATE Task-wide scope only ENOTSUP + * PROC_POLICY_RSRCACT_NOTIFY_KQ Task-wide scope only ENOTSUP + * PROC_POLICY_RSRCACT_NOTIFY_EXC ENOTSUP Per-thread scope only + * + * A deadline-based CPU limit is actually a simple wallclock timer - the requested action is performed + * after the specified amount of wallclock time has elapsed. + * + * A percentage-based CPU limit performs the requested action after the specified amount of actual CPU time + * has been consumed -- regardless of how much wallclock time has elapsed -- by either the task as an + * aggregate entity (so-called "Task-wide" or "Proc-wide" scope, whereby the CPU time consumed by all threads + * in the task are added together), or by any one thread in the task (so-called "per-thread" scope). + * + * We support either deadline != 0 OR percentage != 0, but not both. The original intention in having them + * share an API was to use actual CPU time as the basis of the deadline-based limit (as in: perform an action + * after I have used some amount of CPU time; this is different than the recurring percentage/interval model) + * but the potential consumer of the API at the time was insisting on wallclock time instead. + * + * Currently, requesting notification via an exception is the only way to get per-thread scope for a + * CPU limit. All other types of notifications force task-wide scope for the limit. + */ +int +proc_set_task_ruse_cpu(task_t task, uint32_t policy, uint32_t percentage, uint64_t interval, uint64_t deadline) +{ + int error = 0; + int scope; + + /* + * Enforce the matrix of supported configurations for policy, percentage, and deadline. + */ + switch (policy) { + // If no policy is explicitly given, the default is to throttle. + case TASK_POLICY_RESOURCE_ATTRIBUTE_NONE: + case TASK_POLICY_RESOURCE_ATTRIBUTE_THROTTLE: + if (deadline != 0) + return (ENOTSUP); + scope = TASK_RUSECPU_FLAGS_PROC_LIMIT; + break; + case TASK_POLICY_RESOURCE_ATTRIBUTE_SUSPEND: + case TASK_POLICY_RESOURCE_ATTRIBUTE_TERMINATE: + case TASK_POLICY_RESOURCE_ATTRIBUTE_NOTIFY_KQ: + if (percentage != 0) + return (ENOTSUP); + scope = TASK_RUSECPU_FLAGS_DEADLINE; + break; + case TASK_POLICY_RESOURCE_ATTRIBUTE_NOTIFY_EXC: + if (deadline != 0) + return (ENOTSUP); + scope = TASK_RUSECPU_FLAGS_PERTHR_LIMIT; + break; + default: + return (EINVAL); + } + + task_lock(task); + if (task != current_task()) { + task->ext_policystate.ru_cpu = policy; + } else { + task->policystate.ru_cpu = policy; + } + error = task_set_cpuusage(task, percentage, interval, deadline, scope); + task_unlock(task); + return(error); +} + +int +proc_clear_task_ruse_cpu(task_t task) +{ + int error = 0; + int action; + void * bsdinfo = NULL; + + task_lock(task); + if (task != current_task()) { + task->ext_policystate.ru_cpu = TASK_POLICY_RESOURCE_ATTRIBUTE_DEFAULT; + } else { + task->policystate.ru_cpu = TASK_POLICY_RESOURCE_ATTRIBUTE_DEFAULT; + } + + error = task_clear_cpuusage_locked(task); + if (error != 0) + goto out; + + action = task->ext_appliedstate.ru_cpu; + if (task->ext_appliedstate.ru_cpu != TASK_POLICY_RESOURCE_ATTRIBUTE_NONE) { + /* reset action */ + task->ext_appliedstate.ru_cpu = TASK_POLICY_RESOURCE_ATTRIBUTE_NONE; + } + if (action != TASK_POLICY_RESOURCE_ATTRIBUTE_NONE) { + bsdinfo = task->bsd_info; + task_unlock(task); + proc_restore_resource_actions(bsdinfo, TASK_POLICY_CPU_RESOURCE_USAGE, action); + goto out1; + } + +out: + task_unlock(task); +out1: + return(error); + +} + +/* used to apply resource limit related actions */ +static int +task_apply_resource_actions(task_t task, int type) +{ + int action = TASK_POLICY_RESOURCE_ATTRIBUTE_NONE; + void * bsdinfo = NULL; + + switch (type) { + case TASK_POLICY_CPU_RESOURCE_USAGE: + break; + case TASK_POLICY_WIREDMEM_RESOURCE_USAGE: + case TASK_POLICY_VIRTUALMEM_RESOURCE_USAGE: + case TASK_POLICY_DISK_RESOURCE_USAGE: + case TASK_POLICY_NETWORK_RESOURCE_USAGE: + case TASK_POLICY_POWER_RESOURCE_USAGE: + return(0); + + default: + return(1); + }; + + /* only cpu actions for now */ + task_lock(task); + + if (task->ext_appliedstate.ru_cpu == TASK_POLICY_RESOURCE_ATTRIBUTE_NONE) { + /* apply action */ + task->ext_appliedstate.ru_cpu = task->ext_policystate.ru_cpu; + action = task->ext_appliedstate.ru_cpu; + } else { + action = task->ext_appliedstate.ru_cpu; + } + + if (action != TASK_POLICY_RESOURCE_ATTRIBUTE_NONE) { + bsdinfo = task->bsd_info; + task_unlock(task); + proc_apply_resource_actions(bsdinfo, TASK_POLICY_CPU_RESOURCE_USAGE, action); + } else + task_unlock(task); + + return(0); +} + +/* For ledger hookups */ +static int +task_get_cpuusage(task_t task, uint32_t * percentagep, uint64_t * intervalp, uint64_t * deadlinep) +{ + *percentagep = task->rusage_cpu_percentage; + *intervalp = task->rusage_cpu_interval; + *deadlinep = task->rusage_cpu_deadline; + + return(0); +} + +int +task_set_cpuusage(task_t task, uint64_t percentage, uint64_t interval, uint64_t deadline, int scope) +{ + uint64_t abstime = 0; + uint64_t save_abstime = 0; + uint64_t limittime = 0; + thread_t thread; + + lck_mtx_assert(&task->lock, LCK_MTX_ASSERT_OWNED); + + /* By default, refill once per second */ + if (interval == 0) + interval = NSEC_PER_SEC; + + if (percentage != 0) { + if (percentage > 100) + percentage = 100; + limittime = (interval * percentage)/ 100; + nanoseconds_to_absolutetime(limittime, &abstime); + if (scope == TASK_RUSECPU_FLAGS_PERTHR_LIMIT) { + /* + * A per-thread CPU limit on a task generates an exception + * (LEDGER_ACTION_EXCEPTION) if any one thread in the task + * exceeds the limit. + */ + task->rusage_cpu_flags |= TASK_RUSECPU_FLAGS_PERTHR_LIMIT; + task->rusage_cpu_perthr_percentage = percentage; + task->rusage_cpu_perthr_interval = interval; + queue_iterate(&task->threads, thread, thread_t, task_threads) { + set_astledger(thread); + } + } else if (scope == TASK_RUSECPU_FLAGS_PROC_LIMIT) { + /* + * Currently, a proc-wide CPU limit always blocks if the limit is + * exceeded (LEDGER_ACTION_BLOCK). + */ + task->rusage_cpu_flags |= TASK_RUSECPU_FLAGS_PROC_LIMIT; + task->rusage_cpu_percentage = percentage; + task->rusage_cpu_interval = interval; + + ledger_set_limit(task->ledger, task_ledgers.cpu_time, abstime); + ledger_set_period(task->ledger, task_ledgers.cpu_time, interval); + ledger_set_action(task->ledger, task_ledgers.cpu_time, LEDGER_ACTION_BLOCK); + } + } + + if (deadline != 0) { + assert(scope == TASK_RUSECPU_FLAGS_DEADLINE); + + /* if already in use, cancel and wait for it to cleanout */ + if (task->rusage_cpu_callt != NULL) { + task_unlock(task); + thread_call_cancel_wait(task->rusage_cpu_callt); + task_lock(task); + } + if (task->rusage_cpu_callt == NULL) { + task->rusage_cpu_callt = thread_call_allocate_with_priority(task_action_cpuusage, (thread_call_param_t)task, THREAD_CALL_PRIORITY_KERNEL); + } + /* setup callout */ + if (task->rusage_cpu_callt != 0) { + task->rusage_cpu_flags |= TASK_RUSECPU_FLAGS_DEADLINE; + task->rusage_cpu_deadline = deadline; + + nanoseconds_to_absolutetime(deadline, &abstime); + save_abstime = abstime; + clock_absolutetime_interval_to_deadline(save_abstime, &abstime); + thread_call_enter_delayed(task->rusage_cpu_callt, abstime); + } + } + + return(0); +} + +int +task_clear_cpuusage(task_t task) +{ + int retval = 0; + + task_lock(task); + retval = task_clear_cpuusage_locked(task); + task_unlock(task); + + return(retval); +} + +int +task_clear_cpuusage_locked(task_t task) +{ + thread_call_t savecallt; + thread_t thread; + + /* cancel percentage handling if set */ + if (task->rusage_cpu_flags & TASK_RUSECPU_FLAGS_PROC_LIMIT) { + task->rusage_cpu_flags &= ~TASK_RUSECPU_FLAGS_PROC_LIMIT; + ledger_set_limit(task->ledger, task_ledgers.cpu_time, LEDGER_LIMIT_INFINITY); + task->rusage_cpu_percentage = 0; + task->rusage_cpu_interval = 0; + } + + if (task->rusage_cpu_flags & TASK_RUSECPU_FLAGS_PERTHR_LIMIT) { + task->rusage_cpu_flags &= ~TASK_RUSECPU_FLAGS_PERTHR_LIMIT; + queue_iterate(&task->threads, thread, thread_t, task_threads) { + set_astledger(thread); + } + task->rusage_cpu_perthr_percentage = 0; + task->rusage_cpu_perthr_interval = 0; + + } + + /* cancel deadline handling if set */ + if (task->rusage_cpu_flags & TASK_RUSECPU_FLAGS_DEADLINE) { + task->rusage_cpu_flags &= ~TASK_RUSECPU_FLAGS_DEADLINE; + if (task->rusage_cpu_callt != 0) { + savecallt = task->rusage_cpu_callt; + task->rusage_cpu_callt = NULL; + task->rusage_cpu_deadline = 0; + task_unlock(task); + thread_call_cancel_wait(savecallt); + thread_call_free(savecallt); + task_lock(task); + } + } + return(0); +} + +/* called by ledger unit to enforce action due to resource usage criteria being met */ +void +task_action_cpuusage(thread_call_param_t param0, __unused thread_call_param_t param1) +{ + task_t task = (task_t)param0; + (void)task_apply_resource_actions(task, TASK_POLICY_CPU_RESOURCE_USAGE); + return; +} + +#if CONFIG_EMBEDDED +/* return the appstate of a task */ +int +proc_lf_getappstate(task_t task) +{ + return(task->appstate); + +} + + +/* set appstate of a task and apply approp actions */ +int +proc_lf_setappstate(task_t task, int state) +{ + int ret = 0, oldstate; + kern_return_t kret = KERN_SUCCESS; + int applywatch = 0, setbg = 0, setnetbg = 0; + int sethib_suspend = 0, sethib_resume=0; + + if (state == TASK_APPSTATE_NONE) + goto out; + + /* valid states? */ + switch (state) { + case TASK_APPSTATE_ACTIVE: + case TASK_APPSTATE_BACKGROUND: + case TASK_APPSTATE_NONUI: + case TASK_APPSTATE_INACTIVE: + break; + default: + ret = EINVAL; + goto out; + + } + + task_lock(task); + oldstate = task->appstate; + if (oldstate == state) { + /* no changes */ + goto out1; + } + + switch(oldstate) { + case TASK_APPSTATE_ACTIVE: + switch(state) { + case TASK_APPSTATE_BACKGROUND: + /* moving from active to app background */ + task->ext_policystate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL; + proc_apply_bgtaskpolicy_internal(task, 1, 1); + /* watchers need update */ + applywatch = 1; + setbg = 1; + /* set network part */ + setnetbg = 1; + break; + + case TASK_APPSTATE_NONUI: + /* set no graphics */ + task->ext_policystate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS; + task->ext_appliedstate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS; + break; + + case TASK_APPSTATE_INACTIVE: + /* suspend the process */ + kret = task_pidsuspend_locked(task); + if (kret != KERN_SUCCESS) + ret = EINVAL; + else + sethib_suspend = 1; + + break; + } + break; + + case TASK_APPSTATE_BACKGROUND: + switch(state) { + /* watchers need update */ + applywatch = 1; + setbg = 0; + /* set network part */ + setnetbg = 1; + case TASK_APPSTATE_ACTIVE: + /* remove app background */ + ret = proc_restore_bgtaskpolicy_internal(task, 1, 1, BASEPRI_DEFAULT); + /* going from BG to active */ + break; + + case TASK_APPSTATE_NONUI: + /* remove app background + no graphics */ + task->ext_policystate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS; + task->ext_appliedstate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS; + ret = proc_restore_bgtaskpolicy_internal(task, 1, 1, BASEPRI_DEFAULT); + break; + + case TASK_APPSTATE_INACTIVE: + /* suspend and then remove app background */ + kret = task_pidsuspend_locked(task); + if (kret != KERN_SUCCESS) { + ret = EINVAL; + } else { + ret = proc_restore_bgtaskpolicy_internal(task, 1, 1, BASEPRI_DEFAULT); + sethib_suspend = 1; + } + + break; + + } + break; + + case TASK_APPSTATE_NONUI: + switch(state) { + case TASK_APPSTATE_ACTIVE: + /* restore graphics access */ + task->ext_policystate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS; + task->ext_appliedstate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_DEFAULT; + break; + + case TASK_APPSTATE_BACKGROUND: + /* set app background */ + task->ext_policystate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL; + + ret = proc_apply_bgtaskpolicy_internal(task, 1, 1); + if (ret == 0) { + task->ext_policystate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_DEFAULT; + task->ext_appliedstate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_DEFAULT; + } + /* watchers need update */ + applywatch = 1; + setbg = 1; + /* set network part */ + setnetbg = 1; + break; + + case TASK_APPSTATE_INACTIVE: + /* suspend & restore graphics access */ + kret = task_pidsuspend_locked(task); + if (kret != KERN_SUCCESS) { + ret = EINVAL; + } else { + ret = proc_restore_bgtaskpolicy_internal(task, 1, 1, BASEPRI_DEFAULT); + task->ext_policystate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_DEFAULT; + task->ext_appliedstate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_DEFAULT; + sethib_suspend = 1; + } + break; + } + break; + + case TASK_APPSTATE_INACTIVE: + switch(state) { + case TASK_APPSTATE_ACTIVE: + /* resume process */ + /* going from inactive to active */ + break; + + case TASK_APPSTATE_BACKGROUND: + task->ext_policystate.hw_bg = TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL; + ret = proc_apply_bgtaskpolicy_internal(task, 1, 1); + /* put in app background & resume process */ + /* watchers need update */ + applywatch = 1; + setbg = 1; + /* set network part */ + setnetbg = 1; + break; + + case TASK_APPSTATE_NONUI: + /* remove graphics access and resume */ + task->ext_policystate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS; + task->ext_appliedstate.hw_gpu = TASK_POLICY_HWACCESS_GPU_ATTRIBUTE_NOACCESS; + break; + } + /* pidresume does drop task lock,so no need to have locked version */ + task_unlock(task); + kret = task_pidresume(task); + task_lock(task); + sethib_resume = 1; + break; + } + /* set the new app state on the task */ + task->appstate = state; +out1: + task_unlock(task); + if (setnetbg != 0) { + /* apply network background */ + if (setbg != 0) + proc_apply_task_networkbg_internal(task->bsd_info, NULL); + else + proc_restore_task_networkbg_internal(task->bsd_info, NULL); + } +#if CONFIG_MEMORYSTATUS + if (sethib_suspend != 0) + memorystatus_on_suspend(proc_pid(task->bsd_info)); + if (sethib_resume != 0) + memorystatus_on_resume(proc_pid(task->bsd_info)); +#endif /* CONFIG_MEMORYSTATUS */ + /* if watchers need update, safe point to do that */ + if (applywatch != 0) + apply_appstate_watchers(task, setbg); + +out: + return(ret); +} + +static void +task_watch_lock(void) +{ + lck_mtx_lock(&task_watch_mtx); +} + +static void +task_watch_unlock(void) +{ + lck_mtx_unlock(&task_watch_mtx); +} + +static void +add_taskwatch_locked(task_t task, task_watch_t * twp) +{ + queue_enter(&task->task_watchers, twp, task_watch_t *, tw_links); + task->num_taskwatchers++; + +} + +static void +remove_taskwatch_locked(task_t task, task_watch_t * twp) +{ + queue_remove(&task->task_watchers, twp, task_watch_t *, tw_links); + task->num_taskwatchers--; +} + + +int +proc_lf_pidbind(task_t curtask, uint64_t tid, task_t target_task, int bind) +{ + thread_t self = current_thread(); + thread_t target_thread = NULL; + int selfset = 0, ret = 0, setbg = 0; + task_watch_t *twp = NULL; + task_t task = TASK_NULL; + + + if ((tid == 0) || (tid == self->thread_id)) { + selfset = 1; + target_thread = self; + thread_reference(target_thread); + } else { + task_lock(curtask); + target_thread = task_findtid(curtask, tid); + if (target_thread != NULL) + thread_reference(target_thread); + else { + ret = ESRCH; + goto out; + } + + task_unlock(curtask); + } + + if (bind != 0) { + /* task is still active ? */ + task_lock(target_task); + if (target_task->active == 0) { + task_unlock(target_task); + ret = ESRCH; + goto out; + } + task_unlock(target_task); + + twp = (task_watch_t *)kalloc(sizeof(task_watch_t)); + if (twp == NULL) { + task_watch_unlock(); + ret = ENOMEM; + goto out; + } + + bzero(twp, sizeof(task_watch_t)); + + task_watch_lock(); + + if (target_thread->taskwatch != NULL){ + /* already bound to another task */ + task_watch_unlock(); + + kfree(twp, sizeof(task_watch_t)); + ret = EBUSY; + goto out; + } + + task_reference(target_task); + + twp->tw_task = target_task; /* holds the task reference */ + twp->tw_thread = target_thread; /* holds the thread reference */ + twp->tw_state = target_task->appstate; + twp->tw_importance = target_thread->importance; + + add_taskwatch_locked(target_task, twp); + + target_thread->taskwatch = twp; + + if (target_task->appstate == TASK_APPSTATE_BACKGROUND) + setbg = 1; + + task_watch_unlock(); + + if (setbg != 0) { + set_thread_appbg(target_thread, setbg, INT_MIN); + } + + /* retain the thread reference as it is in twp */ + target_thread = NULL; + } else { + /* unbind */ + task_watch_lock(); + if ((twp = target_thread->taskwatch) != NULL) { + task = twp->tw_task; + target_thread->taskwatch = NULL; + remove_taskwatch_locked(task, twp); + + task_watch_unlock(); + + task_deallocate(task); /* drop task ref in twp */ + set_thread_appbg(target_thread, 0, twp->tw_importance); + thread_deallocate(target_thread); /* drop thread ref in twp */ + kfree(twp, sizeof(task_watch_t)); + } else { + task_watch_unlock(); + ret = 0; /* return success if it not alredy bound */ + goto out; + } + } +out: + if (target_thread != NULL) + thread_deallocate(target_thread); /* drop thread ref acquired in this routine */ + return(ret); +} + +static void +set_thread_appbg(thread_t thread, int setbg,int importance) +{ + /* TBD: ensure the proc for network is fine */ + if (setbg == 0) { + restore_bgthreadpolicy_locked(thread, 0, importance); + proc_restore_task_networkbg_internal(thread->task->bsd_info, thread); + } else { + apply_bgthreadpolicy_external(thread); + proc_apply_task_networkbg_internal(thread->task->bsd_info, thread); + } +} + +static void +apply_appstate_watchers(task_t task, int setbg) +{ + int numwatchers = 0, i, j; + thread_watchlist_t * threadlist; + task_watch_t * twp; + +retry: + /* if no watchers on the list return */ + if ((numwatchers = task->num_taskwatchers) == 0) + return; + + threadlist = (thread_watchlist_t *)kalloc(numwatchers*sizeof(thread_watchlist_t)); + if (threadlist == NULL) + return; + + bzero(threadlist, numwatchers*sizeof(thread_watchlist_t)); + + task_watch_lock(); + /*serialize application of app state changes */ + if (task->watchapplying != 0) { + lck_mtx_sleep(&task_watch_mtx, LCK_SLEEP_DEFAULT, &task->watchapplying, THREAD_UNINT); + task_watch_unlock(); + kfree(threadlist, numwatchers*sizeof(thread_watchlist_t)); + goto retry; + } + + if (numwatchers != task->num_taskwatchers) { + task_watch_unlock(); + kfree(threadlist, numwatchers*sizeof(thread_watchlist_t)); + goto retry; + } + + task->watchapplying = 1; + i = 0; + queue_iterate(&task->task_watchers, twp, task_watch_t *, tw_links) { + + threadlist[i].thread = twp->tw_thread; + thread_reference(threadlist[i].thread); + if (setbg != 0) { + twp->tw_importance = twp->tw_thread->importance; + threadlist[i].importance = INT_MIN; + } else + threadlist[i].importance = twp->tw_importance; + i++; + if (i > numwatchers) + break; + } + task_watch_unlock(); + + for (j = 0; j< i; j++) { + set_thread_appbg(threadlist[j].thread, setbg, threadlist[j].importance); + thread_deallocate(threadlist[j].thread); + } + kfree(threadlist, numwatchers*sizeof(thread_watchlist_t)); + + + task_watch_lock(); + task->watchapplying = 0; + thread_wakeup_one(&task->watchapplying); + task_watch_unlock(); +} + +void +thead_remove_taskwatch(thread_t thread) +{ + task_watch_t * twp; + int importance = 0; + + task_watch_lock(); + if ((twp = thread->taskwatch) != NULL) { + thread->taskwatch = NULL; + remove_taskwatch_locked(twp->tw_task, twp); + } + task_watch_unlock(); + if (twp != NULL) { + thread_deallocate(twp->tw_thread); + task_deallocate(twp->tw_task); + importance = twp->tw_importance; + kfree(twp, sizeof(task_watch_t)); + /* remove the thread and networkbg */ + set_thread_appbg(thread, 0, importance); + } +} + +void +task_removewatchers(task_t task) +{ + int numwatchers = 0, i, j; + task_watch_t ** twplist = NULL; + task_watch_t * twp = NULL; + +retry: + if ((numwatchers = task->num_taskwatchers) == 0) + return; + + twplist = (task_watch_t **)kalloc(numwatchers*sizeof(task_watch_t *)); + if (twplist == NULL) + return; + + bzero(twplist, numwatchers*sizeof(task_watch_t *)); + + task_watch_lock(); + if (task->num_taskwatchers == 0) { + task_watch_unlock(); + goto out; + } + + if (numwatchers != task->num_taskwatchers) { + task_watch_unlock(); + kfree(twplist, numwatchers*sizeof(task_watch_t *)); + numwatchers = 0; + goto retry; + } + + i = 0; + while((twp = (task_watch_t *)dequeue_head(&task->task_watchers)) != NULL) + { + twplist[i] = twp; + task->num_taskwatchers--; + + /* + * Since the linkage is removed and thead state cleanup is already set up, + * remove the refernce from the thread. + */ + twp->tw_thread->taskwatch = NULL; /* removed linkage, clear thread holding ref */ + i++; + if ((task->num_taskwatchers == 0) || (i > numwatchers)) + break; + } + + task_watch_unlock(); + + for (j = 0; j< i; j++) { + + twp = twplist[j]; + /* remove thread and network bg */ + set_thread_appbg(twp->tw_thread, 0, twp->tw_importance); + thread_deallocate(twp->tw_thread); + task_deallocate(twp->tw_task); + kfree(twp, sizeof(task_watch_t)); + } + +out: + kfree(twplist, numwatchers*sizeof(task_watch_t *)); + +} +#endif /* CONFIG_EMBEDDED */ + + +int +proc_disable_task_apptype(task_t task, int policy_subtype) +{ + void * bsdinfo = NULL; + int ret = 0; + int setbg = 0; +#if !CONFIG_EMBEDDED + int maxpri = BASEPRI_DEFAULT; +#endif /* !CONFIG_EMBEDDED */ + + task_lock(task); + + if (task->ext_policystate.apptype != policy_subtype) { + ret = EINVAL; + goto out; + } + +#if !CONFIG_EMBEDDED + switch (task->role) { + case TASK_FOREGROUND_APPLICATION: + maxpri = BASEPRI_FOREGROUND; + break; + case TASK_BACKGROUND_APPLICATION: + maxpri = BASEPRI_BACKGROUND; + break; + default: + maxpri = BASEPRI_DEFAULT; + } + + +#endif /* !CONFIG_EMBEDDED */ + + /* TAL apps are cleared with BG handling on first foreground application */ + if (task->ext_appliedstate.apptype != PROC_POLICY_OSX_APPTYPE_NONE) { + switch (task->ext_appliedstate.apptype) { +#if !CONFIG_EMBEDDED + case PROC_POLICY_OSX_APPTYPE_TAL: + /* disable foreground/background handling */ + task->ext_appliedstate.apptype = PROC_POLICY_OSX_APPTYPE_NONE; + /* external BG application removal */ + proc_restore_bgtaskpolicy_internal(task, 1, 1, maxpri); + bsdinfo = task->bsd_info; + setbg = 0; + break; + + case PROC_POLICY_OSX_APPTYPE_DBCLIENT: + /* disable foreground/background handling */ + task->ext_appliedstate.apptype = PROC_POLICY_OSX_APPTYPE_NONE; + /* internal BG application removal */ + proc_restore_bgtaskpolicy_internal(task, 1, 0, maxpri); + bsdinfo = task->bsd_info; + setbg = 0; + break; + +#endif /* !CONFIG_EMBEDDED */ + default: + ret = EINVAL; + break; + } + + } else { + ret = EINVAL; + } + +out: + task_unlock(task); + /* if backgrounding action ... */ + if (bsdinfo != NULL) + proc_set_task_networkbg(bsdinfo, setbg); + + return(ret); +} + +int +proc_enable_task_apptype(task_t task, int policy_subtype) +{ + void * bsdinfo = NULL; + int setbg = 0; + int ret = 0; + + task_lock(task); + + if (task->ext_policystate.apptype != policy_subtype) { + ret = EINVAL; + goto out; + } + + if (task->ext_appliedstate.apptype == PROC_POLICY_OSX_APPTYPE_NONE) { + switch (task->ext_policystate.apptype) { +#if !CONFIG_EMBEDDED + case PROC_POLICY_OSX_APPTYPE_TAL: + /* TAL policy is activated again */ + task->ext_appliedstate.apptype = task->ext_policystate.apptype; + if (task->role == TASK_BACKGROUND_APPLICATION) { + if (task->role == TASK_BACKGROUND_APPLICATION) { + proc_apply_bgtaskpolicy_internal(task, 1, 1); + bsdinfo = task->bsd_info; + setbg = 1; + } + } + ret = 0; + break; +#endif /* !CONFIG_EMBEDDED */ + default: + ret = EINVAL; + } + } else + ret = EINVAL; + +out: + task_unlock(task); + /* if backgrounding action ... */ + if (bsdinfo != NULL) + proc_set_task_networkbg(bsdinfo, setbg); + + return(ret); +} + +#if CONFIG_EMBEDDED +int +proc_setthread_saved_importance(thread_t thread, int importance) +{ + if ((thread->task->ext_appliedstate.apptype == PROC_POLICY_IOS_APPLE_DAEMON) && + (thread->appliedstate.hw_bg == TASK_POLICY_BACKGROUND_ATTRIBUTE_ALL)) + { + /* the thread is still backgrounded , save the importance for restore time */ + thread->saved_importance = importance; + + return(1); + } else + return(0); +} +#endif /* CONFIG_EMBEDDED */