上一篇《Linux系统中的gadgetfs介绍》介绍了Linux系统中Gadgetfs使用的基本方法,接下来再介绍下如何使用单线程同步Gadgetfs提供的俩个Bulk endpoint的读写。

一般来说,针对Gadgetfs的一个读端,一个写端可以使用俩个线程进行分别操作,但在某些通信协议中,上层会话要求接收到指定数量的数据包后,接收方要给予确认。这个确认包在某些情况下,是接收方确认接收到的某个包的seqno,但此时发送方可能已经发送了后续的其他数据包。因此,可能会出现部分包重传的情况,导致了额外的带宽占用,所以有必要对读写线程的同步进行控制。个人比较喜欢使用单线程同时提供读写机制,但这要求读写的俩个Endpoint都支持poll操作。实际调查中发现,Gadgetfs的Control Endpoint支持poll操作,但ep1in&ep1out俩个Endpoint,并不支持poll操作,这就导致以上的简单思想无法实现。再深入调查后,了解到Gadgetfs的Endpoint文件描述符支持aio,aio又可以和eventfd结合起来,使得poll操作可以执行,从而实现在单线程中,对读写俩个操作进行同步及优先级的控制。

这里主要介绍下读端的poll操作如何实现。

续上一篇:在完成了对$EP的设置后,基于libaio的接口,创建一个异步读操作的context:

io_setup( 1, &ioCtx );

创建eventfd:

ep1EventFd  =   eventfd( 0, EFD_NONBLOCK | EFD_CLOEXEC );

填充libaio的数据结构struct iocb:

io_prep_pread( ioCb, _ep1Out, driverbuffer, 1024, 0 );/* ioCb为指向struct iocb的指针,_ep1Out为读端fd,driverbuffer大小为1024*/

设置aio的eventfd

io_set_eventfd( ioCb, ep1EventFd );

提交aio读操作:

io_submit( ioCtx, 1, &ioCb );

之后就可以针对eventfd进行poll操作,侦听是否有数据到达。

poll返回后,数据已经写入到driverbuffer中,后续处理如下:

struct io_event _event;

struct timespec _timeout = { 0, 0 };

uint64_t _num;

io_getevents( ioCtx, 0, 1, &_event, &_timeout );/* 获取到达数据的基本信息,_event.res为数据的长度 */

read( ep1EventFd, &_num, sizeof( uint64_t ));/* clear eventfd */

io_submit( ioCtx, 1, &ioCb );/* 重新提交,接收下个数据 */

写操作可以采用其他任何机制,只要保证由同一线程执行即可,不再赘述。

Logo

更多推荐