zircon fifo实现分析

fifo是一种进程间通信机制,是一种先进先出的queue。其设计目的是作为共享内存传输的控制面,
其读写性能比socket或者channel都更加有效率,但是其在elements和buffers的大小上有严格的限制!
//TODO:限制的本质原因

系统调用banjo文件位置:zircon\system\public\zircon\syscalls.banjo

fifo的创建:zx_fifo_create
系统调用到内核的实现为sys_fifo_create

sys_fifo_create
    auto up = ProcessDispatcher::GetCurrent() //调用process的dispatcher的静态方法GetCurrent,获取当前进程的dispatcher对象,主要做权限检查,确认当前进程有FIFO的新建权限!
    FifoDispatcher::Create //限制(count * elemsize)不能大于PAGE_SIZE,即4096。应该可以改!
    out0->make //kernel句柄传递到用户态
    out1->make
    
fifo的读取:zx_fifo_read
系统调用到内核的实现为sys_fifo_read

sys_fifo_read
    auto up = ProcessDispatcher::GetCurrent()
    up->GetDispatcherWithRights
    FifoDispatcher::ReadToUser
    actual_count.copy_to_user
    
fifo的读取:zx_fifo_write
系统调用到内核的实现为zx_fifo_write

zx_fifo_write
    auto up = ProcessDispatcher::GetCurrent()
    up->GetDispatcherWithRights
    FifoDispatcher::WriteFromUser
        FifoDispatcher::WriteSelfLocked
    actual_count.copy_to_user
        
其实fifo的实现非常简单,提供的系统调用接口有3个:create、read、write。
fifo在内核中的实现呈现为一个FifoDispatcher对象,该对象继承自PeeredDispatcher。其包含如下的私有成员:
data_:uint8_t类型的指针,用于存储FIFO数据
head_:指示FIFO中上次写入的下一个位置
tail_:指示FIFO中上次读取的下一个位置
elem_size_:FIFO中存取的元素结构体大小
elem_count_:FIFO中存取的元素结构体数量
mask_:elem_count_-1,用于对head_和tail_取模

不过fifo在zircon内核中还是非常有代表性;其代表了一种双端(peer)对象。
内核中的所有peer对象都继承PeeredDispatcher类。
它包含了一个PeerHolder类型的私有成员,而PeerHolder类型则主要提供一个基于mutex的lock对象及获取这个lock对象指针的get_lock方法。
fifo的读写操作都需要在这个mutex对象的保护下进行,保证数据一致性!
PeeredDispatcher类还包含另一个重要数据成员——peer_,为指向它自身类型的一个指针。

在FifoDispatcher::Create静态方法中,首先会动态创建一个PeerHolder对象,然后将它同时传递给两个fifo的构造函数。
对,这里会创建两个fifo对象(fifo0、fifo1),它们具有相同尺寸的存数据的buffer,但是注意,这两个buffer是相互独立的!
这两个fifo的初始化时,传入了同一个holder对象,这也标志着两个fifo在数据的读写上都会竞争同一把mutex锁,串行执行!!
两个fifo创建好后,会调用Init方法,将各自的peer_成员指向对方,如下:
    fifo0.dispatcher()->Init(fifo1.dispatcher());
    fifo1.dispatcher()->Init(fifo0.dispatcher());
这样两个fifo之间就被一把mutex锁和各自的peer_对象联系了起来,下面还会详细分析下fifo的读写,到时还会更深切的理解内核的peer对象!

FifoDispatcher::ReadToUser
    Guard<fbl::Mutex> guard{get_lock()}; //第一步先获取holder的mutext锁
    ptr.copy_array_to_user //将fifo的数据拷贝到用户空间给定的指针
    peer_->UpdateStateLocked(0u, ZX_FIFO_WRITABLE) //这句的前提是之前fifo已经full,但经过这轮read后fifo有空闲了,所以通知对端(peer)可写
    UpdateStateLocked(ZX_FIFO_READABLE, 0u) //如果本fifo被这轮读空,则置为本fifo dispatcher为不可读!

FifoDispatcher::WriteFromUser
    Guard<fbl::Mutex> guard{get_lock()}; //第一步仍然是先拿holder锁
    peer_->WriteSelfLocked //FifoDispatcher::WriteSelfLocked,这里是直接写到对端(peer)的fifo中去
        ptr.copy_array_from_user //将数据拷贝到fifo中
        UpdateStateLocked(0u, ZX_FIFO_READABLE); //这句执行的前提是之前fifo为空,这轮写入后,需要通知本fifo dispatcher可读
        peer_->UpdateStateLocked(ZX_FIFO_WRITABLE, 0u); //如果本fifo被这轮写满,则设置对端fifo dispatcher为不可写!

这里边涉及到一个UpdateStateLocked函数,没有展开讲,因为在“zircon的event实现及async loop机制”文章中已经讲过,可以参考那里的分析。


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值