`
mfcai
  • 浏览: 404713 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

内核等待机制学习(一)

 
阅读更多
假设我们在 kernel有一个 buffer,应用可以通过read,write等系统调用来读取或写数据到这个 buffer 里。
如果有一个 app 写数据到 buffer 时,此时 buffer 已经满了。那么如何去处理这种情形呢 ?
第一种,传给 user 一个错误讯息,说 buffer 已经满了,不能再写入。
第二种,将 user 的要求 block 住, 等app将 buffer 数据读走,留出空位时,再让 user 写入资料。
如果采用第二种,我们就要用到wait_queue了。wait_queue 是 kernel 所提供的.


假设这里这个驱动例子将维护一个大小为20的buffer,并加入read和write功能:
当 buffer 中没有数据时,read() 就会被 block 住,直到有数据写入为止。
而当 write buffer 时,如果调用 write() 时,空间已满或写入的数据比 buffer 大时,就会被 block 住,
直到有A数据读出来为止。在 write buffer 的程序代码中,我们使用 wait_queue 来做到 block IO 的功能。


今天主要先建立linux驱动程序的框架
一、linux驱动程序框架
第1步:建立Linux驱动程序框架(装载和卸载Linux驱动)
     任何类型的程序都有一个基本的结构,例如,C语言需要有一个入口函数main。Linux驱动程序也不例外。Linux内核在使用驱动时首先需要装载驱动。
在装载过程中需要进行一些初始化工作,例如,建立设备文件,分配内存地址空间等。当Linux系统退出时需要卸载Linux驱动,在卸载的过程中需要释放
由Linux驱动占用的资源,例如,删除设备文件、释放内存地址空间等。在Linux驱动程序中需要提供两个函数来分别处理驱动初始化和退出的工作。这两个函数分别用module_init和module_exit宏指定。
Linux驱动程序一般都都需要指定这两个函数,因此包含这两个函数以及指定这两个函数的两个宏的C程序文件也可看作是Linux驱动的骨架。

第2步:注册和注销设备文件
      任何一个Linux驱动都需要有一个设备文件。否则应用程序将无法与驱动程序交互。建立设备文件的工作一般在第1步编写的处理Linux初始化工作的函数
中完成。删除设备文件一般在第1步编写的处理Linux退出工作的函数中完成。

第3步:指定与驱动相关的信息
     驱动程序是自描述的。例如,可以通过modinfo命令获取驱动程序的作者姓名、使用的开源协议、别名、驱动描述等信息。这些信息都需要在驱动源代
码中指定。通过 MODULE_AUTHOR、MODULE_LICENSE 、MODULE_ALIAS 、MODULE_DESCRIPTION等宏可以指定与驱动相关的信息。

第4步:定义能在设备上进行的操作
struct file_operations,函数指针的集合,定义能在设备上进行的操作。
当执行exampledev_init时,它将调用内核函数 register_chrdev,
把驱动程序的基本入口点指针存放在内核的字符设备地址表中,在用户进程对该设备执行系统调用时提供入口地址


二.模块    
linux中的驱动程序,是以模块的形式编写的。模块的加载方式有两种:
1)用insmod命令手工加载模块。
2)一种直接编译进内核。
模块的卸载通过rmmod命令来删除模块。
模块的实现机制:
对于每一个内核模块来说,必定包含两个函数:卸载函数和初始化函数
1、将模块插入到内核时的初始化工作
1)准备struct file_operations结构体;
2)使用register_chrdev_region注册,申请设备号;
3)使用cdev_init初始化struct cdev结构体,建立cdev和file_operation之间的连接;
4)使用cdev_add增加struct cdev结构体;
5)出错处理。
1.2 从内核中删除模块时的清理工作
1)使用cdev_del删除struct cdev结构体;
2)释放其他申请的资源;
3)使用unregister_chrdev_region释放设备号。


三、设备注册
在linux2.6内核中,字符设备使用struct cdev结构来描述。
本文中,字符设备的注册分为两个步骤:
1、初始化cdev结构
   struct cdev的初始化使用cdev_init来完成
   syntax:
   void cdev_init(struct cdev *cdev,struct file_operations *fops)
   参数:
   cdev:待初始化的cdev结构
   fops:设备对应的操作函数集
2、添加cdev
   struct cdev的注册使用cdev_add来完成
   syntax:
   int cdev_add(struct cdev *p,dev_t dev,unsigned count)
   参数:
   p:要注册的字符设备
   dev:设备号,驱动程序对应的主设备号
   count:添加的设备个数


以下是代码
globalfifo.c
#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>


#define GLOBALFIFO_SIZE 20
#define GLOBALFIFO_MAJOR 150    
static int globalfifo_major = GLOBALFIFO_MAJOR;


struct globalfifo_dev                                     
{                                                        
struct cdev cdev;                       
  unsigned int current_len;    
  unsigned char mem[GLOBALFIFO_SIZE];                
  
};


struct globalfifo_dev *globalfifo_devp;
int globalfifo_open(struct inode *inode, struct file *filp)
{
filp->private_data = globalfifo_devp;
return 0;
}


int globalfifo_release(struct inode *inode, struct file *filp)
{
return 0;
}


static const struct file_operations globalfifo_fops =
{
  .owner = THIS_MODULE,
  .open = globalfifo_open,
  .release = globalfifo_release,
};


static void globalfifo_setup_cdev(struct globalfifo_dev *dev, int index)
{
int err, devno = MKDEV(globalfifo_major, index);
cdev_init(&dev->cdev, &globalfifo_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &globalfifo_fops;
err = cdev_add(&dev->cdev, devno, 1);
if(err)
printk(KERN_NOTICE "Error %d adding LED%d", err, index);
}


int globalfifo_init(void)
{
  int ret;
  dev_t devno = MKDEV(globalfifo_major, 0);
        ret = register_chrdev_region(devno, 1, "globalfifo");
 
  if(ret < 0)
    return ret;
  globalfifo_devp = kmalloc(sizeof(struct globalfifo_dev), GFP_KERNEL);
  if(!globalfifo_devp) 
  {
    ret =  - ENOMEM;
    goto fail_malloc;
  }
memset(globalfifo_devp, 0, sizeof(struct globalfifo_dev));
globalfifo_setup_cdev(globalfifo_devp, 0);
return 0;
fail_malloc: unregister_chrdev_region(devno, 1);
  return ret;
}
void globalfifo_exit(void)
{
cdev_del(&globalfifo_devp->cdev);  
kfree(globalfifo_devp);    
unregister_chrdev_region(MKDEV(globalfifo_major, 0), 1);
}
MODULE_LICENSE("Dual BSD/GPL");
module_init(globalfifo_init);
module_exit(globalfifo_exit);




本文欢迎转载,转载请注明出处与作者
出处:http://blog.sina.com.cn/staratsky
作者:流星
0
0
分享到:
评论

相关推荐

    天书夜读:从汇编语言到Windows内核编程(完整版一)

     14.2.3 在内核中等待监控进程的响应 210  14.3 开发监控进程 216  14.4 本软件进一步展望 218  第15章 Rootkit与HIPS 220  15.1 Rootkit为何很重要 222  15.2 Rootkit如何逃过检测 224  15.3 HIPS如何检测...

    Linux2.6内核标准教程(共计8-- 第1个)

    第1章 Linux内核学习基础 1 1.1 为什么研究Linux内核 2 1.1.1 Linux的历史来源 2 1.1.2 Linux的发展现状 3 1.1.3 Linux的前景展望 3 1.2 选择什么版本进行研究 3 1.3 内核基本结构 4 1.3.1 内核在...

    Linux2.6内核标准教程(共计8--第6个)

    第1章 Linux内核学习基础 1 1.1 为什么研究Linux内核 2 1.1.1 Linux的历史来源 2 1.1.2 Linux的发展现状 3 1.1.3 Linux的前景展望 3 1.2 选择什么版本进行研究 3 1.3 内核基本结构 4 1.3.1 内核在...

    天书夜读:从汇编语言到Windows内核编程(完整版 二)

     14.2.3 在内核中等待监控进程的响应 210  14.3 开发监控进程 216  14.4 本软件进一步展望 218  第15章 Rootkit与HIPS 220  15.1 Rootkit为何很重要 222  15.2 Rootkit如何逃过检测 224  15.3 HIPS如何检测...

    Linux2.6内核标准教程(共计8--第8个)

    第1章 Linux内核学习基础 1 1.1 为什么研究Linux内核 2 1.1.1 Linux的历史来源 2 1.1.2 Linux的发展现状 3 1.1.3 Linux的前景展望 3 1.2 选择什么版本进行研究 3 1.3 内核基本结构 4 1.3.1 内核在...

    Linux2.6内核标准教程(共计8--第3个)

    第1章 Linux内核学习基础 1 1.1 为什么研究Linux内核 2 1.1.1 Linux的历史来源 2 1.1.2 Linux的发展现状 3 1.1.3 Linux的前景展望 3 1.2 选择什么版本进行研究 3 1.3 内核基本结构 4 1.3.1 内核在...

    Linux2.6内核标准教程(共计8--第7个)

    第1章 Linux内核学习基础 1 1.1 为什么研究Linux内核 2 1.1.1 Linux的历史来源 2 1.1.2 Linux的发展现状 3 1.1.3 Linux的前景展望 3 1.2 选择什么版本进行研究 3 1.3 内核基本结构 4 1.3.1 内核在...

    操作系统课程实验.rar

    在本实验中将学习模块的基本概念、原理及实现技术,然后利 用内核模块编程访问进程的基本信息,从而加深对进程概念的理解、对模块编程技术的掌 握。 内容要求 (1) 设计一个模块,要求列出系统中所有内核线程的程序...

    天书夜谈:从汇编语言到Windows内核编程

     14.2.3 在内核中等待监控进程的响应 210  14.3 开发监控进程 216  14.4 本软件进一步展望 218  第15章 Rootkit与HIPS 220  15.1 Rootkit为何很重要 222  15.2 Rootkit如何逃过检测 224  15.3 HIPS如何检测...

    Linux2.6内核标准教程(共计8--第4个)

    第1章 Linux内核学习基础 1 1.1 为什么研究Linux内核 2 1.1.1 Linux的历史来源 2 1.1.2 Linux的发展现状 3 1.1.3 Linux的前景展望 3 1.2 选择什么版本进行研究 3 1.3 内核基本结构 4 1.3.1 内核在...

    Linux2.6内核标准教程(共计8--第2个)

    第1章 Linux内核学习基础 1 1.1 为什么研究Linux内核 2 1.1.1 Linux的历史来源 2 1.1.2 Linux的发展现状 3 1.1.3 Linux的前景展望 3 1.2 选择什么版本进行研究 3 1.3 内核基本结构 4 1.3.1 内核在...

    Linux2.6内核标准教程(共计8--第5个)

    第1章 Linux内核学习基础 1 1.1 为什么研究Linux内核 2 1.1.1 Linux的历史来源 2 1.1.2 Linux的发展现状 3 1.1.3 Linux的前景展望 3 1.2 选择什么版本进行研究 3 1.3 内核基本结构 4 1.3.1 内核在...

    操作系统课程设计-同步机制-读者写者

    CreateEvent() 在内核中创建一个新的事件对象。此函数允许有安全性设置、手工还是自动重置的标志以及初始时已接受还是未接受信号状态的标志 OpenEvent() 创建对已经存在的事件对象的引用。此API函数需要名称、继承...

    一个进程池的服务器程序

    一个进程池的服务器程序 下面做了非常简单的http服务器,该服务器只能接收Get请求。 流程大概如下: 1,父进程listen,创建pipe(下面所有父子进程之间的通信都用该pipe) 2,父进程预fork n个子进程 3,各个子...

    windows驱动开发技术详解-part2

    这是书的光盘。共分为两个部分,这是第一部分。 本书由浅入深、循序渐进地... 本章总结了在内核模式下的四种等待方法,读者可以利用这些方法灵活地用在自己的驱动程序中。最 后本章还介绍了如何对IRP的超时情况进行...

    Windows驱动开发技术详解的光盘-part1

     本章总结了在内核模式下的四种等待方法,读者可以利用这些方法灵活地用在自己的驱动程序中。最后本章还介绍了如何对IRP的超时情况进行处理。  10.1 定时器实现方式一  10.1.1 I/O定时器  10.1.2 示例代码  ...

    功能强大的IOCP Socket Servre模块例程源码

    一、声明 版权声明: 1、通讯模块代码版权归作者所有; 2、未经许可不得全部或部分用于任何项目开发; 3、未经许可不得部分修改后再利用源码。 免责声明: 1、 由于设计缺陷或其它Bug造成的后果,作者不承担责任; ...

    linux 系统源码全面剖析

    等待队列 内存管理 物理内存管理 伙伴分配算法 Slab分配算法 虚拟内存管理 mmap完全剖析 内存交换 vmalloc原理与实现 写时复制 零拷贝技术 虚拟内存空间管理 中断机制 硬件相关 中断处理 系统调用 文件系统 虚拟文件...

    新版Android开发教程.rar

    Android 是一个专门针对移动设备的软件集,它包括一个操作系统,中间件和一些重要的应用程序。 Beta 版 的 Android SDK 提供了在 Android 平台上使用 JaVa 语言进行 Android 应用开发必须的工具和 API 接口。 特性 ...

    网络安全员题库答案解析.xls

    14 下面哪个不是LVS的集群组成部分 IPVS内核模块 IPVSserver 15 下面那项不属于集群系统的主要优点 高兼容性 高可用性 16 Nginx中upsteam模块的什么机制能够将某个IP的请求定向到同一台后端服务器上 ip_hash ip_...

Global site tag (gtag.js) - Google Analytics