2017-01-29 3 views
5

Предположим, что у меня есть внешнее устройство, которое постоянно толкает данные в небольшой буфер в моем драйвере. Я использую очередь ожидания, где обработчик прерываний пробуждает ожидающий пользовательский процесс (аналогично LDD (3-е издание) - Реализация обработчика).Стратегия буферизации драйвера устройства Linux

irq_handler_t irq_handler(int irq, void *dev_id, struct pt_regs *regs) 
{ 

flag = 1; 
wake_up_interruptible(&wq); 

return IRQ_HANDLED; 
} 

ssize_t my_read(struct file *dev, char __user *buf, size_t count, loff_t *f_pos) 

{ 

     wait_event_interruptible(wq, flag != 0); 
     flag = 0; 
     copy_to_user(usr_buf, drv_buf, count); 

} 


/***********************User program***********************/ 

while(1) 
{  
    read(fid, buffer, size); 

    //do stuff with data 

} 

Пользовательская программа вызывает чтение и ожидает, пока прерывание не получит новые данные с внешнего устройства. Поскольку внешнее устройство может подталкивать данные быстрее, чем это может выполнить код, какие механизмы я могу использовать для обеспечения того, чтобы данные не перезаписывались до того, как программа пользователя скопирует его? Будет ли кольцевой буфер, такой как структура, работать здесь? Неясно, как его реализовать.

Thanks

+0

Как ваши данные drv_buf получают данные? copy_to_user (usr_buf, drv_buf, count) должен быть copy_to_user (buf, drv_buf, count). –

+0

* «Какие механизмы я могу использовать для обеспечения того, чтобы данные не перезаписывались до того, как программа пользователя скопировала его?» * - По сути, драйвер может только буферизировать столько, сколько может, пока не произойдет переполнение буфера. A (статически выделенный) кольцевой буфер (как предлагается в ответе) может только отложить перерасход, если буфер (кольцевой) не имеет размера. Хорошо написанный драйвер сможет обнаружить и сообщить о таком состоянии. Даже динамически распределенные буферы могут оказаться недостаточными, чтобы справиться с «медленным» считывателем. IOW, вы должны убедиться, что пользовательское пространство может не отставать от поступающих данных, по крайней мере, для некоторой усредненной ставки. – sawdust

ответ

2

Да, буфер буфера будет работать.

Вы просто должны заполнить буфер из обработчика прерываний и вы будете читать его из my_read обратного вызова.

Действительно наивны и действительно очень неэффективен реализация может быть (непроверенные):

static irqreturn_t irq_handler(int irq, void *dev_id) 
{ 
     struct my_dev *dev = dev_id; 

     buf[buf_wr] = read_device(dev); 
     buf_wr++; 

     if (buf_wr >= BUFSIZE) 
       buf_wr = 0; 

     wake_up(&wq); 
     return IRQ_HANDLED; 
} 

static ssize_t my_read(struct file *file, char __user *ubuf, 
          size_t sz, loff_t *ppos) 
{ 
     int n, ret; 

     ret = wait_event_interruptible(wq, 
           buf_wr != buf_rd); 
     if (ret) 
       return ret; 

     n = buf_wr - buf_rd; 
     if (n < 0) 
       n += BUFSIZE; 

     n = min(count, n); 
     ret = copy_to_user(ubuf, buf, n); 
     buf_rd += n; 

     if (buf_rd >= BUFSIZE) 
       buf_rd -= BUFSIZE; 

     if (ret) 
       return ret; 

     *ppos += n; 
     return 1; 
} 

Вы также можете использовать DMA или ММАП или оба, чтобы получить что-то более эффективное.

+0

, когда более двух пользователей могут получить доступ к кольцу buff, он должен защищать некоторые синхронные примитивы, средства в обработчике прерываний-irq_handler, могут спать? –

+0

Пользовательский пространственный сигнал эквивалентен прерыванию в ядре Linux Да, вы можете использовать механизм кольцевого буфера. Но вам нужно использовать метод синхронизации ядра для защиты данных. –

+0

Да, вам определенно нужно использовать правильную блокировку (здесь, вероятно, достаточно мьютекса). Как сказано, это действительно простая реализация, –

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