linux驱动的阻塞与非阻塞
2013-01-29 14:10
120 查看
Linux驱动阻塞的实现
from:http://blog.csdn.net/wanchres/article/details/7109198阻塞地都取串口一个字符
非阻塞地都取串口一个字符
char buf;
fd = open("/dev/ttys",O_RDWR);
.. ..
res = read(fd,&buf,1); //当串口上有输入时才返回
if(res == 1)
{
printf("%c\n",buf);
}char buf;
fd = open("/dev/ttys",O_RDWR | O_NONBLOCK);
.. ..
while( read(fd,&buf,1) !=1); //当串口上无输入也返回,所
//以要循环尝试读取串口
printf("%c\n",buf);
现在我们有了阻塞的方式读取,那么阻塞的进程因为没有获得资源会进入休眠状态,现在就要聊聊有关唤醒的事了。在Linux设备驱动中,可以使用等待队列(wait queue)来实现阻塞进程的唤醒.等待队列能够用于实现内核中的异步事件通知机制。 Linux提供了有关等待队列的操作:1)wait_queue_head_t my_queue; //定义等待队列头2) init_waitqueue_head(&my_queue); //初始化队列头如果觉得上边两步来的麻烦,可以直接使用DECLARE_WAIT_QUEUE_HEAD(name)
//定义并初始化 3) DECLARE_WAITQUEUE(name,tsk); //定义等待队列4) void fastcall add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait); void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
用于将等待队列wait添加到等待队列头指向的等待队列链表中 。
5) wait_event(queue, conditon);
wait_event_interruptible(queue, condition); //可以被信号打断
wait_event_timeout(queue, condition, timeout);
wait_event_interruptible_timeout(queue, condition, timeout); //不能被信号打断
queue:作为等待队列头的等待队列被唤醒
conditon:必须满足,否则阻塞
timeout和conditon相比,有更高优先级
6) void wake_up(wait_queue_head_t *queue);
void wake_up_interruptible(wait_queue_head_t *queue);
上述操作会唤醒以queue作为等待队列头的所有等待队列中所有属于该等待队列头的等待队列对应的进程。
7) sleep_on(wait_queue_head_t *q);
interruptible_sleep_on(wait_queue_head_t *q);
sleep_on作用是把目前进程的状态置成TASK_UNINTERRUPTIBLE,并定义一个等待队列,之后把他附属到等待队列头q,直到资源可用,q引导的等待队列被唤醒。interruptible_sleep_on作用是一样的, 只不过它把进程状态置为TASK_INTERRUPTIBLE.
这两个函数的流程是首先,定义并初始化等待队列,把进程的状态置成TASK_UNINTERRUPTIBLE或TASK_INTERRUPTIBLE,并将对待队列添加到等待队列头。
然后通过schedule(放弃CPU,调度其他进程执行。最后,当进程被其他地方唤醒,将等待队列移除等待队列头。
在Linux内核中,使用set_current_state()和__add_wait_queue()函数来实现目前进程状态的改变,直接使用current->state = TASK_UNINTERRUPTIBLE
类似的语句也是可以的。
因此我们有时也可能在许多驱动中看到,它并不调用sleep_on或interruptible_sleep_on(),而是亲自进行进程的状态改变和切换。
参考:/article/5205726.html
例一:使用 interruptible_sleep_on 函数:
static wait_queue_head_t write_wait; //定义写等待队列头
static wait_queue_head_t read_wait; //定义读等待队列头
static int __init globalfifo_init(void)
{
//...
//初始化等待队列头
init_waitqueue_head(&write_wait);
init_waitqueue_head(&read_wait);
//...
}
static ssize_t XXX_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
int ret;
while (dev->current_len == 0) //无数据可读
{
//判断是否非阻塞
if (filp->f_flags & O_NONBLOCK)
{
ret = -EAGAIN;
goto out;
}
//定义等待队列并插入读等待队列头,会阻塞
interruptible_sleep_on(&read_wait);
//被信号唤醒
if (signal_pending(current))
{
ret = - ERESTARTSYS;
goto out_2;
}
}
//....
//唤醒写等待队列
wake_up_interruptible(&write_wait);
//....
out_2:
return ret;
}
static ssize_t XXX_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
int ret;
while (dev->current_len == GLOBALFIFO_SIZE) //没有写的空间
{
//判断是否阻塞
if (filp->f_flags & O_NONBLOCK)
{
ret = -EAGAIN;
goto out;
}
//定义等待队列并插入读等待队列头,会阻塞
interruptible_sleep_on(&write_wait);
//被信号唤醒
if (signal_pending(current))
{
ret = - ERESTARTSYS;
goto out_2;
}
}
//....
//唤醒写等待队列
wake_up_interruptible(&read_wait);
//....
out_2:
return ret;
}
例二: 不使用 interruptible_sleep_on函数, 手工置进程状态和调度
struct globalfifo_dev
{
struct cdev cdev; /*cdev结构体*/
unsigned int current_len; /*fifo有效数据长度*/
unsigned char mem[GLOBALFIFO_SIZE]; /*全局内存*/
wait_queue_head_t r_wait; /*阻塞读用的等待队列头*/
wait_queue_head_t w_wait; /*阻塞写用的等待队列头*/
};
static int __init globalfifo_init(void)
{
//...
//初始化等待队列头
init_waitqueue_head(&w_wait);
init_waitqueue_head(&r_wait);
//...
}
static ssize_t XXX_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
int ret;
struct globalfifo_dev *dev = filp->private_data; //获得设备结构体指针
DECLARE_WAITQUEUE(wait, current); //定义等待队列
add_wait_queue(&dev->r_wait, &wait); //将等待队列加入等待队列头
while (dev->current_len == 0) //无数据可读
{
//判断是否非阻塞
if (filp->f_flags & O_NONBLOCK)
{
ret = -EAGAIN;
goto out;
}
__set_current_state(TASK_INTERRUPTIBLE); //改变进程状态为睡眠
schedule(); //调度其他进程执行
//被信号唤醒
if (signal_pending(current))
{
ret = - ERESTARTSYS;
goto out_2;
}
}
//....
//唤醒写等待队列
wake_up_interruptible(&w_wait);
//....
out_2:
remove_wait_queue(&dev->r_wait, &wait); //从附属的等待队列头移除
return ret;
}
static ssize_t XXX_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
int ret;
struct globalfifo_dev *dev = filp->private_data; //获得设备结构体指针
DECLARE_WAITQUEUE(wait, current); //定义等待队列
add_wait_queue(&dev->w_wait, &wait); //进入写等待队列头
while (dev->current_len == GLOBALFIFO_SIZE) //没有写的空间
{
//判断是否阻塞
if (filp->f_flags & O_NONBLOCK)
{
ret = -EAGAIN;
goto out;
}
__set_current_state(TASK_INTERRUPTIBLE); //改变进程状态为睡眠
schedule(); //调度其他进程执行
//被信号唤醒
if (signal_pending(current))
{
ret = - ERESTARTSYS;
goto out_2;
}
}
//....
//唤醒写等待队列
wake_up_interruptible(&r_wait);
//....
out_2:
remove_wait_queue(&dev->w_wait, &wait); //从附属的等待队列头移除
return ret;
}
相关文章推荐
- Linux设备驱动编程之阻塞与非阻塞
- linux设备驱动开发详解--第八章 Linux 设备驱动中的阻塞与非阻塞 I/O
- linux设备驱动之阻塞与非阻塞I/O
- 07-S3C2440驱动学习(一)嵌入式linux字符设备驱动-按键驱动程序之异步通知机制+原子操作+互斥信号量+阻塞与非阻塞+定时器去抖
- Linux设备驱动之阻塞I/O与异步通知
- Linux 设备驱动中的 I/O模型(一)—— 阻塞和非阻塞I/O
- Linux设备驱动开发详解-Note(16)---Linux 设备驱动中的阻塞与非阻塞 I/O(1)
- linux设备驱动之阻塞与非阻塞I/0
- linux字符驱动之同步互斥阻塞按键驱动
- linux驱动学习(4)--阻塞和非阻塞
- Linux设备驱动开发详解-Note(17)---Linux 设备驱动中的阻塞与非阻塞 I/O(2)
- Linux设备驱动编程之阻塞与非阻塞 2
- linux驱动-阻塞_非阻塞_异步通知
- 嵌入式linux:阻塞与非阻塞驱动
- 嵌入式linux按键驱动,同步互斥阻塞,linux进程六大状态
- linux字符设备驱动-同步互斥阻塞笔记
- Linux驱动学习8(非阻塞IO的实现--select/poll方法)
- Linux驱动之阻塞与非阻塞
- linux 资源竞争 引起的 阻塞 休眠 以及 驱动部分的工作
- Linux 内核驱动--阻塞与非阻塞机制及Poll/Select分析