首页 > 学院 > 开发设计 > 正文

Linux OS内核 作业三:设备驱动与读写信号量

2019-11-06 08:53:13
字体:
来源:转载
供稿:网友

实验题目:

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 semaphorevoid down_read(struct rw_semaphore *sem); //Hold semaphore for reading, sleep if not availablevoid up_read(struct rw_semaphore *sem); //Release semaphore for readingvoid down_write(struct rw_semaphore *sem); //Hold semaphore for writing, sleep if not availablevoid down_write_trylock(struct rw_semaphore *sem); //Hold semaphore for writing, error if not availablevoid 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 -lmclean: rm -f app app.o编译使用 按照第一部分方法,安装内核模块编译本源码app.c运行 ./app #回车,然后程序就等待输入 read #读操作:输入read命令,并回车 #或 write abcdefg... #写操作:输入write命令和写入的内容,并回车

测试

开启三个终端,分别运行 ./app 。其中一个运行写命令,其余两个运行读命令。

这里写图片描述

结果:可以看到当程序在写时,读操作要等待。当写操作完成时,两个读操作几乎同时进行。


系列博客: 相信当你需要其中一个的时候,也一定需要剩下的两个 Linux OS内核 作业一:kthread和workqueue Linux OS内核 作业二:多线程访问 Linux OS内核 作业三:设备驱动与读写信号量


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表