ipc原理linux,技术内幕:Android的IPC机制-Binder

3.2.2  Binder驱动的实现(6)

14.binder_flush

flush操作接口将在关闭一个设备文件描述符复制时被调用。该函数的实现十分简单,如代码清单3-21所示。

代码清单3-21  binder_flush的实现static int binder_flush(struct file *filp, fl_owner_t id)

{

struct binder_proc *proc=filp->private_data;

binder_defer_work(proc, BINDER_DEFERRED_FLUSH);

return 0;

}

正如上面所说的,通过调用一个workqueue来执行BINDER_DEFERRED_FLUSH操作,从而完成该flush操作,但是最终的处理还是交给了binder_defer_work函数。

15.binder_poll

poll函数是非阻塞型IO的内核驱动实现,所有支持非阻塞IO操作的设备驱动都需要实现poll函数。Binder的poll函数仅支持设备是否可以非阻塞地读(POLLIN),这里有两种等待任务:一种是proc_work,另一种是thread_work。同其他驱动的poll实现一样,这里也是通过调用poll_wait函数来实现的:具体实现如代码清单3-22所示。

代码清单3-22  binder_poll的实现static unsigned int binder_poll(struct file *filp, struct poll_table_struct *wait)

{

struct binder_proc *proc=filp->private_data;

struct binder_thread *thread=NULL;

int wait_for_proc_work;

mutex_lock(&binder_lock);

//得到当前进程的信息

thread=binder_get_thread(proc);

wait_for_proc_work=thread->transaction_stack== NULL &&

list_empty(&thread->todo) && thread->return_error== BR_OK;

mutex_unlock(&binder_lock);

//proc_work方式

if (wait_for_proc_work) {

if (binder_has_proc_work(proc, thread))

return POLLIN;

poll_wait(filp, &proc->wait, wait);

if (binder_has_proc_work(proc, thread))

return POLLIN;

} else {//thread_work方式

if (binder_has_thread_work(thread))

return POLLIN;

poll_wait(filp, &thread->wait, wait);

if (binder_has_thread_work(thread))

return POLLIN;

}

return 0;

}

首先需要取得当前进程/线程的信息,由于所有的线程信息都存储在binder_proc结构体的threads队列中,所以我们可以通过binder_get_thread(proc)来找到当前进程/线程的相关信息,稍后会详细分析查找原理。proc_work和thread_work方式如代码清单3-23所示。

代码清单3-23  proc_work和thread_work的实现static int binder_has_proc_work(struct binder_proc

*proc, struct binder_thread *thread)

{

return !list_empty(&proc->todo) || (thread->looper &

BINDER_LOOPER_STATE_NEED_RETURN);

}

static int binder_has_thread_work(struct binder_thread *thread)

{

return !list_empty(&thread->todo) || thread->return_error != BR_OK ||

(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN);

}

其中,主要是通过检测线程队列是否为空、线程的循环状态以及返回信息来判断所要采用的等待方式,最后通过调用poll_wait函数来实现poll操作。

16.binder_get_thread

该函数可以用于在threads队列中查找当前的进程信息,实现如代码清单3-24所示。

代码清单3-24  binder_get_thread的实现static struct binder_thread *binder_get_thread(struct binder_proc *proc)

{

struct binder_thread *thread=NULL;

struct rb_node *parent=NULL;

//取得队列中的线程

struct rb_node **p= &proc->threads.rb_node;

while (*p) {

parent= *p;

// 取得将要进行比较的线程

thread=rb_entry(parent, struct binder_thread, rb_node);

//比较

if (current->pidpid)

p= &(*p)->rb_left;

else if (current->pid>thread->pid)

p= &(*p)->rb_right;

else

break;

}

//如果不存在

if (*p== NULL) {

//创建一个新进程

thread=kzalloc(sizeof(*thread), GFP_KERNEL);

if (thread== NULL)

return NULL;

//初始化新进程的一系列数据信息

binder_stats.obj_created[BINDER_STAT_THREAD]++;

thread->procproc= proc;

thread->pid=current->pid;

//初始化等待队列

init_waitqueue_head(&thread->wait);

//初始化链表头

INIT_LIST_HEAD(&thread->todo);

//加入到队列

rb_link_node(&thread->rb_node, parent, p);

rb_insert_color(&thread->rb_node, &proc->threads);

//设置其循环状态

thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN;

thread->return_error=BR_OK;

thread->return_error2=BR_OK;

}

return thread;

}

实现原理是通过在队列中比较各个线程的pid与当前线程的pid是否相同,如果找到了,把它的线程信息返回;如果没找到,新建一个线程并把它加入到队列中,然后初始化就绪线程队列等。代码的注释已经把每一个步骤都讲清楚了。0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值