linux驱动25:阻塞型I/O

当数据不可用时,用户可能调用read,或缓冲区满了,用户调用write,在这些情况下,驱动程序应该阻塞该操作,将其置入休眠状态直到可以执行操作。

休眠:当一个进程进入休眠状态,会被标记为一种特殊状态并从调度器运行队列移走。直到状态被修改,进程才被cpu调度。休眠的进程被搁置在一边,等待某个事件的发生。

休眠的两条规则:一、永远不要在原子上下文中进入休眠;二、当一个休眠的进程被唤醒时,必须再次检查它所等待的条件是否的确为真。

等待队列(简单休眠):

等待队列就是一个进程链表,其中包括了等待某个特定事件的所有进程。在linux中,一个等待队列通过一个等待队列头来管理,类型为wait_queue_head_t,定义在<linux/wait.h>。

初始化:

init_waitqueue_head(wait_queue_head_t *);

wait_event:

在条件为真之前,进程保持休眠,休眠的同时,也检查进程等待的条件。

wait_event(queue, condition)

wait_event_interruptible(queue, condition)  可以被信号中断;可返回一个整数值,非零值表示休眠被信号中断

wait_event_timeout(queue, condition, timeout)  等待给定的时间,超时返回0

wait_event_interruptible_timeout(queue, condition, timeout)

wake_up:

void wake_up(queue)  唤醒等待在给定queue上的所有进程

void wake_up_interruptible(queue)  只唤醒那些执行可中断休眠的进程

使用wait_event时使用wake_up,使用wait_event_interruptible使用wake_up_interruptible

#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>

#define MAX_BUF_LEN 256

static int major = 277;
static int minor = 0;
static dev_t helloNum;
struct class *helloClass = NULL;
struct device *helloDev = NULL;
wait_queue_head_t readWq, writeWq; 
static int haveData = 0;
static char helloBuf[MAX_BUF_LEN] = {0};

int hello_open(struct inode *pinode, struct file *pfile)
{
	printk("hello_open, minor:%d, major:%d\n", iminor(pinode), imajor(pinode));
	return 0;
}

int hello_release(struct inode *pinode, struct file *pfile)
{
	printk("hello_release, minor:%d, major:%d\n", iminor(pinode), imajor(pinode));	
	return 0;
}

ssize_t hello_read(struct file *filep, char __user *buf, size_t size, loff_t *pos)
{
	int copySize;

	if (size > MAX_BUF_LEN)
	{
		copySize = MAX_BUF_LEN;
	}
	else
	{
		copySize = size;
	}

	wait_event_interruptible(readWq, haveData == 1);

	if(copy_to_user(buf, helloBuf, copySize))
	{
		return -EFAULT;
	}

	printk("read:%s\n",helloBuf);
	haveData = 0;
	wake_up_interruptible(&writeWq);
	return copySize;
}

ssize_t hello_write(struct file *filep, const char __user *buf, size_t size, loff_t *pos)
{
	int copySize;

	if(size > MAX_BUF_LEN)
	{
		copySize = MAX_BUF_LEN;
	}
	else
	{
		copySize = size;
	}

	wait_event_interruptible(writeWq, haveData == 0);
	
	memset(helloBuf, 0, MAX_BUF_LEN);
	if(copy_from_user(helloBuf, buf, copySize))
	{
		return -EFAULT;
	}
	
	printk("write:%s\n",helloBuf);
	haveData = 1;
	wake_up_interruptible(&readWq);
	return copySize;
}

static struct file_operations hello_ops = {
	.open = hello_open,
	.release = hello_release,
	.read = hello_read,
	.write = hello_write,
};

static int hello_init(void)
{
	int ret = 0;
	printk("hello_init\n");

	ret = register_chrdev( major, "hello", &hello_ops);
	if(ret < 0)
	{
		printk("register_chrdev failed.\n");
		return ret;
	}

	helloClass = class_create(THIS_MODULE, "hellocls");
	if (IS_ERR(helloClass)) 
	{
		printk("class_create failed.\n");
		ret = PTR_ERR(helloClass);
		goto error_exit1;
	}

	helloNum = MKDEV(major,minor);
	printk("major:%d, minor:%d\n", MAJOR(helloNum), MINOR(helloNum));

	helloDev = device_create(helloClass, NULL, helloNum, NULL, "hello0");
	if (IS_ERR(helloDev)) 
	{
		printk("device_create failed.\n");
		ret = PTR_ERR(helloDev);
		goto error_exit2;
	}
	
	init_waitqueue_head(&readWq); 
	init_waitqueue_head(&writeWq); 
	return 0;

error_exit2:
	class_destroy(helloClass);

error_exit1:
	unregister_chrdev(major,"hello");

	return ret;
}

static void hello_exit(void)
{
	printk("hello_exit\n");
	device_destroy(helloClass, helloNum);
	class_destroy(helloClass);
	unregister_chrdev(major,"hello");
}

MODULE_LICENSE("GPL");
module_init(hello_init);
module_exit(hello_exit);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值