驱动学习(七)驱动互斥

驱动学习(七)驱动互斥

1. 什么是驱动互斥?

一类设备对应一个驱动程序,一类设备可以有多个子设备,当多个子设备同时访问一个驱动程序时,会造成竞态。简单来说就是厕所只有一个,不可以同时上。

2. 什么是竞态?

竞态就是两个子设备同时访问了一个驱动程序,就是他俩同时进厕所了,坑位只有一个,这这这,不像话啊。

模拟条件:一个驱动,两个设备文件,一起访问。
在这里插入图片描述

后果是什么?会造成数据错乱,这里我没有还原出来,但是对于内核级别来说是致命的。

3. 如何解决多个子设备对同一个驱动的竞态访问问题呢?

Linux内核提供了多种互斥方法,有互斥锁、信号量、原子变量、自旋锁

3.1 互斥锁

如何防止你在上厕所时,别人从外面把门拉开?加把锁!当然不锁门的当我没说。

应用

 mutex_t mutex;//应用层互斥锁
 1 定义互斥锁
	struct mutex  Mutex;//内核互斥锁
 2 初始化互斥锁
	mutex_init(Mutex);-->在初始化函数中
 3 加锁
	mutex_lock(&Mutex);-->在打开函数中锁住资源
 4 解锁
	mutex_unlock(&Mutex);--->在关闭函数中释放资源

测试

#####驱动代码

  1 #include <linux/module.h>           //模块驱动的头文件
  2 #include <linux/cdev.h>             //设备信息描述的头文件
  3 #include <linux/fs.h>               //静态申请设备号头文件
  4 #include <linux/kdev_t.h>           //设备号用到的头文件和宏函数
  5 #include <linux/uaccess.h>
  6 #include <linux/device.h>
  7 #include "common.h"
  8 
  9 #define BUF_SIZE 100
 10 
 11 int major = 0;                      //主设备号
 12 int min = 0;                        //次设备号
 13 int deviceNum = 0;                  //完整设备号
 14 struct cdev* pCdev = NULL;          //描述设备信息的结构体
 15 char *deviceName = "mutex";//设备名
 16 char buff[BUF_SIZE] = "chrdev-test-2022-7-12";
 17 struct class *pClass = NULL;        //设备文件类指针
 18 int devNum = 2;                     //设备文件数量
 19 struct mutex Mutex;                 //互斥锁
 20 
 21 int testOpen(struct inode *pNode,struct file *pFile)
 22 {
 23         printk("------into test open------\n");
 24         mutex_lock(&Mutex);
 25         printk("------leave test open------\n");
 26         return 0;
 27 }
 28 int testClose(struct inode *pNode,struct file *pFile)
 29 {
 30         printk("------into test close------\n");
 31         mutex_unlock(&Mutex);
 32         printk("------leave test close------\n");
 33         return 0;
 34 }
 35 ssize_t testRead(struct file *pFile,char __user *buf,size_t count,loff_t *pOffset)
 36 {
 37         int res = -1;
 38         printk("------into testRead------\n");
 39         if(count > BUF_SIZE-1)
 40         {
 41                 count = BUF_SIZE - 1;
 42         }
 43         res = copy_to_user(buf,buff,count);
 44         if(res)
 45         {
 46                 printk("copy_to_user error\n");
 47                 return -EFAULT;
 48         }
 49         printk("copy_to_user ok\n");
 50         printk("\t buff = %s\t\n",buff);
 51         printk("------leave testRead------\n");
 52         return count;
 53 }
 54 
 55 ssize_t testWrite(struct file *pFile,const char __user *buf,size_t count,loff_t *pOffset)
 56 {
 57         int res = -1;
 58         printk("------into testWrite------\n");
 59         if(count > BUF_SIZE-1)
 60         {
 61                 count = BUF_SIZE - 1;
 62         }
 63         res = copy_from_user(buff,buf,count);
 64         if(res)
 65         {
 66                 printk("copy_from_user error\n");
 67                 return -EFAULT;
 68         }
 69         printk("copy_from_user ok\n");
 70         printk("\t buff = %s\t\n",buff);
 71         printk("------leave testWrite------\n");
 72         return count;
 73 }
 74 
 75 long testIoctl(struct file *pFile,unsigned int cmd,unsigned long arg)
 76 {
 77         switch(cmd)
 78         {
 79                 case TEST_CMD:
 80                         {
 81                                 printk("test cmd-------arg = %ld \n",arg);
 82                         }
 83                         break;
 84                 case TEST_CMD1:
 85                         {
 86                                 printk("test cmd1-------arg = %ld \n",arg);
 87                         }
 88                         break;
 89                 case TEST_CMD2:
 90                         {
 91                                 printk("test cmd2-------arg = %ld \n",arg);
 92                         }
 93                         break;
 94                 default:
 95                         printk("error cmd \n");
 96         }
 97         return 0;
 98 }
 99 
