免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1879 | 回复: 4
打印 上一主题 下一主题

[内核模块] 关于在sysfs attribute文件访问接口中使用wait_queue不会阻塞? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-05-25 20:15 |只看该作者 |倒序浏览
本帖最后由 luakuc 于 2014-05-25 20:24 编辑

最近尝试在Linux 3.12写一个虚拟设备模块,想利用户空间导出属性文件的方式提供用户空间的访问虚拟设备接口:

虚拟设备的定义如下:
  1. struct fifo_device{
  2.         struct device device;
  3.         char fifo[FIFO_BYTE];//读写缓冲区
  4.         size_t current_data_pos; //指示缓冲区已存储数据开始位置
  5.         size_t start_empty_pos;//指示缓冲区可存储数据开始位置
  6.         ssize_t remaind_space;指示缓冲区剩余空间
  7.         void *private_data;

  8.         wait_queue_head_t r_wait;//用于当缓冲区为空时阻塞当前读进程
  9.         wait_queue_head_t w_wait;//用于当缓冲区为满时阻塞当前写进程

  10.         char  name[1];//虚拟设备名字
  11. } fifo_dev;
复制代码
为fifo_dev创建属性文件DEVICE_ATTR_RW("MEM",其show()/store()定义如下:
  1. static ssize_t MEM_device_show(struct device*dev,struct device_attribute *attr,char *buf)
  2. {
  3.         struct fifo_device *pfifo_dev = to_fifo_device(dev);
  4.         static int i=0;

  5.          DECLARE_WAITQUEUE(wait,current);//澹版槑绛夊緟闃熷垪(涓?殑闃熷垪鎴愬憳)

  6.         add_wait_queue(&pfifo_dev->r_wait,&wait);//为读等待队列头添加等待队列
  7.        
  8.         if(unlikely(pfifo_dev->remaind_space >= FIFO_BYTE))
  9.         //while(unlikely(pfifo_dev->remaind_space == FIFO_BYTE))
  10.         {               
  11.                         __set_current_state(TASK_INTERRUPTIBLE);
  12.                         schedule();//在这里由于缓冲区为空,会发生相应读进程调度

  13.                      printk(KERN_EMERG"show : %d remaind_space: %d \n",i++,pfifo_dev->remaind_space);
  14.         }

  15.         {
  16.                 int i=0;
  17.                 int ret=FIFO_BYTE- pfifo_dev->remaind_space;
  18.                 for(;i<ret;i++)
  19.                 {
  20.                         buf[i] = pfifo_dev->fifo[pfifo_dev->current_data_pos];
  21.                         pfifo_dev->current_data_pos = (pfifo_dev->current_data_pos+1)%FIFO_BYTE;
  22.                 }               
  23.         pfifo_dev->remaind_space=pfifo_dev->remaind_space+ret;
  24.        
  25.        
  26.         remove_wait_queue(&pfifo_dev->r_wait,&wait);
  27.         wake_up_interruptible(&pfifo_dev->w_wait);
  28.         __set_current_state(TASK_RUNNING);
  29.         printk(KERN_EMERG"ret : %d\n",ret);
  30.         return ret;

  31.         }
  32. }
复制代码
  1. static ssize_t MEM_device_store(struct device *pdev,struct device_attribute *attr,const char *buf,size_t count)
  2. {
  3.         struct fifo_device *pfifo_dev = to_fifo_device(pdev);
  4.         DECLARE_WAITQUEUE(wait,current);
  5.        
  6.         add_wait_queue(&pfifo_dev->w_wait,&wait);

  7.         if(unlikely(pfifo_dev->remaind_space==0))
  8.         {
  9.                 __set_current_state(TASK_INTERRUPTIBLE);
  10.                 schedule();
  11.         }

  12.         {
  13.                 ssize_t ret  =0;
  14.                 int i=0;               
  15.                 if(likely(pfifo_dev->remaind_space >= count))
  16.                         ret = count;
  17.                 else
  18.                         ret = pfifo_dev->remaind_space;
  19.        
  20.                
  21.                         for(;i<ret;i++)
  22.                         {
  23.                                 pfifo_dev->fifo[pfifo_dev->start_empty_pos]=buf[i];
  24.                                 pfifo_dev->start_empty_pos= (pfifo_dev->start_empty_pos+1)%FIFO_BYTE;
  25.                         }
  26.                 pfifo_dev->remaind_space = pfifo_dev->remaind_space - ret;
  27.                
  28.                
  29.                 remove_wait_queue(&pfifo_dev->w_wait,&wait);
  30.                 wake_up_interruptible(&pfifo_dev->r_wait);
  31.                 __set_current_state(TASK_RUNNING);
  32.                 return ret;
  33.         }
  34. }
复制代码
用户空间访问:
  1. int main(int argc,char **argv)
  2. {
  3.         ssize_t bytes;
  4.         char  buf[30];
  5.         int fd = open("/sys/devices/fifo-IPC-bus/mini_fifo/fifo-MEM",O_RDWR);
  6.         if(fd < 0)
  7.         {
  8.                 perror("open");
  9.                 return fd;
  10.         }
  11.         while(*argv[1]=='r')
  12.         {
  13.                 memset(buf,0,30);
  14.         bytes = read(fd,buf,10);

  15.         printf("len: %d  read: %s\n",bytes,buf);

  16.         sleep(1);
  17.         }
  18.         while(*argv[1]=='w')
  19.         {
  20.                
  21.                 bytes= write(fd,"--write--",9);
  22.                 if(bytes<0)
  23.                 {
  24.                         perror("write");
  25.                         return -errno;
  26.                 }
  27.                 sleep(1);
  28.         }
  29.         return 0;
  30. }
复制代码
运行的情形:
1,首先运行读进程时,(由于现在缓冲区没有数据) ,读进程被阻塞
2,运行写进程时,由于里面有数据,其会**读进程,并且打印读出的数据
3,关闭写进程,读进程读并且打印直至缓冲区为空
4,读进程继续打印信息为len 0 : read:                   <----------疑问在这,<1>既然缓冲区为空为什么没有被阻塞(或者说read()怎么就返回了,不应该是在VFS级别已经做了NONBLOCK吧??)??

<2> 在地3步,假如不关闭写进程,读写进程一直可以正常读写

下面是疑问<1>用trace跟踪读进程的输出:
......
read(3, "", 10)                         = 0
write(1, "--read 0--\n", 11--read 0--
)            = 11
write(1, "len: 0  read: \n", 15len: 0  read:
)        = 15
rt_sigprocmask(SIG_BLOCK, [CHLD], [], = 0
rt_sigaction(SIGCHLD, NULL, {SIG_DFL, [], 0}, = 0
rt_sigprocmask(SIG_SETMASK, [], NULL, = 0
nanosleep({1, 0}, 0xbf957534)           = 0
read(3, "", 10)
.......

请教诸位,是不是还有什么地方我还还需要注意???

论坛徽章:
0
2 [报告]
发表于 2014-05-27 15:15 来自手机 |只看该作者
可能找到原因 晚上尝试解释一下

论坛徽章:
0
3 [报告]
发表于 2014-05-27 22:28 来自手机 |只看该作者
luakuc 发表于 2014-05-27 15:15:14
可能找到原因 晚上尝试解释一下

vfs的接口函数:
sysfs_fs_read
.......
if(buffer->needs_fill_read&&*ppos==0)
fill_read_buffer-->show注意在这里里面可能由于等待队列而休眠
.....
needs_fill_read = 0
......
store大概是
sysfs_file_write
fill_write_buffer-->store()

论坛徽章:
0
4 [报告]
发表于 2014-05-27 23:10 来自手机 |只看该作者
luakuc 发表于 2014-05-27 22:28:55

vfs的接口函数:
sysfs_fs_read
.......
if(buffer->needs_fill_read&&*ppos==0)
fill_read_buffer-->show

sysfs_file_open()
.......
bu这种情况下的ffer = kmalloc()
.......
在这里,读写进程会在open的时候会分别得到buffer(应该在这里没有说错吧)那么buffer-->needs_read_fill 在show和store里就不会相互指示。也即在读进程被写进程唤醒之后,读进程的show因为

论坛徽章:
0
5 [报告]
发表于 2014-05-27 23:16 来自手机 |只看该作者
本帖最后由 luakuc 于 2014-05-28 07:57 编辑
luakuc 发表于 2014-05-27 23:10:25

sysfs_file_open()
.......
bu这种情况下的ffer = kmalloc()
.......
在这里,读写进程会在open的时候会分

buffer-->needs_read_fill = 0 以及 *ppos !=0不会得到执行。也即读进程不会导致休眠,出现疑问<1>明天


若上面每次open的时候buffer不同,那么可以肯定的是,在同一进程不同具有读写线程时,是可以利用线程间同步实现等待资源(待证)
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP