linux设备驱动笔记--阻塞与非阻塞I/O

阻塞I/O

阻塞操作是指在执行设备操作时,若不能获得资源,则挂起进程直到满足可操作的条件后再进行操作。被挂起的进程进入睡眠状态,被从调度器的运行队列移走,直到等待的条件被满足。

非阻塞I/O

而非阻塞操作的进程在不能进行设备操作时,并不挂起,它要么放弃,要么不停地查询,直至可以进行操作为止。

等待队列

等待队列以队列为基础数据结构,与进程调度机制紧密结合,可以用来实现阻塞进程的唤醒。

使用方法

定义等待队列头

wait_queue_head_t my_queue;

初始化等待队列头

init_waitqueue_head(&my_queue);
还可以用宏定义
DECLARE_WAIT_QUEUE_HEAD (name);

定义等待队列元素

DECLARE_WAITQUEUE(name, tsk);tsk一般为current,指当前进程。

添加/移除等待队列

void add_wait_queue(wait_queue_head_t *q,wait_queue_t *wait);
void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);

等待事件

wait_event(queue, condition)
wait_event_interruptible(queue, condition) //可以被信号打断
wait_event_timeout(queue, condition, timeout)
wait_event_interruptible_timeout(queue, condition, timeout)
queue作为等待队列头部的队列被唤醒,而且第2个参数condition必须满足,否则继续阻塞。

唤醒队列

void wake_up(wait_queue_head_t *queue);
void wake_up_interruptible(wait_queue_head_t *queue);
唤醒以queue作为等待队列头部的队列中所有的进程。

在等待队列上睡眠

sleep_on(wait_queue_head_t *q );
interruptible_sleep_on(wait_queue_head_t *q );
这两个函数可以把进程状态设置为TASK_UNINTERRUPTIBLE。

驱动使用等待队列模板

static ssize_t xxx_write(struct file *file, const char *buffer, size_t count,loff_t *ppos)
{
	DECLARE_WAITQUEUE(wait, current); 
	add_wait_queue(&xxx_wait, &wait); 
	do {
		avail = device_writable(...);
		if (avail < 0) {
			if (file->f_flags &O_NONBLOCK) {
				ret = -EAGAIN;
				goto out;
		}
		__set_current_state(TASK_INTERRUPTIBLE);
		schedule(); /* 调度其他进程执行 */
		if (signal_pending(current)) { /* 如果是因为信号唤醒 */
				ret = -ERESTARTSYS;
				goto out;
			}
		}
	} while (avail < 0);
		/* 写设备缓冲区 */
	device_write(...)
	out:
	remove_wait_queue(&xxx_wait, &wait); /* 将元素移出 xxx_wait 指引的队列 */
	set_current_state(TASK_RUNNING); /* 设置进程状态为 TASK_RUNNING */
	return ret;
}

轮询操作

使用非阻塞I/O的应用程序通常会使用select()和poll()系统调用查询是否可对设备进行无阻塞的访问。select()和poll()系统调用最终会使设备驱动中的poll()函数被执行。

select函数

int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,struct timeval *timeout);
FD_ZERO(fd_set *set)	//清除文件描述符集合
FD_SET(int fd,fd_set *set)	//将一个文件描述符加入文件描述符集合中
FD_CLR(int fd,fd_set *set)	//将一个文件描述符从文件描述符集合中清除
FD_ISSET(int fd,fd_set *set)	//判断文件描述符是否被置位

poll函数

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

设备驱动中的poll函数

unsigned int(*poll)(struct file * filp, struct poll_table* wait);

1)对可能引起设备文件状态变化的等待队列调用poll_wait()函数,将对应的等待队列头部添加到poll_table中。
2)返回表示是否能对设备进行无阻塞读、写访问的掩码。

poll_wait

void poll_wait(struct file *filp, wait_queue_heat_t *queue, poll_table * wait);

作用是将当前进程添加到指定的等待列表中,以便在设备就绪时通知进程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值