From 47747abe74eb4cd2005c566babe46d472245a7bf Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 29 Mar 2017 10:24:24 -0700 Subject: [PATCH] ANDROID: binder: push new transactions to waiting threads. Instead of pushing new synchronous transactions to the process waitqueue, select a thread that is waiting on proc work to handle the transaction. This will make it easier to do proper priority inheritance. If we can't find a waiting thread, submit the work to the proc waitqueue instead as we did previously. Change-Id: Ib9385ba2c3e8b1e6d2106f1fce5b60bb117ec308 Signed-off-by: Martijn Coenen --- drivers/android/binder.c | 61 +++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/drivers/android/binder.c b/drivers/android/binder.c index d64f5179ed34..a43b3fb04bda 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -631,7 +631,19 @@ static void binder_wakeup_poll_threads(struct binder_proc *proc, bool sync) } } -static void binder_wakeup_thread(struct binder_proc *proc, bool sync) +/** + * binder_select_thread() - selects a thread for doing proc work. + * @proc: process to select a thread from + * + * Note that calling this function moves the thread off the waiting_threads + * list, so it can only be woken up by the caller of this function, or a + * signal. Therefore, callers *should* always wake up the thread this function + * returns. + * + * Return: If there's a thread currently waiting for process work, + * returns that thread. Otherwise returns NULL. + */ +static struct binder_thread *binder_select_thread(struct binder_proc *proc) { struct binder_thread *thread; @@ -640,8 +652,19 @@ static void binder_wakeup_thread(struct binder_proc *proc, bool sync) struct binder_thread, waiting_thread_node); - if (thread) { + if (thread) list_del_init(&thread->waiting_thread_node); + + return thread; +} + +static void binder_wakeup_thread(struct binder_proc *proc, bool sync) +{ + struct binder_thread *thread; + + BUG_ON(!spin_is_locked(&proc->proc_lock)); + thread = binder_select_thread(proc); + if (thread) { if (sync) wake_up_interruptible_sync(&thread->wait); else @@ -1919,7 +1942,6 @@ static void binder_transaction(struct binder_proc *proc, binder_size_t last_fixup_min_off = 0; struct binder_context *context = proc->context; bool oneway; - bool wakeup_for_proc_work = false; e = binder_transaction_log_add(&binder_transaction_log); e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY); @@ -2042,7 +2064,6 @@ static void binder_transaction(struct binder_proc *proc, } else { target_list = &target_proc->todo; target_wait = NULL; - wakeup_for_proc_work = true; } e->to_proc = target_proc->pid; @@ -2319,14 +2340,30 @@ static void binder_transaction(struct binder_proc *proc, binder_enqueue_work(&t->work, target_list, __LINE__); binder_proc_unlock(target_thread->proc, __LINE__); binder_free_transaction(in_reply_to); + wake_up_interruptible_sync(target_wait); } else if (!(t->flags & TF_ONE_WAY)) { BUG_ON(t->buffer->async_transaction != 0); binder_proc_lock(thread->proc, __LINE__); t->need_reply = 1; t->from_parent = thread->transaction_stack; thread->transaction_stack = t; - binder_enqueue_work(&t->work, target_list, __LINE__); binder_proc_unlock(thread->proc, __LINE__); + binder_proc_lock(target_proc, __LINE__); + if (!target_thread) { + /* See if we can find a thread to take this */ + target_thread = binder_select_thread(target_proc); + if (target_thread) { + target_wait = &target_thread->wait; + target_list = &target_thread->todo; + } + } + binder_enqueue_work(&t->work, target_list, __LINE__); + if (target_wait) + wake_up_interruptible_sync(target_wait); + else + binder_wakeup_poll_threads(target_proc, + true /* sync */); + binder_proc_unlock(target_proc, __LINE__); } else { BUG_ON(target_node == NULL); BUG_ON(t->buffer->async_transaction != 1); @@ -2334,10 +2371,10 @@ static void binder_transaction(struct binder_proc *proc, binder_proc_lock(target_node->proc, __LINE__); if (target_node->has_async_transaction) { target_list = &target_node->async_todo; - target_wait = NULL; - wakeup_for_proc_work = false; - } else + } else { target_node->has_async_transaction = 1; + binder_wakeup_thread(target_proc, false /*sync */); + } /* * Test/set of has_async_transaction * must be atomic with enqueue on @@ -2346,14 +2383,6 @@ static void binder_transaction(struct binder_proc *proc, binder_enqueue_work(&t->work, target_list, __LINE__); binder_proc_unlock(target_node->proc, __LINE__); } - - if (target_wait) { - wake_up_interruptible_sync(target_wait); - } else if (wakeup_for_proc_work) { - binder_proc_lock(target_proc, __LINE__); - binder_wakeup_thread(target_proc, !oneway /*sync */); - binder_proc_unlock(target_proc, __LINE__); - } return; err_translate_failed: