2017-01-29 3 views
5

내 드라이버의 작은 버퍼에 지속적으로 데이터를 밀어 넣는 외부 장치가 있다고 가정합니다. 인터럽트 처리기가 대기중인 사용자 프로세스를 깨우는 대기열을 사용하고 있습니다 (LDD (3rd edition)과 유사 함 - 처리기 구현).리눅스 장치 드라이버 버퍼링 전략

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 

} 

사용자 프로그램은 읽기를 호출하고 인터럽트가 외부 장치에서 새 데이터를 가져올 때까지 대기합니다. 외부 장치는이 코드가 실행할 수있는 것보다 더 빨리 데이터를 푸시 할 수 있으므로 사용자 프로그램이 데이터를 복사하기 전에 데이터를 덮어 쓰지 않도록 어떤 메커니즘을 사용할 수 있습니까? 구조와 같은 링 버퍼가 여기에서 작동합니까? 그것을 구현하는 방법이 명확하지 않습니다.

감사합니다.

+0

drv_buf가 데이터를 가져 오는 방법은 무엇입니까? copy_to_user (usr_buf, drv_buf, count)는 copy_to_user (buf, drv_buf, count) 여야합니다. –

+0

* "사용자 프로그램에서 데이터를 복사하기 전에 데이터를 덮어 쓰지 않도록 어떤 메커니즘을 사용할 수 있습니까?"* 기본적으로 드라이버는 버퍼 오버런이 발생할 때까지 가능한 한 많이 버퍼링 할 수 있습니다. 응답에 제안 된대로 (정적으로 할당 된) 링 버퍼는 (링) 버퍼의 크기가 작을 때만 오버런을 연기 할 수 있습니다. 잘 작성된 운전자는 그러한 상태를 감지하고보고 할 수 있습니다. 동적으로 할당 된 버퍼조차도 "느린"독자에 대처할 수 없을 수도 있습니다. 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 또는 mmap에 또는 둘 모두를 사용할 수 있습니다.

+0

두 명 이상의 사용자가 링 버프에 액세스 할 수있는 경우, 일부 동기식 프리미티브로 보호해야합니다. 즉, 인터럽트 핸들러에서 irq_handler가 잠들 수 있습니까? –

+0

사용자 공간 신호는 Linux 커널의 인터럽트와 동일합니다. 예, 링 버퍼 메커니즘을 사용할 수 있습니다. 하지만 데이터를 보호하기 위해 커널 동기화 방법을 사용해야합니다. –

+0

예, 올바른 잠금을 사용해야합니다 (여기서는 뮤텍스가 충분할 것입니다). 말했듯이 이것은 매우 간단한 구현입니다. –

관련 문제