打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Linux驱动阻塞的实现
2011-08-19 23:56

Linux驱动阻塞的实现

应用程序:

阻塞地都取串口一个字符

非阻塞地都取串口一个字符

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(),而是亲自进行进程的状态改变和切换。

 参考:http://www.cnblogs.com/hanyan225/archive/2010/10/12/1848914.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;
}

 

 

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
linux设备驱动归纳总结(三):5.阻塞型IO实现
Linux驱动总结3- unlocked_ioctl和堵塞(waitqueue)读写函数的实现
Linux内核开发之异步通知与异步I/O(二)
休眠(sleep)
全面解析Linux内核的同步与互斥机制
wait
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服