Linux阻塞型程序设计

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值