问题:
当一个设备无法立即满足用户的读写请求时应当如何处理?
例如:调用read时没有数据可读,但以后会有。调用write时没空间可以写,但设备暂时没有准备好接收数据
这时候,驱动程序应当阻塞进程,使它进入睡眠,直到请求可以得到满足。
解决:
阻塞方式是文件读写操作的默认方式,但应用程序员可以通过使用O_NONBLOCK标志来人为的设置读写操作为非阻塞方式(在<linux/fcntl.h>中,在打开文件中指定)
非阻塞方式时,调用read、write,遇到上述问题,系统只是简单地返回-EAGAIN,而不会再阻塞进程。
代码:
/*mem设备描述结构体*/
struct mem_dev
{
char *data;
unsigned long size;
wait_queue_head_t inq; //定义了等待队列
};
/*设备驱动模块加载函数 节选*/
static int memdev_init(void)
{
/*为设备分配内存*/
for (i=0; i < MEMDEV_NR_DEVS; i++)
{
mem_devp[i].size = MEMDEV_SIZE;
mem_devp[i].data = kmalloc(MEMDEV_SIZE, GFP_KERNEL);
memset(mem_devp[i].data, 0, MEMDEV_SIZE);
/*初始化等待队列*/
init_waitqueue_head(&(mem_devp[i].inq));
}
}
while (!have_data) /* 没有数据可读,考虑为什么不用if,而用while,中断信号唤醒 */
{
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
wait_event_interruptible(dev->inq,have_data); //把调用驱动程序的应用程序阻塞在inq的等待队列中
}
/*写函数*/
static ssize_t mem_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
have_data = true; /* 有新的数据可读 */
/* 唤醒读进程 */
wake_up(&(dev->inq));
}
测试程序:
先读,让进程阻塞,再写,让进程唤醒
#include <stdio.h>
int main()
{
FILE *fp = NULL;
char Buf[128];
/*初始化Buf*/
strcpy(Buf,"memdev is char dev!");
printf("BUF: %s\n",Buf);
/*打开设备文件*/
fp = fopen("/dev/memdev0","r+");
if (fp == NULL)
{
printf("Open memdev0 Error!\n");
return -1;
}
/*清除Buf*/
strcpy(Buf,"Buf is NULL!");
printf("Read BUF1: %s\n",Buf);
/*读出数据*/
fread(Buf, sizeof(Buf), 1, fp);
/*检测结果*/
printf("Read BUF2: %s\n",Buf);
fclose(fp);
return 0;
}
#include <stdio.h>
int main()
{
FILE *fp = NULL;
char Buf[128];
/*打开设备文件*/
fp = fopen("/dev/memdev0","r+");
if (fp == NULL)
{
printf("Open Dev memdev0 Error!\n");
return -1;
}
/*写入设备*/
strcpy(Buf,"memdev is char dev!");
printf("Write BUF: %s\n",Buf);
fwrite(Buf, sizeof(Buf), 1, fp);
sleep(5);
fclose(fp);
return 0;
}