wait_event_interruptible和down_interruptible

star_999_xing 2016-02-14 09:59:17
最近在学习驱动,对于中断和信号量不是很清楚,在调试一个usb驱动时,发现这样一个问题,
一个线程调用read接口阻塞在wait_event_interruptible后在另一线程中调用write时就会阻塞在down_interruptible,不是很明白这两个函数之间有什么关系?
下面是驱动的部分代码:
static ssize_t hg3_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos)
{
struct usb_hg3 *dev;
int retval = 0;
struct urb *urb = NULL;
char *buf = NULL;
size_t writesize = min(count, (size_t)MAX_TRANSFER);

printk("get in write \n");

dev = (struct usb_hg3 *)file->private_data;

/* verify that we actually have some data to write */
if (count == 0)
goto exit;

printk("hg3_write: getin down_interruptible\n");
/* limit the number of URBs in flight to stop a user from using up all RAM */
if (!(file->f_flags & O_NONBLOCK))
{
printk("hg3_write: down_interruptible, file->f_flags: %d\n", file->f_flags);
if (down_interruptible(&dev->limit_sem))
{
retval = -ERESTARTSYS;
goto exit;
}
}
else
{
printk("hg3_write: down_trylock\n");
if (down_trylock(&dev->limit_sem))
{
retval = -EAGAIN;
goto exit;
}
}

mutex_lock(&dev->io_mutex);
if (!dev->interface)
{ /* disconnect() was called */
retval = -ENODEV;
goto error;
}
printk("hg3_write: usb_alloc_urb\n");
/* create a urb, and a buffer for it, and copy the data to the urb */
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb)
{
retval = -ENOMEM;
goto error;
}
printk("hg3_write: usb_buffer_alloc\n");
buf = usb_buffer_alloc(dev->udev, writesize, GFP_KERNEL, &urb->transfer_dma);
if (!buf)
{
retval = -ENOMEM;
goto error;
}
printk("hg3_write: copy_from_user\n");
if (copy_from_user(buf, user_buffer, writesize))
{
retval = -EFAULT;
goto error;
}
printk("hg3_write: usb_fill_bulk_urb\n");
/* initialize the urb properly */
usb_fill_bulk_urb(urb, \
dev->udev, \
usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr), \
buf, \
writesize, \
hg3_write_bulk_callback, \
dev);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

/* send the data out the bulk port */
printk("hg3_write: usb_submit_urb\n");
retval = usb_submit_urb(urb, GFP_KERNEL);
if (retval)
{
err("%s - failed submitting write urb, error %d", __FUNCTION__, retval);
goto error;
}

/* release our reference to this urb, the USB core will eventually free it entirely */
usb_free_urb(urb); //为什么不释放
printk("hg3_write: mutex_unlock, then return\n");
mutex_unlock(&dev->io_mutex);
return writesize;

error:
if (urb)
{
usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma);
usb_free_urb(urb);
}
mutex_unlock(&dev->io_mutex);
up(&dev->limit_sem);

exit:
PDEBUG("WRITE exit %d\n", retval);
return retval;
}
static void hg3_write_bulk_callback(struct urb *urb)
{
struct usb_hg3 *dev;

dev = (struct usb_hg3 *)urb->context;

/* sync/async unlink faults aren't errors */
//检查urb的状态,判断这个urb是否成功完成传输
if (urb->status &&
!(urb->status == -ENOENT ||
urb->status == -ECONNRESET ||
urb->status == -ESHUTDOWN))
{
err("%s - nonzero write bulk status received: %d",
__FUNCTION__, urb->status);
}

/* free up our allocated buffer */
usb_buffer_free(urb->dev, urb->transfer_buffer_length,
urb->transfer_buffer, urb->transfer_dma);
usb_free_urb(urb);
up(&dev->limit_sem);
#ifdef HG3_USB_DEBUG
PDEBUG("wr:%d\n\n", test_num_w++);
#endif
}

static ssize_t hg3_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
struct usb_hg3 *dev;
int retval;
ssize_t cur_suffix_tmp;
uint32_t flags = 0;
size_t chunk = 0;

printk("get in read\n");

dev = (struct usb_hg3 *)file->private_data;

mutex_lock(&dev->io_mutex); //这个位置肯定不对, exit后要解互斥锁,前面goto exit会出问题

if (!dev->interface)
{ /* disconnect() was called */
retval = -ENODEV;
goto exit;
}

//非阻塞文件属性,直接返回EAGAIN错误
if (file->f_flags & O_NONBLOCK)
{
retval = -EAGAIN;
goto exit;
}

//无数据可读时挂起等待
while(dev->urb_in_buff.start_suffix == dev->urb_in_buff.cur_suffix)
{
if(wait_event_interruptible(dev->inq, \
(dev->urb_in_buff.cur_suffix != dev->urb_in_buff.start_suffix)))
{
retval = -ERESTARTSYS;
goto exit;
}
}

