From: Riley Andrews <riandrews@android.com>
To: linux-kernel@vger.kernel.org,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"Arve Hjønnevåg" <arve@android.com>,
"Riley Andrews" <riandrews@android.com>,
devel@driverdev.osuosl.org
Subject: [PATCH 10/13] android: binder: refactor binder_thread_read loop
Date: Thu, 28 May 2015 16:08:28 -0700 [thread overview]
Message-ID: <1432854511-33320-11-git-send-email-riandrews@android.com> (raw)
In-Reply-To: <1432854511-33320-1-git-send-email-riandrews@android.com>
Add dedicated functions for every work type in the switch statement.
Refactor the loop logic to remove the while 1, and make it explicit
which work items cause the loop to exit.
Signed-off-by: Riley Andrews <riandrews@android.com>
---
drivers/android/binder.c | 433 +++++++++++++++++++++++++----------------------
1 file changed, 231 insertions(+), 202 deletions(-)
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index abd5556..b69ca0a 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -2327,6 +2327,207 @@ static int binder_has_thread_work(struct binder_thread *thread)
(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN);
}
+static int binder_work_transaction(struct binder_thread *thread,
+ struct binder_work *w, void * __user *ptr)
+{
+ struct binder_proc *proc = thread->proc;
+ struct binder_transaction_data tr;
+ struct binder_transaction *t;
+ uint32_t cmd;
+
+ t = container_of(w, struct binder_transaction, work);
+ BUG_ON(!t->buffer);
+ if (t->buffer->target_node) {
+ struct binder_node *target_node = t->buffer->target_node;
+
+ tr.target.ptr = target_node->ptr;
+ tr.cookie = target_node->cookie;
+ t->saved_priority = task_nice(current);
+ if (t->priority < target_node->min_priority &&
+ !(t->flags & TF_ONE_WAY))
+ binder_set_nice(t->priority);
+ else if (!(t->flags & TF_ONE_WAY) ||
+ t->saved_priority > target_node->min_priority)
+ binder_set_nice(target_node->min_priority);
+ cmd = BR_TRANSACTION;
+ } else {
+ tr.target.ptr = 0;
+ tr.cookie = 0;
+ cmd = BR_REPLY;
+ }
+ tr.code = t->code;
+ tr.flags = t->flags;
+ tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid);
+
+ if (t->from) {
+ struct task_struct *sender = t->from->proc->tsk;
+
+ tr.sender_pid = task_tgid_nr_ns(sender,
+ task_active_pid_ns(current));
+ } else {
+ tr.sender_pid = 0;
+ }
+
+ tr.data_size = t->buffer->data_size;
+ tr.offsets_size = t->buffer->offsets_size;
+ tr.data.ptr.buffer = (binder_uintptr_t)((uintptr_t)t->buffer->data +
+ proc->user_buffer_offset);
+ tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size,
+ sizeof(void *));
+
+ if (put_user(cmd, (uint32_t __user *)*ptr))
+ return -EFAULT;
+ *ptr += sizeof(uint32_t);
+ if (copy_to_user(*ptr, &tr, sizeof(tr)))
+ return -EFAULT;
+ *ptr += sizeof(tr);
+
+ trace_binder_transaction_received(t);
+ binder_stat_br(proc, thread, cmd);
+ binder_debug(BINDER_DEBUG_TRANSACTION,
+ "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %016llx-%016llx\n",
+ proc->pid, thread->pid,
+ (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : "BR_REPLY",
+ t->debug_id, t->from ? t->from->proc->pid : 0,
+ t->from ? t->from->pid : 0, cmd,
+ t->buffer->data_size, t->buffer->offsets_size,
+ (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets);
+
+ list_del(&t->work.entry);
+ t->buffer->allow_user_free = 1;
+ if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
+ t->to_thread = thread;
+ binder_dst_save_transaction(thread, t);
+ } else {
+ t->buffer->transaction = NULL;
+ kfree(t);
+ binder_stats_deleted(BINDER_STAT_TRANSACTION);
+ }
+ return 0;
+}
+
+static int binder_work_node(struct binder_thread *thread,
+ struct binder_work *w, void * __user *ptr)
+{
+ struct binder_node *node = container_of(w, struct binder_node, work);
+ struct binder_proc *proc = thread->proc;
+ uint32_t cmd = BR_NOOP;
+ const char *cmd_name;
+ int strong = node->internal_strong_refs || node->local_strong_refs;
+ int weak = !hlist_empty(&node->refs) || node->local_weak_refs || strong;
+
+ if (weak && !node->has_weak_ref) {
+ cmd = BR_INCREFS;
+ cmd_name = "BR_INCREFS";
+ node->has_weak_ref = 1;
+ node->pending_weak_ref = 1;
+ node->local_weak_refs++;
+ } else if (strong && !node->has_strong_ref) {
+ cmd = BR_ACQUIRE;
+ cmd_name = "BR_ACQUIRE";
+ node->has_strong_ref = 1;
+ node->pending_strong_ref = 1;
+ node->local_strong_refs++;
+ } else if (!strong && node->has_strong_ref) {
+ cmd = BR_RELEASE;
+ cmd_name = "BR_RELEASE";
+ node->has_strong_ref = 0;
+ } else if (!weak && node->has_weak_ref) {
+ cmd = BR_DECREFS;
+ cmd_name = "BR_DECREFS";
+ node->has_weak_ref = 0;
+ }
+ if (cmd != BR_NOOP) {
+ if (put_user(cmd, (uint32_t __user *)*ptr))
+ return -EFAULT;
+ *ptr += sizeof(uint32_t);
+ if (put_user(node->ptr, (binder_uintptr_t __user *)*ptr))
+ return -EFAULT;
+ *ptr += sizeof(binder_uintptr_t);
+ if (put_user(node->cookie, (binder_uintptr_t __user *)*ptr))
+ return -EFAULT;
+ *ptr += sizeof(binder_uintptr_t);
+
+ binder_stat_br(proc, thread, cmd);
+ binder_debug(BINDER_DEBUG_USER_REFS,
+ "%d:%d %s %d u%016llx c%016llx\n",
+ proc->pid, thread->pid, cmd_name, node->debug_id,
+ (u64)node->ptr, (u64)node->cookie);
+ } else {
+ list_del_init(&w->entry);
+ if (!weak && !strong) {
+ binder_debug(BINDER_DEBUG_INTERNAL_REFS,
+ "%d:%d node %d u%016llx c%016llx deleted\n",
+ proc->pid, thread->pid, node->debug_id,
+ (u64)node->ptr, (u64)node->cookie);
+ rb_erase(&node->rb_node, &proc->nodes);
+ kfree(node);
+ binder_stats_deleted(BINDER_STAT_NODE);
+ } else {
+ binder_debug(BINDER_DEBUG_INTERNAL_REFS,
+ "%d:%d node %d u%016llx c%016llx state unchanged\n",
+ proc->pid, thread->pid, node->debug_id,
+ (u64)node->ptr, (u64)node->cookie);
+ }
+ }
+ return 0;
+}
+
+static int binder_work_dead_binder(struct binder_thread *thread,
+ struct binder_work *w, void * __user *ptr)
+{
+ struct binder_ref_death *death;
+ struct binder_proc *proc = thread->proc;
+ uint32_t cmd;
+
+ death = container_of(w, struct binder_ref_death, work);
+ if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION)
+ cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE;
+ else
+ cmd = BR_DEAD_BINDER;
+ if (put_user(cmd, (uint32_t __user *)*ptr))
+ return -EFAULT;
+ *ptr += sizeof(uint32_t);
+ if (put_user(death->cookie, (binder_uintptr_t __user *)*ptr))
+ return -EFAULT;
+ *ptr += sizeof(binder_uintptr_t);
+ binder_stat_br(proc, thread, cmd);
+ binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, "%d:%d %s %016llx\n",
+ proc->pid, thread->pid, cmd == BR_DEAD_BINDER ?
+ "BR_DEAD_BINDER" : "BR_CLEAR_DEATH_NOTIFICATION_DONE",
+ (u64)death->cookie);
+
+ if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) {
+ list_del(&w->entry);
+ kfree(death);
+ binder_stats_deleted(BINDER_STAT_DEATH);
+ } else {
+ list_move(&w->entry, &proc->delivered_death);
+ }
+ return 0;
+}
+
+static int binder_work_tr_complete(struct binder_thread *thread,
+ struct binder_work *w, void * __user *ptr)
+{
+ uint32_t cmd = BR_TRANSACTION_COMPLETE;
+ struct binder_proc *proc = thread->proc;
+
+ if (put_user(cmd, (uint32_t __user *)*ptr))
+ return -EFAULT;
+ *ptr += sizeof(uint32_t);
+
+ binder_stat_br(proc, thread, cmd);
+ binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE,
+ "%d:%d BR_TRANSACTION_COMPLETE\n",
+ proc->pid, thread->pid);
+
+ list_del(&w->entry);
+ kfree(w);
+ binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
+ return 0;
+}
+
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
@@ -2408,11 +2609,9 @@ retry:
if (ret)
return ret;
- while (1) {
- uint32_t cmd;
- struct binder_transaction_data tr;
+ while (((end - ptr) >= sizeof(struct binder_transaction_data) + 4)) {
struct binder_work *w;
- struct binder_transaction *t = NULL;
+ bool done_processing_work = false;
if (!list_empty(&thread->todo)) {
w = list_first_entry(&thread->todo, struct binder_work,
@@ -2428,209 +2627,39 @@ retry:
break;
}
- if (end - ptr < sizeof(tr) + 4)
- break;
-
switch (w->type) {
- case BINDER_WORK_TRANSACTION: {
- t = container_of(w, struct binder_transaction, work);
- } break;
- case BINDER_WORK_TRANSACTION_COMPLETE: {
- cmd = BR_TRANSACTION_COMPLETE;
- if (put_user(cmd, (uint32_t __user *)ptr))
- return -EFAULT;
- ptr += sizeof(uint32_t);
-
- binder_stat_br(proc, thread, cmd);
- binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE,
- "%d:%d BR_TRANSACTION_COMPLETE\n",
- proc->pid, thread->pid);
-
- list_del(&w->entry);
- kfree(w);
- binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
- } break;
- case BINDER_WORK_NODE: {
- struct binder_node *node = container_of(w, struct binder_node, work);
- uint32_t cmd = BR_NOOP;
- const char *cmd_name;
- int strong = node->internal_strong_refs || node->local_strong_refs;
- int weak = !hlist_empty(&node->refs) || node->local_weak_refs || strong;
-
- if (weak && !node->has_weak_ref) {
- cmd = BR_INCREFS;
- cmd_name = "BR_INCREFS";
- node->has_weak_ref = 1;
- node->pending_weak_ref = 1;
- node->local_weak_refs++;
- } else if (strong && !node->has_strong_ref) {
- cmd = BR_ACQUIRE;
- cmd_name = "BR_ACQUIRE";
- node->has_strong_ref = 1;
- node->pending_strong_ref = 1;
- node->local_strong_refs++;
- } else if (!strong && node->has_strong_ref) {
- cmd = BR_RELEASE;
- cmd_name = "BR_RELEASE";
- node->has_strong_ref = 0;
- } else if (!weak && node->has_weak_ref) {
- cmd = BR_DECREFS;
- cmd_name = "BR_DECREFS";
- node->has_weak_ref = 0;
- }
- if (cmd != BR_NOOP) {
- if (put_user(cmd, (uint32_t __user *)ptr))
- return -EFAULT;
- ptr += sizeof(uint32_t);
- if (put_user(node->ptr,
- (binder_uintptr_t __user *)ptr))
- return -EFAULT;
- ptr += sizeof(binder_uintptr_t);
- if (put_user(node->cookie,
- (binder_uintptr_t __user *)ptr))
- return -EFAULT;
- ptr += sizeof(binder_uintptr_t);
-
- binder_stat_br(proc, thread, cmd);
- binder_debug(BINDER_DEBUG_USER_REFS,
- "%d:%d %s %d u%016llx c%016llx\n",
- proc->pid, thread->pid, cmd_name,
- node->debug_id,
- (u64)node->ptr, (u64)node->cookie);
- } else {
- list_del_init(&w->entry);
- if (!weak && !strong) {
- binder_debug(BINDER_DEBUG_INTERNAL_REFS,
- "%d:%d node %d u%016llx c%016llx deleted\n",
- proc->pid, thread->pid,
- node->debug_id,
- (u64)node->ptr,
- (u64)node->cookie);
- rb_erase(&node->rb_node, &proc->nodes);
- kfree(node);
- binder_stats_deleted(BINDER_STAT_NODE);
- } else {
- binder_debug(BINDER_DEBUG_INTERNAL_REFS,
- "%d:%d node %d u%016llx c%016llx state unchanged\n",
- proc->pid, thread->pid,
- node->debug_id,
- (u64)node->ptr,
- (u64)node->cookie);
- }
- }
- } break;
+ case BINDER_WORK_TRANSACTION:
+ ret = binder_work_transaction(thread, w, &ptr);
+ /*
+ * Threads can only handle one incoming transaction,
+ * at a time, so return before processing any more
+ * transaction work nodes.
+ */
+ done_processing_work = true;
+ break;
+ case BINDER_WORK_TRANSACTION_COMPLETE:
+ ret = binder_work_tr_complete(thread, w, &ptr);
+ break;
+ case BINDER_WORK_NODE:
+ ret = binder_work_node(thread, w, &ptr);
+ break;
case BINDER_WORK_DEAD_BINDER:
case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
- case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: {
- struct binder_ref_death *death;
- uint32_t cmd;
-
- death = container_of(w, struct binder_ref_death, work);
- if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION)
- cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE;
- else
- cmd = BR_DEAD_BINDER;
- if (put_user(cmd, (uint32_t __user *)ptr))
- return -EFAULT;
- ptr += sizeof(uint32_t);
- if (put_user(death->cookie,
- (binder_uintptr_t __user *)ptr))
- return -EFAULT;
- ptr += sizeof(binder_uintptr_t);
- binder_stat_br(proc, thread, cmd);
- binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION,
- "%d:%d %s %016llx\n",
- proc->pid, thread->pid,
- cmd == BR_DEAD_BINDER ?
- "BR_DEAD_BINDER" :
- "BR_CLEAR_DEATH_NOTIFICATION_DONE",
- (u64)death->cookie);
-
- if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) {
- list_del(&w->entry);
- kfree(death);
- binder_stats_deleted(BINDER_STAT_DEATH);
- } else
- list_move(&w->entry, &proc->delivered_death);
- if (cmd == BR_DEAD_BINDER)
- goto done; /* DEAD_BINDER notifications can cause transactions */
- } break;
- }
-
- if (!t)
- continue;
-
- BUG_ON(t->buffer == NULL);
- if (t->buffer->target_node) {
- struct binder_node *target_node = t->buffer->target_node;
-
- tr.target.ptr = target_node->ptr;
- tr.cookie = target_node->cookie;
- t->saved_priority = task_nice(current);
- if (t->priority < target_node->min_priority &&
- !(t->flags & TF_ONE_WAY))
- binder_set_nice(t->priority);
- else if (!(t->flags & TF_ONE_WAY) ||
- t->saved_priority > target_node->min_priority)
- binder_set_nice(target_node->min_priority);
- cmd = BR_TRANSACTION;
- } else {
- tr.target.ptr = 0;
- tr.cookie = 0;
- cmd = BR_REPLY;
- }
- tr.code = t->code;
- tr.flags = t->flags;
- tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid);
-
- if (t->from) {
- struct task_struct *sender = t->from->proc->tsk;
-
- tr.sender_pid = task_tgid_nr_ns(sender,
- task_active_pid_ns(current));
- } else {
- tr.sender_pid = 0;
+ /*
+ * Dead binder notifications can cause userspace to
+ * issue transactions, so break out here so that only
+ * one notification is given to userspace at a time.
+ */
+ done_processing_work = true;
+ case BINDER_WORK_CLEAR_DEATH_NOTIFICATION:
+ ret = binder_work_dead_binder(thread, w, &ptr);
+ break;
}
+ if (ret < 0)
+ return ret;
- tr.data_size = t->buffer->data_size;
- tr.offsets_size = t->buffer->offsets_size;
- tr.data.ptr.buffer = (binder_uintptr_t)(
- (uintptr_t)t->buffer->data +
- proc->user_buffer_offset);
- tr.data.ptr.offsets = tr.data.ptr.buffer +
- ALIGN(t->buffer->data_size,
- sizeof(void *));
-
- if (put_user(cmd, (uint32_t __user *)ptr))
- return -EFAULT;
- ptr += sizeof(uint32_t);
- if (copy_to_user(ptr, &tr, sizeof(tr)))
- return -EFAULT;
- ptr += sizeof(tr);
-
- trace_binder_transaction_received(t);
- binder_stat_br(proc, thread, cmd);
- binder_debug(BINDER_DEBUG_TRANSACTION,
- "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %016llx-%016llx\n",
- proc->pid, thread->pid,
- (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" :
- "BR_REPLY",
- t->debug_id, t->from ? t->from->proc->pid : 0,
- t->from ? t->from->pid : 0, cmd,
- t->buffer->data_size, t->buffer->offsets_size,
- (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets);
-
- list_del(&t->work.entry);
- t->buffer->allow_user_free = 1;
- if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
- t->to_thread = thread;
- binder_dst_save_transaction(thread, t);
- } else {
- t->buffer->transaction = NULL;
- kfree(t);
- binder_stats_deleted(BINDER_STAT_TRANSACTION);
- }
- break;
+ if (done_processing_work)
+ break;
}
done:
--
2.2.0.rc0.207.ga3a616c
next prev parent reply other threads:[~2015-05-28 23:11 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-05-28 23:08 [PATCH 0/13] Binder driver refactor and minor bug fixes Riley Andrews
2015-05-28 23:08 ` [PATCH 01/13] drivers: android: correct the size of struct binder_uintptr_t for BC_DEAD_BINDER_DONE Riley Andrews
2015-05-29 9:23 ` Dan Carpenter
2015-05-28 23:08 ` [PATCH 02/13] android: binder: fix duplicate error return Riley Andrews
2015-05-28 23:08 ` [PATCH 03/13] android: binder: refactor binder_thread_write Riley Andrews
2015-05-29 10:06 ` Dan Carpenter
2015-05-28 23:08 ` [PATCH 04/13] android: binder: refactor binder_transact handle translation Riley Andrews
2015-05-28 23:08 ` [PATCH 05/13] android: binder: refactor binder_transact transaction buffer loop Riley Andrews
2015-05-29 10:25 ` Dan Carpenter
2015-05-28 23:08 ` [PATCH 06/13] android: binder: add function to find target binder node Riley Andrews
2015-05-28 23:08 ` [PATCH 07/13] android: binder: add functions for manipulating transaction stack Riley Andrews
2015-05-28 23:08 ` [PATCH 08/13] android: binder: add function for logging failed transactions Riley Andrews
2015-05-28 23:08 ` [PATCH 09/13] android: binder: add function for finding prior thread in transaction stack Riley Andrews
2015-05-28 23:08 ` Riley Andrews [this message]
2015-05-28 23:08 ` [PATCH 11/13] android: binder: add function to handle waiting for binder_thread_read Riley Andrews
2015-05-28 23:08 ` [PATCH 12/13] android: binder: add function to pass thread errors to userspace Riley Andrews
2015-05-28 23:08 ` [PATCH 13/13] android: binder: add function for processing work nodes in binder_thread_read Riley Andrews
2015-05-29 11:56 ` Dan Carpenter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1432854511-33320-11-git-send-email-riandrews@android.com \
--to=riandrews@android.com \
--cc=arve@android.com \
--cc=devel@driverdev.osuosl.org \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®