文章目录
本人学习完韦老师的视频,因此来复习巩固,写以笔记记之。
韦老师的课比较难,第一遍不知道在说什么,但是坚持看完一遍,再来复习,基本上就水到渠成了。
看完视频复习的同学观看最佳!
基于 IMX6ULL-PRO
一、同步与互斥
Linux驱动 = 驱动框架 + 硬件编程
1.1 内联汇编
内联汇编:在C函数中使用汇编代码。
有些算法需要我们手工优化,这时就需要手写汇编代码;或是有时需要调用特殊的汇编指令(比如使用ldrex/strex实现互斥访问),这都涉及内联汇编。
三种不同的方式实现加法函数
① C语言实现后的汇编很复杂,需要入栈、出栈等操作,效率不算高。
反汇编查看add函数的一系列汇编操作
② 使用汇编函数实现加法
单独另起一个add.S汇编文件
会导致最后生成文件的反汇编只有2条指令,提高了效率
③ 使用内联汇编
内联汇编语法:
①:也可以写作__asm__,表示这是一段内联汇编。
②:有3个取值:volatile、inline、goto。volatile的意思是易变的、不稳定的,用来告诉编译器不要随便优化这段代码,否则可能出问题。③:汇编指令,用双引号包含起来,每条指令 \n 分开
④:输出操作数,内联汇编执行时,输出的数据保存在这里
⑤:输入操作数,内联汇编执行前,输入的数据保存在这里
⑥:除输出操作数外,还修改了那些寄存器、内存
cc:表示汇编代码会修改“flags register”
操作数中的constraint前还可以加上一些修饰字符,比如“=r”、“+r”、“=&r”。
&
:告诉编译器,给我分配一个单独的寄存器,别为了省事跟输入操作数用同一个寄存器。
变量的修改需要读出、修改、写入三个步骤,在这过程中若被别的进程抢占,都会导致同步与互斥原理的失败
1.2 原子操作的实现原理和使用
原子操作:就是这个操作不会被打断
typedef struct {
int counter;
} atomic_t;
三条指令分别实现读出、修改、写入
ldrex
指令:读入,标记addr为独占访问
strex
指令: ①未被抢占时,写入,清除独占标记,返回值Ret = 0。②被抢占,发现非独占,放弃写入,Ret = 1
teq该指令通常用于比较操作数1和操作数2是否相等
(1) 原子变量使用案例
使用原子变量实现:只能有一个APP访问驱动程序
static atomic_t valid = ATOMIC_INIT(1);
static ssize_t gpio_key_drv_open (struct inode *node, struct file *file)
{
if (atomic_dec_and_test(&valid)){
return 0;}
atomic_inc(&valid);
return -EBUSY;
}
valid初始值为1,进入if条件语句执行减1函数后,结果为0,返回值为1,成功返回0;当程序被打断时,由于valid为0,减1后结果为-1,返回值为0,则不执行if语句,返回-EBUSY
(2) 原子位的操作
1.3 Linux系统下的锁
Linux内核提供了很多类型的锁,它们可以分为两类:
① 自旋锁(spinning lock):简单地说就是无法获得锁时,不会休眠,会一直循环等待。
② 睡眠锁(sleeping lock):无法获得锁时,当前线程就会休眠;其中又分为互斥量mutex和信号量semaphore。
(1) 自旋锁
SMP就是Symmetric Multi-Processors,对称多处理器;UP即Uni-Processor,系统只有一个单核CPU。
对于单CPU系统,自旋锁的自旋功能就去掉了:只剩下禁止抢占、禁止中断。
① spinlock在UP系统中的实现
对于spin_lock(),当前线程正在执行内核态函数时,它是有可能被别的线程抢占,在UP系统中spin_lock()就退化为preempt_disable()
对于spin_lock_irq(),在UP系统中就退化为local_irq_disable()和preempt_disable()
假设程序A要访问临界资源,可能会有中断也来访问临界资源,可能会有程序B也来访问临界资源,那么使用spin_lock_irq()来保护临界资源:先禁止中断防止中断来抢,再禁止preempt防止其他进程来抢。
②spinlock在SMP系统中的实现
(2) 信号量semaphore
初始化semaphore之后,就可以使用down函数或其他衍生版本来获取信号量,使用up函数释放信号量。
down函数的实现
如果semaphore中的count大于0,那么down函数就可以获得信号量;否则就休眠。在读取、修改count时,要使用spinlock来实现互斥。
休眠时,要把当前进程放在semaphore的wait_list链表中,别的进程释放信号量时去wait_list中把进程取出、唤醒。
up函数的实现
如果有其他进程在等待信号量,则count值无需调整,直接取出第1个等待信号量的进程,把信号量给它,共把它唤醒。
如果没有其他进程在等待信号量,则调整count。
(3) 互斥量mutex
互斥量mutex结构体,metex中的count值,1表示unlocked,0表示locked,还有一类值“负数”表示“locked,并且可能有其他程序在等待”。
mutex_lock函数的fastpath实现
mutex_unlock函数的fastpath实现