Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7a6edeb6 authored by Martijn Coenen's avatar Martijn Coenen Committed by Amit Pundir
Browse files

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: default avatarMartijn Coenen <maco@google.com>
parent 69308b3b
Loading
Loading
Loading
Loading
+53 −21
Original line number Diff line number Diff line
@@ -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)
{
@@ -2633,11 +2668,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) {
@@ -2659,12 +2698,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);

@@ -2783,7 +2824,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;
@@ -3185,6 +3225,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);
@@ -3279,6 +3320,7 @@ static void binder_transaction(struct binder_proc *proc,

	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,
@@ -4076,26 +4118,13 @@ static int binder_thread_read(struct binder_proc *proc,
		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;
@@ -4271,6 +4300,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);
@@ -4321,6 +4352,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);
}