From 07a30fe025b8d156f6b2ea23d6339f4ba4100bd9 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 7 Jun 2017 10:02:12 -0700 Subject: [PATCH] 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 --- drivers/android/binder.c | 74 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 21 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index c99b4497..1005848 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -610,6 +610,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. */ @@ -628,6 +629,7 @@ struct binder_thread { struct binder_stats stats; atomic_t tmp_ref; bool is_dead; + struct task_struct *task; }; struct binder_transaction { @@ -646,6 +648,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 @@ -1160,6 +1163,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) { @@ -2634,11 +2669,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) { @@ -2660,12 +2699,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); @@ -2742,7 +2783,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; @@ -3152,6 +3192,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); @@ -3240,6 +3281,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, @@ -4051,26 +4093,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; @@ -4246,6 +4275,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); @@ -4296,6 +4327,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); } -- 2.7.4