|
@@ -822,6 +822,7 @@ static void
|
|
|
binder_enqueue_deferred_thread_work_ilocked(struct binder_thread *thread,
|
|
|
struct binder_work *work)
|
|
|
{
|
|
|
+ WARN_ON(!list_empty(&thread->waiting_thread_node));
|
|
|
binder_enqueue_work_ilocked(work, &thread->todo);
|
|
|
}
|
|
|
|
|
@@ -839,6 +840,7 @@ static void
|
|
|
binder_enqueue_thread_work_ilocked(struct binder_thread *thread,
|
|
|
struct binder_work *work)
|
|
|
{
|
|
|
+ WARN_ON(!list_empty(&thread->waiting_thread_node));
|
|
|
binder_enqueue_work_ilocked(work, &thread->todo);
|
|
|
thread->process_todo = true;
|
|
|
}
|
|
@@ -1270,19 +1272,12 @@ static int binder_inc_node_nilocked(struct binder_node *node, int strong,
|
|
|
} else
|
|
|
node->local_strong_refs++;
|
|
|
if (!node->has_strong_ref && target_list) {
|
|
|
+ struct binder_thread *thread = container_of(target_list,
|
|
|
+ struct binder_thread, todo);
|
|
|
binder_dequeue_work_ilocked(&node->work);
|
|
|
- /*
|
|
|
- * Note: this function is the only place where we queue
|
|
|
- * directly to a thread->todo without using the
|
|
|
- * corresponding binder_enqueue_thread_work() helper
|
|
|
- * functions; in this case it's ok to not set the
|
|
|
- * process_todo flag, since we know this node work will
|
|
|
- * always be followed by other work that starts queue
|
|
|
- * processing: in case of synchronous transactions, a
|
|
|
- * BR_REPLY or BR_ERROR; in case of oneway
|
|
|
- * transactions, a BR_TRANSACTION_COMPLETE.
|
|
|
- */
|
|
|
- binder_enqueue_work_ilocked(&node->work, target_list);
|
|
|
+ BUG_ON(&thread->todo != target_list);
|
|
|
+ binder_enqueue_deferred_thread_work_ilocked(thread,
|
|
|
+ &node->work);
|
|
|
}
|
|
|
} else {
|
|
|
if (!internal)
|
|
@@ -2723,6 +2718,7 @@ static void binder_transaction(struct binder_proc *proc,
|
|
|
{
|
|
|
int ret;
|
|
|
struct binder_transaction *t;
|
|
|
+ struct binder_work *w;
|
|
|
struct binder_work *tcomplete;
|
|
|
binder_size_t *offp, *off_end, *off_start;
|
|
|
binder_size_t off_min;
|
|
@@ -2864,6 +2860,29 @@ static void binder_transaction(struct binder_proc *proc,
|
|
|
goto err_invalid_target_handle;
|
|
|
}
|
|
|
binder_inner_proc_lock(proc);
|
|
|
+
|
|
|
+ w = list_first_entry_or_null(&thread->todo,
|
|
|
+ struct binder_work, entry);
|
|
|
+ if (!(tr->flags & TF_ONE_WAY) && w &&
|
|
|
+ w->type == BINDER_WORK_TRANSACTION) {
|
|
|
+ /*
|
|
|
+ * Do not allow new outgoing transaction from a
|
|
|
+ * thread that has a transaction at the head of
|
|
|
+ * its todo list. Only need to check the head
|
|
|
+ * because binder_select_thread_ilocked picks a
|
|
|
+ * thread from proc->waiting_threads to enqueue
|
|
|
+ * the transaction, and nothing is queued to the
|
|
|
+ * todo list while the thread is on waiting_threads.
|
|
|
+ */
|
|
|
+ binder_user_error("%d:%d new transaction not allowed when there is a transaction on thread todo\n",
|
|
|
+ proc->pid, thread->pid);
|
|
|
+ binder_inner_proc_unlock(proc);
|
|
|
+ return_error = BR_FAILED_REPLY;
|
|
|
+ return_error_param = -EPROTO;
|
|
|
+ return_error_line = __LINE__;
|
|
|
+ goto err_bad_todo_list;
|
|
|
+ }
|
|
|
+
|
|
|
if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
|
|
|
struct binder_transaction *tmp;
|
|
|
|
|
@@ -3247,6 +3266,7 @@ err_alloc_tcomplete_failed:
|
|
|
kfree(t);
|
|
|
binder_stats_deleted(BINDER_STAT_TRANSACTION);
|
|
|
err_alloc_t_failed:
|
|
|
+err_bad_todo_list:
|
|
|
err_bad_call_stack:
|
|
|
err_empty_call_stack:
|
|
|
err_dead_binder:
|