100 struct file_operations fp_arr =
101 {
102         .owner = THIS_MODULE,
103         .open = testOpen,
104         .read = testRead,
105         .write = testWrite,
106         .release = testClose,
107         .unlocked_ioctl = testIoctl
108 };
109 
110 int driverr_init(void)               //模块初始化函数
111 {
112         int res = 0;
113         int i = 0;
114         struct device *pDevTmp = NULL;
115         printk("*********into driver init\n");
116         //动态申请设备号
117         res = alloc_chrdev_region(&deviceNum,min,devNum,deviceName);
118         if(res)
119         {
120                 printk("alloc_chrdev_region error\n");
121                 return res;
122         }
123         printk("alloc_chrdev_region OK!\n");
124         printk("major = %d minor = %d \n",MAJOR(deviceNum),MINOR(deviceNum));
125         major = MAJOR(deviceNum);
126         //创建设备
127         pCdev = cdev_alloc();
128         if(NULL == pCdev)
129         {
130                 printk("cdev_alloc error\n");
131                 unregister_chrdev_region(deviceNum,devNum);
132                 return -1;
133         }
134         printk("cdev_alloc ok\n");
135         //设备初始化
136         cdev_init(pCdev,&fp_arr);
137         printk("cdev_init ok\n");
138         //设备与设备号关联
139         res = cdev_add(pCdev,deviceNum,devNum);
140         if(res)
141         {
142                 printk("cdev_add error\n");
143                 cdev_del(pCdev);
144         }
145         printk("cdev_add ok\n");
146         //创建设备文件类
147         pClass = class_create(THIS_MODULE,"mutex");
148         if(NULL == pClass)
149         {
150                 printk("class_create error\n");
151                 cdev_del(pCdev);
152         }
153         printk("class_create ok\n");
154         //创建设备文件
155         for(;i < devNum;i++)
156         {
157                 pDevTmp = device_create(pClass,NULL,MKDEV(major,i),NULL,"mutex%d",i);
158                 if(IS_ERR(pDevTmp))
159                 {
160                         printk("device_create error\n");
161                         for(i = 0;i < devNum;i++)
162                         {
163                                 device_destroy(pClass,MKDEV(major,i));
164                         }
165                         class_destroy(pClass);
166                         return -2;
167                 }
168         }
169         printk("device_create ok\n");
170         //初始化互斥锁
171         mutex_init(&Mutex);
172         printk("*********leave driver init\n");
173         return 0;
174 }
175 
176 void driver_clear(void)             //模块清除函数
177 {
178         int i = 0;
179         printk("*********into driver clear\n");
180         for(;i < devNum; i++)
181         {
182                 device_destroy(pClass,MKDEV(major,i));
183         }
184         class_destroy(pClass);
185         cdev_del(pCdev);
186         unregister_chrdev_region(deviceNum,devNum);
187         printk("*********leave driver clear\n");
188 }
189 
190 module_init(driverr_init);           //模块加载函数
191 module_exit(driver_clear);          //模块卸载函数
192 
193 
194 MODULE_LICENSE("GPL");
195 MODULE_AUTHOR("cfy");
196 MODULE_ALIAS("liangzai");
197 MODULE_DESCRIPTION("2022-7-12");
#####测试代码test.c

  1 #include <stdio.h>
  2 #include <sys/types.h>
  3 #include <sys/stat.h>
  4 #include <fcntl.h>
  5 #include <unistd.h>
  6 #include <string.h>
  7 
  8 #define BUF_SIZE 100
  9 
 10 int main()
 11 {
 12         int fd = open("/dev/mutex0",O_RDWR);
 13         if(fd < 0)
 14         {
 15                 printf("open mutex0 err\n");
 16                 return -1;
 17         }
 18         printf("open mutex0 ok\n");
 19 
 20         char buf[BUF_SIZE] = {0};
 21         //测试读
 22         read(fd,buf,BUF_SIZE-1);
 23         printf("read data:%s\n",buf);
 24         bzero(buf,sizeof(buf));
 25 
 26         //测试写
 27         printf(">> input:");
 28         scanf("%s",buf);
 29         write(fd,buf,sizeof(buf));
 30         bzero(buf,sizeof(buf));
 31         read(fd,buf,BUF_SIZE-1);
 32         printf("write end read data:%s\n",buf);
 33 
 34         close(fd);
 35         return 0;
 36 
 37 
 38 }

test1.c就是打开/dev/mutex1这个文件,其余和test.c一致。

安装加了互斥锁的驱动,修改设备文件权限
在这里插入图片描述

先执行test测试程序,再执行test1测试程序。
在这里插入图片描述

在test没使用完驱动资源之前,test1是拿不到资源的,光标一直在闪。

让test释放驱动资源。

在这里插入图片描述

这样test1拿到驱动资源了,test1读到的数据是test输入的数据。这样就实现了互斥锁的功能。

3.2 信号量

应用

1 定义信号量
	struct semaphore sem;//内核信号量
2 初始化信号量
	sema_init(&sem,1)//在初始化函数中进行
3 获取信号量
	down_interruptible(&sem)相当于进程中的p操作-->sem_wait//在打开函数中进行,可以中断(接收信号)
    down(&sem)也可以,不能中断
4 释放信号量
	up(&sem)相当于进程中的V操作-->sem_post//在关闭函数中进行

测试

效果与互斥锁一样,代码太长了要不不放了。

在这里插入图片描述

3.3 原子变量
1 定义原子变量并初始化
	atomic_t  a=ATOMIC_INIT(1);
2 打开函数
	原子变量只能通过Linux内核提供的接口函数来操作
	atomic_dec_and_test(&a):给原子变量a减1,然后测试a的值是否为0,如果为0,该函数返回true,否则返回false
	if(!atomic_dec_and_test(&a))
	{
		return busy;
	}
    使用驱动资源;               
3 关闭函数
	atomic_inc(&a)-->给原子变量a加1

测试

代码按照上面写就可以
在这里插入图片描述

test占用之后test1使用会报错

3.4 自旋锁

跟互斥锁差不多,代码不放了。

1 定义自旋锁
	spinlock_t  t;
2 初始化自旋锁
	spin_lock_init(&t)-->初始化函数中
3 获取自旋锁
	spin_lock(&t)-->打开函数
4 释放自旋锁
	spin_unlock(&t)-->关闭函数
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值