3.3 transaction async request
对于异步传输,在上层空间传下来的数据结构binder_transcation_data中的flags域中可以体现出来,也就是flags的TF_ONE_WAY位为1,就表示需要异步传输,不需要等待回复数据。
其实异步和同步传输在发送请求的过程绝大多数是一样的,这里就不再重复,本小节描述一下关于异步传输独有的地方即可。
关键在函数调用binder_transaction(proc, thread, &tr, cmd == BC_REPLY)中体现了不同:
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
{
if (reply) { // 发送的是回复数据
…
}else { // 发送的是请求数据
…
if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
… // 同步传输的优化
}
}
if (target_thread) {
e->to_thread = target_thread->pid;
target_list = &target_thread->todo;
target_wait = &target_thread->wait;
} else {
target_list = &target_proc->todo;
target_wait = &target_proc->wait;
}
…
if (!reply && !(tr->flags & TF_ONE_WAY))
… // 发送同步非回复数据
else
t->from = NULL; /* 如果是BC_REPLY或者是异步传输,这里不需要记录和返回信息相关的东西。*/
…
t->buffer = binder_alloc_buf(target_proc, tr->data_size,
tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
/* 最后一个参数只有在非回复并且是异步的情况下才会为1,这个值会记录在所分配
的binder_buffer.async_transaction中来表示当前的buffer用在异步传输中还是同步传输中。*/
… // flat_binder_object结构体处理
if (reply) { // 发送的是回复数据
…
}else if (!(t->flags & TF_ONE_WAY)) { // 同步发送请求
…
}else { // 异步发送请求
BUG_ON(target_node == NULL);// 异步传输时目标一定要明确
BUG_ON(t->buffer->async_transaction != 1); // 前面提到的重要标志
// 下面是对异步通讯的分流处理
if (target_node->has_async_transaction) {/* 如果目标task仍然还有一
个异步需要处理的话,该标志为1。*/
target_list = &target_node->async_todo;/* 将当前的这个的异步传输任
务转入目标进程binder_node的异步等待队列async_todo中。*/
target_wait = NULL;
} else
target_node->has_async_transaction = 1;
// 否则,将该标志置1,表明当前有一个异步交互正在处理。
} // else
t->work.type = BINDER_WORK_TRANSACTION;
list_add_tail(&t->work.entry, target_list); /* 将binder_work加入目标任务队
列中: async_todo。 */
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
list_add_tail(&tcomplete->entry, &thread->todo);/* 发送端binder_work加入当
前线程的todo队列中,binder驱动通知发送端,数据已经成功发送出去了。*/
…
if (target_wait) {
…
wake_up_interruptible(target_wait); // target_wait == NULL
}
…
}
对于异步发送请求来说,到这里结束之后,驱动中已经准备好了相应的binder_transaction结构体,只不过极有可能将这个结构体通过其中的binder_work域挂到了目标进程的binder_node.async_todo队列中,直到target_node->has_async_transaction标志为0。接着如果运气好的话,才有可能将binder_transaction移动到目标进程的全局任务队列binder_node.todo中,这时binder驱动就会给他找一个空闲线程来处理这个请求数据包。
3.4 receive request
接收端的task也是利用ioctl()进行读操作的,前面列出的struct binder_write_read结构体中如果有包含读取数据的buffer和预备读取大小,那么在write完该传输的数据之后就会进行read的操作,如下:(整理下思路,以下所讨论的内容均属于另一个进程的某个task,和前面传输部分属于不同的task,所以调用ioctl的时候,所描述的当前task也是接收端的,而非发送端。)
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){ </