Linux OS内核 作业三:设备驱动与读写信号量
2017-02-28 20:38
375 查看
实验题目:
http://gauss.ececs.uc.edu/Courses/c4029/labs/lab6.html
大致内容就是写一个设备驱动,实现“开关读写”。然后加入读写信号量,实现互斥访问:可以多个人同时读,但只要有一个人写,那么其他人就不能读和写。
安装
卸载
注:
1. 关于显示运行时间的问题,可以参考我的另一篇博文:http://blog.csdn.net/u013806583/article/details/58127067
2. 关于如何编译、加载和卸载内核模块,可以参考《Linux OS内核 作业一》的方法:http://blog.csdn.net/u013806583/article/details/58604378
编译
使用
按照第一部分方法,安装内核模块
编译本源码app.c
运行
结果:可以看到当程序在写时,读操作要等待。当写操作完成时,两个读操作几乎同时进行。
系列博客:
相信当你需要其中一个的时候,也一定需要剩下的两个
Linux OS内核 作业一:kthread和workqueue
Linux OS内核 作业二:多线程访问
Linux OS内核 作业三:设备驱动与读写信号量
http://gauss.ececs.uc.edu/Courses/c4029/labs/lab6.html
大致内容就是写一个设备驱动,实现“开关读写”。然后加入读写信号量,实现互斥访问:可以多个人同时读,但只要有一个人写,那么其他人就不能读和写。
编写内核模块:实现对设备的访问
//"RW_module.c" #include <linux/kernel.h> #include <linux/module.h> #include <linux/timer.h> #include <linux/fs.h> #include <linux/sched.h> #include <linux/rwsem.h> #include <linux/cdev.h> #include <linux/wait.h> #include <linux/sched.h> #include <linux/rwsem.h> #include <asm/uaccess.h> #include <linux/wait.h> MODULE_LICENSE("GPL"); #define DEVICE_NAME "guan_device" static int MAX_BUF_LEN=1024; static char drv_buf[1024]; //方法声明,在下面具体实现 ssize_t read(struct file *filp, char *buff, size_t count, loff_t *offp); ssize_t write(struct file *filp, const char *buff, size_t count, loff_t *offp); int open(struct inode *inode, struct file *filp); int release(struct inode *inode, struct file *filp); struct file_operations fops = { .read = read, .write = write, .open = open, .release = release }; struct cdev *kernel_cdev; /* declared globally */ dev_t dev_no; /* declared globally */ int Major; /* declared globally */ //定义信号量 struct rw_semaphore sem_guan; wait_queue_head_t queue; /** struct rw_semaphore sem_guan = { long count; raw_spinlock_t wait_lock; struct list_head wait_list; }; void init_rwsem(struct rw_semaphore); //Initialize the semaphore void down_read(struct rw_semaphore *sem); //Hold semaphore for reading, sleep if not available void up_read(struct rw_semaphore *sem); //Release semaphore for reading void down_write(struct rw_semaphore *sem); //Hold semaphore for writing, sleep if not available void down_write_trylock(struct rw_semaphore *sem); //Hold semaphore for writing, error if not available void up_write(struct rw_semaphore *sem); //Release semaphore for writing */ //=========================================================================== //用于延迟等待,模拟耗时操作 void dely_guan(void) { //delay for 20 seconds like this: wait_event_timeout(queue, 0, 20*HZ); } //======================================== /** *加载内核模块时 */ int init_module( void ) { int ret; kernel_cdev = cdev_alloc(); kernel_cdev->ops = &fops; ret = alloc_chrdev_region(&dev_no , 0, 1, DEVICE_NAME);//动态分配设备编号,DEVICE_NAME //add (register) the character device interface to (with) the operating system int dev; Major = MAJOR(dev_no); dev = MKDEV(Major,0); ret = cdev_add(kernel_cdev, dev, 1); //初始化信号量 init_rwsem(&sem_guan); init_waitqueue_head(&queue); return 0; } /** * */ void cleanup_module( void ) { //注销设备 cdev_del(kernel_cdev); unregister_chrdev_region(dev_no, 1); unregister_chrdev(Major, DEVICE_NAME); printk(KERN_INFO "ReadWrite module uninstalling\n"); return; } //===============以下是“开关读写”操作的具体实现============================================= ssize_t read(struct file *filp, char *buff, size_t count, loff_t *offp) { //加锁 down_read(&sem_guan); //把数据传到“用户空间”,即“读” copy_to_user(buff, drv_buf,count); printk(KERN_INFO "user read data from driver:\t%s\n",buff); //模拟等待 dely_guan(); //释放 up_read(&sem_guan); return count; } ssize_t write(struct file *filp, const char *buff, size_t count, loff_t *offp) { //加锁 down_write(&sem_guan); //把数据从“用户空间”传到“内核空间”,即“写”到设备上 copy_from_user(drv_buf , buff, count); printk(KERN_INFO "user write data to driver:\t%s\n",buff); dely_guan(); //释放锁 up_write(&sem_guan); return count; } int open(struct inode *inode, struct file *filp) { printk(KERN_INFO "open device"); return 0; } int release(struct inode *inode, struct file *filp) { printk(KERN_INFO "release device"); return 0; }
安装
sudo insmod RW_module.ko #这里是内核模块的名字 cat /proc/devices | grep guan_device #这里是内核模块中定义的设备名称 #get the major number:得到设备编号 sudo mknod /dev/interface c 247(设备编号) 0 #创建设备 sudo chmod a+w /dev/guan_device #更改权限
卸载
sudo rmmod RW_module #卸载模块 sudo rm -f /dev/guan_device #删除设备
注:
1. 关于显示运行时间的问题,可以参考我的另一篇博文:http://blog.csdn.net/u013806583/article/details/58127067
2. 关于如何编译、加载和卸载内核模块,可以参考《Linux OS内核 作业一》的方法:http://blog.csdn.net/u013806583/article/details/58604378
用户编写自定义程序,访问设备
源码:app.c
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> int MAX_LEN=32; int fd; char read_buf[100]; void write_guan(char* str) { printf("start to write ...\n"); //调用函数,完成“写”操作 write(fd, str, sizeof(str)); } void read_guan() { printf("start to read ...\n"); //调用函数,完成“读”操作 read(fd, read_buf, sizeof(read_buf)); //输出独到的内容 printf("%s\n",read_buf ); } void main(int argc, char const *argv[]) { fd = open("/dev/guan_device", O_RDWR);//DEVICE_NAME /** *O_RDONLY 只读打开。 O_WRONLY 只写打开。 O_RDWR 读、写打开。 */ char order_input[5]; char content_input[100]; scanf("%s",order_input); if (strcmp(order_input,"read")==0) { read_guan(); }else if (strcmp(order_input,"write")==0) { scanf("%s",content_input); write_guan(content_input); }else{ printf("input ERROR !\n"); } return ; }
makefile:
main: app.o gcc -o app app.o -lm clean: rm -f app app.o
编译
使用
按照第一部分方法,安装内核模块
编译本源码app.c
运行
./app #回车,然后程序就等待输入 read #读操作:输入read命令,并回车 #或 write abcdefg... #写操作:输入write命令和写入的内容,并回车
测试
开启三个终端,分别运行 ./app 。其中一个运行写命令,其余两个运行读命令。结果:可以看到当程序在写时,读操作要等待。当写操作完成时,两个读操作几乎同时进行。
系列博客:
相信当你需要其中一个的时候,也一定需要剩下的两个
Linux OS内核 作业一:kthread和workqueue
Linux OS内核 作业二:多线程访问
Linux OS内核 作业三:设备驱动与读写信号量
相关文章推荐
- 例说linux内核与应用数据通信(三):读写内核设备驱动文件
- 例说linux内核与应用数据通信(三):读写内核设备驱动文件
- 从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响(一)
- 浅谈 Linux 内核开发之 PCI 设备驱动
- 编写Linux设备驱动时内核版本号的判断
- 浅谈 Linux 内核开发之网络设备驱动
- 从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响
- 从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响
- 从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响
- 浅谈 Linux 内核开发之网络设备驱动
- 从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响
- 浅谈 Linux 内核开发之网络设备驱动[转]
- Linux设备驱动开发详解--笔记3--Linux内核及内核编程
- (转载)从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响
- 从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响
- 从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响
- 从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响
- 从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响
- 从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响 -zt
- 浅谈 Linux 内核开发之 PCI 设备驱动