//获取cur_suffix
spin_lock_irqsave(&(dev->in_buf_lock), flags);
cur_suffix_tmp = dev->urb_in_buff.cur_suffix;
spin_unlock_irqrestore(&(dev->in_buf_lock), flags);

//若cur_suffix > start_suffix,则数据为顺行,未循环回去
if(cur_suffix_tmp > dev->urb_in_buff.start_suffix)
{
//获取本次数据长度
ssize_t cp_len = SuffixOffsetCalc(dev->urb_in_buff.start_suffix, \
cur_suffix_tmp);
/* ****************按照上层需要的length进行拷贝************************* */
size_t chunk = min(cp_len, count); //获取copy给用户的最小值

if(copy_to_user(buffer, \
&dev->urb_in_buff.data[dev->urb_in_buff.start_suffix], chunk))
{
dev->urb_in_buff.start_suffix += chunk; //这个位置直接+,不会超范围. 因为chunk<=count
retval = -EFAULT;
}
else
{
dev->urb_in_buff.start_suffix += chunk;
retval = chunk;
}

}
//数据已循环回到缓冲区头部
else
{
//从start_suffix到缓冲区尾的长度
ssize_t front_len = SuffixOffsetCalc(dev->urb_in_buff.start_suffix, IN_BUFF_EFFCT_SIZE);
//后半部分的长度其实就是cur_suffix_tmp

//将前后两部分拷贝到临时缓冲区拼接起来
memcpy(dev->urb_in_buff.tmp_data, \
&dev->urb_in_buff.data[dev->urb_in_buff.start_suffix], front_len);
memcpy(&dev->urb_in_buff.tmp_data[front_len], dev->urb_in_buff.data, \
cur_suffix_tmp);

chunk = min(SuffixOffsetCalc(dev->urb_in_buff.start_suffix, cur_suffix_tmp), count); //获取copy给用户的最小值

if (copy_to_user(buffer,dev->urb_in_buff.tmp_data, chunk))
{
if(chunk < front_len)
{
dev->urb_in_buff.start_suffix += chunk;
}
else
{
dev->urb_in_buff.start_suffix = chunk - front_len;
}

retval = -EFAULT;
}
else
{
if(chunk < front_len)
{
dev->urb_in_buff.start_suffix += chunk;
}
else
{
dev->urb_in_buff.start_suffix = chunk - front_len;
}
retval = chunk;

}

}

exit:
mutex_unlock(&dev->io_mutex);
return retval;
}

分剩的不多了,请多担待
...全文
539 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
star_999_xing 2016-02-16
  • 打赏
  • 举报
回复
@nswcfd 我在应用层的调用是这样的 先向usb写数据,然后外设才会回复在读,但是读和写是相互独立的线程,所以有时就会出现没有数据需要读时read停在wait_event_interruptible,但是这时我需要写数据,却写不进去了。 有什么办法让读和写之间不相互影响吗?
nswcfd 2016-02-16
  • 打赏
  • 举报
回复
不太清楚您的业务逻辑,不过既然是interruptible就可以被信号中断。
star_999_xing 2016-02-15
  • 打赏
  • 举报
回复
@nswcfd 那我怎样做才能解决这个问题呢? 我尝试使用wait_event_interruptible_timeout,让他在超时退出read,不知道为什么read进入不了中断,而且write还是阻塞状态。
star_999_xing 2016-02-15
  • 打赏
  • 举报
回复
if(!wait_event_interruptible_timeout(dev->inq, \ (dev->urb_in_buff.cur_suffix != dev->urb_in_buff.start_suffix),10000)) { retval = -ERESTARTSYS; goto exit; } 用wait_event_interruptible_timeout可以让write继续执行,但是用ctrl+c非正常退出应用程序的话,驱动还是一直在执行read,这样正常吗?还是我理解的有问题,这个函数不可以被ctrl+C中断。
nswcfd 2016-02-14
  • 打赏
  • 举报
回复
独立的看两个没关系,一个是在描述event,一个在描述semaphore。 不过在这个驱动里就产生了关联: 1. reader首先down_sem,持有信号量; 2. 由于没有数据,reader在event上无线循环,注意并没有释放信号量; 3. writer尝试down_sem失败,被阻塞 不过这不是deadlock,当usb设备上产生数据之后,相应的中断会调用wakeup, 使得2进展下去,从而reader可以up_sem,进一步促使writer的down_sem成功返回。
star_999_xing 2016-02-14
  • 打赏
  • 举报
回复
有没有大神帮忙看看解答一下啊,自己顶

1,318

社区成员

发帖
与我相关
我的任务
社区描述
主要是开发驱动技术
社区管理员
  • 驱动程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