上一篇《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 );/* 重新提交,接收下個資料 */
寫操作可以採用其他任何機制,只要保證由同一線程執行即可,不再贅述。