Linux阻塞型程序设计

    xiaoxiao2021-03-25  75

    Linux阻塞型程序设计

    等待队列

             在Linux驱动程序设计中,可以使用等待队列来实现进程的阻塞,等待队列可以看做保存进程的容器,在阻塞进程时,将进程放入等待队列,当唤醒进程时,从等待队列中取出进程。

    Linux2.6内核提供了如下关于等待队列的操作

    1、  定义等待队列

    wait_queue_head_t my_queue

    2、  初始化等待队列

    init_waitqueue_head(&my_queue)

    3、  定义并初始化等待队列

    DECLARE_WAIT_QUEUE_HEAD(my_queue)

    4、  有条件睡眠

    wait_event(queue,condition)

    当condition为真时,立即返回;否则让进程进入TASK_UNINTERRUPTIBLE模式的睡眠

    wait_event_interruptible(queue,condition)

    当condition为真时,立即返回;否则让进程进入TASK_INTERRUPTIBLE模式的睡眠

    int wait_event_killable(wait_queue_t queue, condition)

    当condition为真时,立即返回;否则让进程进入TASK_KILLABLE模式的睡眠

    5、  无条件睡眠

    sleep_on(wait_queue_head_t *q)           

    让进程进入不可中断的睡眠

    interruptible_sleep_on(wait_queue_head_t*q)

    让进程进入可中断的睡眠

    6、  从等待队列中唤醒进程

    wake_up(wait_queue_t *q)

    可以唤醒所有模式的等待队列

     wake_up_interruptible(wait_queue_t*q)

    唤醒TASK_INTERRUPTIBLE模式的进程

    代码示例

    #include <linux/module.h>

    #include <linux/types.h>

    #include <linux/fs.h>

    #include <linux/errno.h>

    #include <linux/mm.h>

    #include <linux/sched.h>

    #include <linux/init.h>

    #include <linux/cdev.h>

    #include <asm/io.h>

    #include <asm/system.h>

    #include <asm/uaccess.h>

     

    #include "memdev.h"

     

    static mem_major = MEMDEV_MAJOR;

    bool have_data = false; /*表明设备有足够数据可供读*/

     

    module_param(mem_major, int, S_IRUGO);

     

    struct mem_dev *mem_devp; /*设备结构体指针*/

     

    struct cdev cdev;

     

    /*文件打开函数*/

    int mem_open(struct inode *inode, structfile *filp)

    {

       struct mem_dev *dev;

       

       /*获取次设备号*/

       int num = MINOR(inode->i_rdev);

     

       if (num >= MEMDEV_NR_DEVS)

               return -ENODEV;

       dev = &mem_devp[num];

       

       /*将设备描述结构指针赋值给文件私有数据指针*/

       filp->private_data = dev;

       

       return 0;

    }

     

    /*文件释放函数*/

    int mem_release(struct inode *inode, structfile *filp)

    {

     return 0;

    }

     

    /*读函数*/

    static ssize_t mem_read(struct file *filp,char __user *buf, size_t size, loff_t *ppos)

    {

     unsigned long p =  *ppos;

     unsigned int count = size;

      intret = 0;

     struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/

     

      /*判断读位置是否有效*/

      if(p >= MEMDEV_SIZE)

       return 0;

      if(count > MEMDEV_SIZE - p)

       count = MEMDEV_SIZE - p;

       

    while (!have_data) /* 没有数据可读,考虑为什么不用if,而用while,中断信号唤醒 */

    {

           if (filp->f_flags & O_NONBLOCK)

               return -EAGAIN;

            

             wait_event_interruptible(dev->inq,have_data);

    }

     

     

      /*读数据到用户空间*/

      if(copy_to_user(buf, (void*)(dev->data + p), count))

      {

       ret =  - EFAULT;

      }

     else

      {

       *ppos += count;

       ret = count;

      

       printk(KERN_INFO "read %d bytes(s) from %d\n", count, p);

      }

     

     have_data = false; /* 表明不再有数据可读 */

     return ret;

    }

     

    /*写函数*/

    static ssize_t mem_write(struct file *filp,const char __user *buf, size_t size, loff_t *ppos)

    {

     unsigned long p =  *ppos;

     unsigned int count = size;

      intret = 0;

     struct mem_dev *dev = filp->private_data; /*获得设备结构体指针*/

     

      /*分析和获取有效的写长度*/

      if(p >= MEMDEV_SIZE)

       return 0;

      if(count > MEMDEV_SIZE - p)

       count = MEMDEV_SIZE - p;

       

      /*从用户空间写入数据*/

      if(copy_from_user(dev->data + p, buf, count))

       ret =  - EFAULT;

     else

      {

       *ppos += count;

       ret = count;

       

       printk(KERN_INFO "written %d bytes(s) from %d\n", count, p);

      }

     

     have_data = true; /* 有新的数据可读 */

       

       /* 唤醒读进程 */

       wake_up(&(dev->inq));

     

     return ret;

    }

     

    /* seek文件定位函数 */

    static loff_t mem_llseek(struct file *filp,loff_t offset, int whence)

    {

       loff_t newpos;

     

       switch(whence) {

         case 0: /* SEEK_SET */

           newpos = offset;

           break;

     

         case 1: /* SEEK_CUR */

           newpos = filp->f_pos + offset;

           break;

     

         case 2: /* SEEK_END */

           newpos = MEMDEV_SIZE -1 + offset;

           break;

     

         default: /* can't happen */

           return -EINVAL;

        }

       if ((newpos<0) || (newpos>MEMDEV_SIZE))

                 return -EINVAL;

                

       filp->f_pos = newpos;

       return newpos;

     

    }

     

    /*文件操作结构体*/

    static const struct file_operationsmem_fops =

    {

     .owner = THIS_MODULE,

     .llseek = mem_llseek,

     .read = mem_read,

     .write = mem_write,

     .open = mem_open,

     .release = mem_release,

    };

     

    /*设备驱动模块加载函数*/

    static int memdev_init(void)

    {

      intresult;

      inti;

     

     dev_t devno = MKDEV(mem_major, 0);

     

      /* 静态申请设备号*/

      if(mem_major)

       result = register_chrdev_region(devno, 2, "memdev");

     else  /* 动态分配设备号 */

      {

       result = alloc_chrdev_region(&devno, 0, 2, "memdev");

       mem_major = MAJOR(devno);

     } 

     

      if(result < 0)

       return result;

     

      /*初始化cdev结构*/

     cdev_init(&cdev, &mem_fops);

     cdev.owner = THIS_MODULE;

     cdev.ops = &mem_fops;

     

      /* 注册字符设备 */

     cdev_add(&cdev, MKDEV(mem_major, 0), MEMDEV_NR_DEVS);

      

      /* 为设备描述结构分配内存*/

     mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev), GFP_KERNEL);

      if(!mem_devp)    /*申请失败*/

      {

       result =  - ENOMEM;

       goto fail_malloc;

      }

     memset(mem_devp, 0, sizeof(struct mem_dev));

     

      /*为设备分配内存*/

      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));

      }

      

     return 0;

     

     fail_malloc:

     unregister_chrdev_region(devno, 1);

     

     return result;

    }

     

    /*模块卸载函数*/

    static void memdev_exit(void)

    {

     cdev_del(&cdev);   /*注销设备*/

     kfree(mem_devp);     /*释放设备结构体内存*/

     unregister_chrdev_region(MKDEV(mem_major, 0), 2); /*释放设备号*/

    }

     

    MODULE_AUTHOR("David Xie");

    MODULE_LICENSE("GPL");

     

    module_init(memdev_init);

    module_exit(memdev_exit);

    转载请注明原文地址: https://ju.6miu.com/read-25668.html

    最新回复(0)