对LDD3前七章的一个小节

最近又重读了LDD3(Linux Device Driver, 3rd Edition) , 对LDD的前面一部分, 即如何写一个字符设备进行了一个小结. 希望能够对初学者有用.
对于下面这一段代码, 演示了如何创建一个字符设备, 涉及到如下知识点:
1. 如何创建字符设备, 2. 使用信号量进行互斥, 3. 创建等待队列, 4. 设计一个定时器
分别包括了LDD3中第二, 三, 五, 六, 七章中的小部分内容.

下面对代码进行一些简要的说明.
1. 首先是char_init函数, 该函数完成了对字符设备的注册功能. 如果注册成功, 则输出字符设备的主设备号. 另一方面, 还完成了对信号量的初始化, 以及对等待队列的初始化. 因此, 当insmod结束之后, 正常情况下就完成了对字符设备的注册等一系列的初始化动作了.
2. 然后再看打开设备的操作char_open. 当你在程序中调用open时, 就会去调用这个函数. 这个函数中有一个try_module_get(THIS_MODULE);它表示当前这个模块处于使用之中. 此时通过lsmod可以看到used一栏中不为0. 如果此时调用rmmod去卸载这个模块, 则会出错. 提示当前模块正在使用中, 不能被卸载.
3. 打开之后就是去读这个字符设备. 此时在程序中调用read时, 就会去调用模块中的char_read这个函数. 这个函数首先调用down_interruptible函数, 进行锁定. 这样, 只有一个进程能够运行char_read这个函数. 然后再是初始化定时器. 时间为5秒钟. 之后再去调用my_read这个函数. 在这个函数中检查flag是否为0, 如果为0了, 则将当前进程放到等待队列中去, 等待其它的进程将自己唤醒. 当过了五秒钟之后, 由于定时器的作用, 调用了my_handler这个函数, 它一方面将flag的值设为1, 另一方面调用wake_up_interruptible将该等待队列上的进程唤醒. 因此, 此时my_read函数又开始继续往下面执行了. 剩下的工作就是删除定时器, 并将值传递给用户态的程序.
4. 最后用户态的程序调用close()时则关于了这个设备, 此时调用了module_put(THIS_MODULE); 与之前的try_module_get相对应, 即表示当前模块没有被占用, 此时可以调用rmmod将模块卸载掉.
下面就编写一个用户态的程序来试验这个字符设备
test.c

最后是实验步骤.
1. 首先编写Makefile.

2. 在当前目录下使用make进行编译, 然后再使用make install将模块加载进内核. 此时使用dmesg可以查看系统给该字符设备分配的设备号是多少. 假如为253. 则创建该字符设备. mknod /dev/chardev c 253 0
3. 编译test.c, 然后运行, 在运行时, 其等待了5秒钟, 即为等待定时器的那个过程. 最后得到输出的结果. 此时再通过dmesg命令可以查看模块中函数的调用过程.
4. 实验完之后调用make uninstall卸载该模块, 并调用make clean清除一些临时文件.
下面的结果为我在自己的机器上运行后通过dmesg打印出来的结果.

    另外, 如果test程序在等待时执行rmmod chardev时会提示设备正在忙. 就是前面的try_module_get()所引起的. 同时如果在两个终端运行test这个程序, 则第二个test程序会阻塞, 并在第一个test程序结束之后才得以执行. 防止了并发.
    上面对字符设备的注册, 信号量, 等待队列以及定时器的使用作了一个简单的介绍, 当然, LDD3前七章的内容远不止这些. 还有很多需要去参透的地方. 
    我以前第一次看LDD的时候, 对里面的很多东西也不理解, 第一次看完之后完全不知道自己看了什么. 所以写这篇文章希望能对刚开始看LDD的朋友有一点用处.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值