2016-07-11 2 views
3

Я работаю над встроенным процессором, работающим с Yocto. У меня есть модифицированный драйвер UIO uio_pdrv_genirq.c.Использование select() для обнаружения блока в файле устройства UIO

Я пишу библиотеку для управления DMA. Существует одна функция, которая записывает в файл устройства и инициирует DMA. Вторая функция предназначена для ожидания завершения DMA путем вызова select(). Пока выполняется 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

После дальнейшего исследования выясняется, что 'select()' будет функционировать должным образом, если я включу 'read()' впоследствии. Я подтвердил, что это вызов 'select()', который блокирует по времени обе функции в этом случае. Может быть, когда я только вызываю 'select()' компилятор понимает, что я никогда не делаю 'read()' и не оптимизирует 'select()' out? –

ответ

0

Оказалось, что драйвер UIO содержит два счетчика. Один записывает количество событий (event_count), а другой регистрирует количество событий, о которых сигнализирует (listener->event_count).

Когда вы делаете read() на водителе UIO возвращает количество событий и делает listener->event_count равного event_count. то есть. слушатель теперь обновляется со всеми событиями, которые произошли.

При использовании poll() или select() на водителя UIO, он проверяет, если эти два числа различны и возвращается, если они (если они таки ждет, пока они не отличаются, а затем возвращается). Он не обновляет listener->event_count.

Очевидно, что если вы не сделаете read() между вызовами select() тогда listener->event_count не будет соответствовать event_count и второй select() будет немедленно вернуться.Поэтому необходимо позвонить read() между звонками до select().

С задним числом кажется ясным, что select() должен работать таким образом, но в то время это было не очевидно.

0

В этом ответе предполагается, что для указанного файла устройства можно использовать select() как предназначенный для этого файла (я использую select() только для дескрипторов сокетов). В качестве альтернативной функции select() вы можете проверить семейство функций poll(). Следующее, мы надеемся, по крайней мере, предложит намеки относительно того, что можно сделать для решения вашей проблемы при вызове select().

Первый параметр функции select() должен быть максимальным числом дескрипторов плюс 1. Поскольку у вас есть только один дескриптор, вы можете передать его непосредственно, чтобы выбрать() в качестве своего первого параметра, и добавить 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 

    } 
    } 
} 
Смежные вопросы