Вопрос в Книжном драйвере устройства Linux 3-й о обработчике прерывания для циклического буфера - PullRequest
0 голосов
/ 01 ноября 2019

Я читаю LLDR3, у меня есть вопрос по P.271 в разделе " Реализация обработчика * "

Внизу приведены коды, у меня есть вопросы:

Я вижу writer (ISR) и reader (который активируется ISR), они касаются одного и того же буфера ( short_queue ), поскольку они касаются общегоресурс, разве это не беспокоит случай, когда " short_i_read " был прерван ISR модуля записи, когда он работает с буфером?

Я могу понять, что модуль ISR Writer не будет прерван, посколькуэто ISR и обычно IRQ будет отключен до завершения. Но для буфера чтения "short_i_read" я не вижу места, чтобы гарантировать атомарную работу.

Единственное, что я заметил, это то, что

  • увеличение записи буфера (ISR) только наshort_head
  • увеличение считывателя буфера только на short_tail

Означает ли это, что этот код позволяет автору записи и считывателю только касаться разных переменных, чтобы он достиг вида циклического буфера без блокировки?

irqreturn_t short_interrupt(int irq, void *dev_id, struct pt_regs *regs) {
    struct timeval tv;    
    int written;
    do_gettimeofday(&tv);
    /* Write a 16 byte record. Assume PAGE_SIZE is a multiple of 16 */
    written = sprintf((char *)short_head,"%08u.%06u\n", (int)(tv.tv_sec % 100000000), (int)(tv.tv_usec));    
    BUG_ON(written != 16);
    short_incr_bp(&short_head, written);
    wake_up_interruptible(&short_queue);
    /* awake any reading process */
    return IRQ_HANDLED; 
}


static inline void short_incr_bp(volatile unsigned long *index, int delta) {
    unsigned long new = *index + delta;
    barrier();  /* Don't optimize these two together */
    *index = (new >= (short_buffer + PAGE_SIZE)) ? short_buffer : new; 
}

ssize_t short_i_read (struct file *filp, char __user *buf, size_t count,     loff_t *f_pos) 
{
    int count0;
    DEFINE_WAIT(wait);
    while (short_head == short_tail) {
        prepare_to_wait(&short_queue, &wait, TASK_INTERRUPTIBLE);
        if (short_head == short_tail)
            schedule();
        finish_wait(&short_queue, &wait);
        if (signal_pending (current))  /* a signal arrived */
            return -ERESTARTSYS; /* tell the fs layer to handle it */    
    }    
    /* count0 is the number of readable data bytes */
    count0 = short_head - short_tail;
    if (count0 < 0) /* wrapped */
    count0 = short_buffer + PAGE_SIZE - short_tail;
    if (count0 < count) count = count0;
    if (copy_to_user(buf, (char *)short_tail, count))
        return -EFAULT;
    short_incr_bp (&short_tail, count); 
    return count; 
}

...