- 论坛徽章:
- 0
|
本帖最后由 luakuc 于 2014-05-25 20:24 编辑
最近尝试在Linux 3.12写一个虚拟设备模块,想利用户空间导出属性文件的方式提供用户空间的访问虚拟设备接口:
虚拟设备的定义如下:- struct fifo_device{
- struct device device;
- char fifo[FIFO_BYTE];//读写缓冲区
- size_t current_data_pos; //指示缓冲区已存储数据开始位置
- size_t start_empty_pos;//指示缓冲区可存储数据开始位置
- ssize_t remaind_space;指示缓冲区剩余空间
- void *private_data;
- wait_queue_head_t r_wait;//用于当缓冲区为空时阻塞当前读进程
- wait_queue_head_t w_wait;//用于当缓冲区为满时阻塞当前写进程
- char name[1];//虚拟设备名字
- } fifo_dev;
复制代码 为fifo_dev创建属性文件DEVICE_ATTR_RW("MEM" ,其show()/store()定义如下:- static ssize_t MEM_device_show(struct device*dev,struct device_attribute *attr,char *buf)
- {
- struct fifo_device *pfifo_dev = to_fifo_device(dev);
- static int i=0;
- DECLARE_WAITQUEUE(wait,current);//澹版槑绛夊緟闃熷垪(涓?殑闃熷垪鎴愬憳)
- add_wait_queue(&pfifo_dev->r_wait,&wait);//为读等待队列头添加等待队列
-
- if(unlikely(pfifo_dev->remaind_space >= FIFO_BYTE))
- //while(unlikely(pfifo_dev->remaind_space == FIFO_BYTE))
- {
- __set_current_state(TASK_INTERRUPTIBLE);
- schedule();//在这里由于缓冲区为空,会发生相应读进程调度
- printk(KERN_EMERG"show : %d remaind_space: %d \n",i++,pfifo_dev->remaind_space);
- }
- {
- int i=0;
- int ret=FIFO_BYTE- pfifo_dev->remaind_space;
- for(;i<ret;i++)
- {
- buf[i] = pfifo_dev->fifo[pfifo_dev->current_data_pos];
- pfifo_dev->current_data_pos = (pfifo_dev->current_data_pos+1)%FIFO_BYTE;
- }
- pfifo_dev->remaind_space=pfifo_dev->remaind_space+ret;
-
-
- remove_wait_queue(&pfifo_dev->r_wait,&wait);
- wake_up_interruptible(&pfifo_dev->w_wait);
- __set_current_state(TASK_RUNNING);
- printk(KERN_EMERG"ret : %d\n",ret);
- return ret;
- }
- }
复制代码- static ssize_t MEM_device_store(struct device *pdev,struct device_attribute *attr,const char *buf,size_t count)
- {
- struct fifo_device *pfifo_dev = to_fifo_device(pdev);
- DECLARE_WAITQUEUE(wait,current);
-
- add_wait_queue(&pfifo_dev->w_wait,&wait);
- if(unlikely(pfifo_dev->remaind_space==0))
- {
- __set_current_state(TASK_INTERRUPTIBLE);
- schedule();
- }
- {
- ssize_t ret =0;
- int i=0;
- if(likely(pfifo_dev->remaind_space >= count))
- ret = count;
- else
- ret = pfifo_dev->remaind_space;
-
-
- for(;i<ret;i++)
- {
- pfifo_dev->fifo[pfifo_dev->start_empty_pos]=buf[i];
- pfifo_dev->start_empty_pos= (pfifo_dev->start_empty_pos+1)%FIFO_BYTE;
- }
- pfifo_dev->remaind_space = pfifo_dev->remaind_space - ret;
-
-
- remove_wait_queue(&pfifo_dev->w_wait,&wait);
- wake_up_interruptible(&pfifo_dev->r_wait);
- __set_current_state(TASK_RUNNING);
- return ret;
- }
- }
复制代码 用户空间访问:- int main(int argc,char **argv)
- {
- ssize_t bytes;
- char buf[30];
- int fd = open("/sys/devices/fifo-IPC-bus/mini_fifo/fifo-MEM",O_RDWR);
- if(fd < 0)
- {
- perror("open");
- return fd;
- }
- while(*argv[1]=='r')
- {
- memset(buf,0,30);
- bytes = read(fd,buf,10);
- printf("len: %d read: %s\n",bytes,buf);
- sleep(1);
- }
- while(*argv[1]=='w')
- {
-
- bytes= write(fd,"--write--",9);
- if(bytes<0)
- {
- perror("write");
- return -errno;
- }
- sleep(1);
- }
- return 0;
- }
复制代码 运行的情形:
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)
.......
请教诸位,是不是还有什么地方我还还需要注意??? |
|