ANDROID: binder: improve priority inheritance.
By raising the priority of a thread selected for a transaction *before* we wake it up. Delay restoring the priority when doing a reply until after we wake-up the process receiving the reply. Change-Id: Ic332e4e0ed7d2d3ca6ab1034da4629c9eadd3405 Signed-off-by: Martijn Coenen <maco@google.com>
This commit is contained in:
parent
adb685439e
commit
7230f99185
1 changed files with 53 additions and 21 deletions
|
@ -611,6 +611,7 @@ enum {
|
|||
* @is_dead: thread is dead and awaiting free
|
||||
* when outstanding transactions are cleaned up
|
||||
* (protected by @proc->inner_lock)
|
||||
* @task: struct task_struct for this thread
|
||||
*
|
||||
* Bookkeeping structure for binder threads.
|
||||
*/
|
||||
|
@ -629,6 +630,7 @@ struct binder_thread {
|
|||
struct binder_stats stats;
|
||||
atomic_t tmp_ref;
|
||||
bool is_dead;
|
||||
struct task_struct *task;
|
||||
};
|
||||
|
||||
struct binder_transaction {
|
||||
|
@ -647,6 +649,7 @@ struct binder_transaction {
|
|||
unsigned int flags;
|
||||
struct binder_priority priority;
|
||||
struct binder_priority saved_priority;
|
||||
bool set_priority_called;
|
||||
kuid_t sender_euid;
|
||||
/**
|
||||
* @lock: protects @from, @to_proc, and @to_thread
|
||||
|
@ -1161,6 +1164,38 @@ static void binder_set_priority(struct task_struct *task,
|
|||
set_user_nice(task, priority);
|
||||
}
|
||||
|
||||
static void binder_transaction_priority(struct task_struct *task,
|
||||
struct binder_transaction *t,
|
||||
struct binder_priority node_prio)
|
||||
{
|
||||
struct binder_priority desired_prio;
|
||||
|
||||
if (t->set_priority_called)
|
||||
return;
|
||||
|
||||
t->set_priority_called = true;
|
||||
t->saved_priority.sched_policy = task->policy;
|
||||
t->saved_priority.prio = task->normal_prio;
|
||||
|
||||
desired_prio.prio = t->priority.prio;
|
||||
desired_prio.sched_policy = t->priority.sched_policy;
|
||||
|
||||
if (node_prio.prio < t->priority.prio ||
|
||||
(node_prio.prio == t->priority.prio &&
|
||||
node_prio.sched_policy == SCHED_FIFO)) {
|
||||
/*
|
||||
* In case the minimum priority on the node is
|
||||
* higher (lower value), use that priority. If
|
||||
* the priority is the same, but the node uses
|
||||
* SCHED_FIFO, prefer SCHED_FIFO, since it can
|
||||
* run unbounded, unlike SCHED_RR.
|
||||
*/
|
||||
desired_prio = node_prio;
|
||||
}
|
||||
|
||||
binder_set_priority(task, desired_prio);
|
||||
}
|
||||
|
||||
static struct binder_node *binder_get_node_ilocked(struct binder_proc *proc,
|
||||
binder_uintptr_t ptr)
|
||||
{
|
||||
|
@ -2635,11 +2670,15 @@ static bool binder_proc_transaction(struct binder_transaction *t,
|
|||
{
|
||||
struct list_head *target_list = NULL;
|
||||
struct binder_node *node = t->buffer->target_node;
|
||||
struct binder_priority node_prio;
|
||||
bool oneway = !!(t->flags & TF_ONE_WAY);
|
||||
bool wakeup = true;
|
||||
|
||||
BUG_ON(!node);
|
||||
binder_node_lock(node);
|
||||
node_prio.prio = node->min_priority;
|
||||
node_prio.sched_policy = node->sched_policy;
|
||||
|
||||
if (oneway) {
|
||||
BUG_ON(thread);
|
||||
if (node->has_async_transaction) {
|
||||
|
@ -2661,12 +2700,14 @@ static bool binder_proc_transaction(struct binder_transaction *t,
|
|||
if (!thread && !target_list)
|
||||
thread = binder_select_thread_ilocked(proc);
|
||||
|
||||
if (thread)
|
||||
if (thread) {
|
||||
target_list = &thread->todo;
|
||||
else if (!target_list)
|
||||
binder_transaction_priority(thread->task, t, node_prio);
|
||||
} else if (!target_list) {
|
||||
target_list = &proc->todo;
|
||||
else
|
||||
} else {
|
||||
BUG_ON(target_list != &node->async_todo);
|
||||
}
|
||||
|
||||
binder_enqueue_work_ilocked(&t->work, target_list);
|
||||
|
||||
|
@ -2743,7 +2784,6 @@ static void binder_transaction(struct binder_proc *proc,
|
|||
}
|
||||
thread->transaction_stack = in_reply_to->to_parent;
|
||||
binder_inner_proc_unlock(proc);
|
||||
binder_set_priority(current, in_reply_to->saved_priority);
|
||||
target_thread = binder_get_txn_from_and_acq_inner(in_reply_to);
|
||||
if (target_thread == NULL) {
|
||||
return_error = BR_DEAD_REPLY;
|
||||
|
@ -3153,6 +3193,7 @@ static void binder_transaction(struct binder_proc *proc,
|
|||
binder_enqueue_work_ilocked(&t->work, &target_thread->todo);
|
||||
binder_inner_proc_unlock(target_proc);
|
||||
wake_up_interruptible_sync(&target_thread->wait);
|
||||
binder_set_priority(current, in_reply_to->saved_priority);
|
||||
binder_free_transaction(in_reply_to);
|
||||
} else if (!(t->flags & TF_ONE_WAY)) {
|
||||
BUG_ON(t->buffer->async_transaction != 0);
|
||||
|
@ -3241,6 +3282,7 @@ err_no_context_mgr_node:
|
|||
|
||||
BUG_ON(thread->return_error.cmd != BR_OK);
|
||||
if (in_reply_to) {
|
||||
binder_set_priority(current, in_reply_to->saved_priority);
|
||||
thread->return_error.cmd = BR_TRANSACTION_COMPLETE;
|
||||
binder_enqueue_work(thread->proc,
|
||||
&thread->return_error.work,
|
||||
|
@ -4052,26 +4094,13 @@ retry:
|
|||
BUG_ON(t->buffer == NULL);
|
||||
if (t->buffer->target_node) {
|
||||
struct binder_node *target_node = t->buffer->target_node;
|
||||
struct binder_priority prio = t->priority;
|
||||
struct binder_priority node_prio;
|
||||
|
||||
tr.target.ptr = target_node->ptr;
|
||||
tr.cookie = target_node->cookie;
|
||||
t->saved_priority.sched_policy = current->policy;
|
||||
t->saved_priority.prio = current->normal_prio;
|
||||
if (target_node->min_priority < t->priority.prio ||
|
||||
(target_node->min_priority == t->priority.prio &&
|
||||
target_node->sched_policy == SCHED_FIFO)) {
|
||||
/*
|
||||
* In case the minimum priority on the node is
|
||||
* higher (lower value), use that priority. If
|
||||
* the priority is the same, but the node uses
|
||||
* SCHED_FIFO, prefer SCHED_FIFO, since it can
|
||||
* run unbounded, unlike SCHED_RR.
|
||||
*/
|
||||
prio.sched_policy = target_node->sched_policy;
|
||||
prio.prio = target_node->min_priority;
|
||||
}
|
||||
binder_set_priority(current, prio);
|
||||
node_prio.sched_policy = target_node->sched_policy;
|
||||
node_prio.prio = target_node->min_priority;
|
||||
binder_transaction_priority(current, t, node_prio);
|
||||
cmd = BR_TRANSACTION;
|
||||
} else {
|
||||
tr.target.ptr = 0;
|
||||
|
@ -4247,6 +4276,8 @@ static struct binder_thread *binder_get_thread_ilocked(
|
|||
binder_stats_created(BINDER_STAT_THREAD);
|
||||
thread->proc = proc;
|
||||
thread->pid = current->pid;
|
||||
get_task_struct(current);
|
||||
thread->task = current;
|
||||
atomic_set(&thread->tmp_ref, 0);
|
||||
init_waitqueue_head(&thread->wait);
|
||||
INIT_LIST_HEAD(&thread->todo);
|
||||
|
@ -4297,6 +4328,7 @@ static void binder_free_thread(struct binder_thread *thread)
|
|||
BUG_ON(!list_empty(&thread->todo));
|
||||
binder_stats_deleted(BINDER_STAT_THREAD);
|
||||
binder_proc_dec_tmpref(thread->proc);
|
||||
put_task_struct(thread->task);
|
||||
kfree(thread);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue