2016-07-11 77 views
3

我正在使用運行Yocto的嵌入式處理器。我有一個修改uio_pdrv_genirq.c UIO驅動程序。使用select()檢測UIO設備文件上的塊

我在寫一個庫來控制DMA。有一個函數寫入設備文件並啓動DMA。第二個功能是通過調用select()來等待DMA完成。當DMA正在進行時,設備文件被阻塞。完成後,DMA控制器發出一箇中斷,釋放設備文件上的塊。

我有系統的工作與使用閱讀()預期,但我想切換到選擇(),這樣我可以包括超時。但是,當我使用select()時,似乎無法識別該塊,並始終立即返回(在DMA完成之前)。我已經包含了一個簡單版本的代碼:

int gannet_dma_interrupt_wait(dma_device_t *dma_device, 
     dma_direction dma_transfer_direction) { 

    fd_set rfds; 
    struct timeval timeout; 
    int select_res; 

    /* Initialize the file descriptor set and add the device file */ 
    FD_ZERO(&rfds); 
    FD_SET(dma_device->fd, &rfds); 

    /* Set the timeout period. */ 
    timeout.tv_sec = 5; 
    timeout.tv_usec = 0; 

    /* The device file will block until the DMA transfer has completed. */ 
    select_res = select(FD_SETSIZE, &rfds, NULL, NULL, &timeout); 

    /* Reset the channel */ 
    gannet_dma_reset(dma_device, dma_transfer_direction); 

    if (select_res == -1) { 
     /* Select has encountered an error */ 
     perror("ERROR <Interrupt Select Failed>\n"); 
     exit(0); 
    } 
    else if (select_res == 1) { 
     /* The device file descriptor block released */ 
     return 0; 
    } 
    else { 
     /* The device file descriptor block exceeded timeout */ 
     return EINTR; 
    } 
} 

我的代碼有什麼明顯的錯誤嗎?或者任何人都可以提出一個替代選擇?

+0

經過進一步的調查發現,如果我之後包含'read()','select()'將按預期工作。我已經確認它是在這種情況下通過計時兩個函數而被阻塞的'select()'調用。難道是因爲當我只調用'select()'時,編譯器意識到我從來沒有實際執行'read()'並優化'select()'out? –

回答

0

事實證明,該UIO驅動程序包含兩個計數器。一個記錄事件數量(event_count),另一個記錄調用功能知道的多少個事件(listener->event_count)。

當您在UIO驅動程序上執行read()時,它會返回事件的數量,並且 會使listener->event_count等於event_count。即。聽衆現在是最新的 所有發生的事件。

當您在UIO驅動程序中使用poll()select(),它會檢查,如果這兩個 數是不同的,回報,如果他們(如果他們是相同的它 等待,直到它們之間的區別,然後返回)。它不會更新 listener->event_count

顯然,如果你不這樣做的呼叫之間read()select()然後 的listener->event_count將不匹配event_count和第二 select()將立即返回。因此有必要致電select()致電 read()

事後看來,select()似乎應該以這種方式工作,但當時對我來說並不明顯。

0

這個答案假定可以使用select()作爲指定設備文件的內容(我只使用select()來描述socket描述符)。作爲select()的替代函數,您可能想要查看poll()系列函數。接下來希望至少能夠提供一些提示,告訴你可以通過調用select()來解決你的問題。

select()函數的第一個參數必須是最大despriptor數加1.因爲只有一個描述符,所以您可以直接將它傳遞給select()作爲其第一個參數並添加1。 dma_device中的文件描述符可能無效。在超時時間返回EINTR實際上可能是您打算做的事情,但如果情況並非如此,並且要測試無效的描述符,這裏有一個不同的版本供您考慮。 select()調用可能被一個信號中斷,在這種情況下,返回值是-1,errno將被設置爲EINTR。這可以通過您的功能在內部處理,如下所示:

FD_ZERO(&rfds); 
FD_SET(dma_device->fd, &rfds); 

timeout.tv_sec = 5; 
timeout.tv_usec = 0; 

// restart select() if it's interrupted by a signal; 

do { 

    select_res = select(dma_device->fd + 1, &rfds, NULL, NULL, &timeout); 

} 
while(select_res < 0 && errno == EINTR); 


if (select_res > 0) { 

    // a file descriptor is legible 

} 
else { 

    if (select_res == 0) { 

    // select() timed-out 
    } 
    else { 

    // an error other than a signal occurred 

    if (errno == EBADF) { 

     // your file descriptor is invalid 

    } 
    } 
}