栈
什么是栈
栈是一段内存空间。
ARM处理器程序的运行过程
ARM芯片属于精简指令集(RISC:Reduced Instruction Set Computing)
特点:
1、对内存只有读和写两种指令,
2、所有的数据运算都是在CPU内部完成的。
举例实现a=a+b;
CPU 先在内存中读取a,b的值放入到CPU的寄存器(这里的寄存器不是指的内存中分配的)中,再进行运算,然后把计算值返回到内存中。
1把内存 a 的值读入 CPU 寄存器 R0,
2 把内存 b 的值读入 CPU 寄存器 R1,
3 把 R0、R1 累加,存入 R0,
4 把 R0 的值写入内存 a。
这个过程中R0 R1寄存器的值会被刷新,那这时如果有B函数打断这个函数,或者响应中断打断这个函数,他们也会使用到CPU中R0,R1寄存器,那么原有的寄存器中的值会被刷新,该如何解决?这时便引入了现场保存和恢复问题。
程序被中断时,怎么保存现场
当正在运行的程序被打断时,这时会将CPU寄存器的值保存到相应的栈中。等恢复现场时,再将这些值取出给CPU寄存器。
举例1函数A中调用函数B流程如下图所示。
1、函数调用
在函数 A 里调用函数 B,实际就是中断函数 A 的执行,那么需要把函数 A 调用 B 之前瞬间的 CPU 寄存器的值,保存到栈里;再去执行函数 B;B函数可能之前被调用过,会现将B函数的栈中的值回传给CPU中的寄存器中,运行B函数的代码;B函数调用完成以后,恢复现场,现将B函数中的值存进B对应的栈中将A函数的栈中的值取出给CPU,再继续运行A函数的代码
2、中断处理
a) 进程 A 正在执行,这时候发生了中断。
b) CPU 强制跳到中断异常向量地址去执行,
c) 这时就需要保存进程 A 被中断瞬间的 CPU 寄存器值
d) 可以保存在进程 A 的内核态栈,也可以保存在进程 A 的内核结构体中。(这个是不是和后面的两种方法有关我这还不清楚)
e) 中断处理完毕,要继续运行进程 A 之前,恢复这些值。
3、进程切换
a) 在所谓的多任务操作系统中,我们以为多个程序是同时运行的。
b) 如果我们能感知微秒、纳秒级的事件,可以发现操作系统时让这些程序
依次执行一小段时间,进程 A 的时间用完了,就切换到进程 B。
c) 怎么切换?
d) 切换过程是发生在内核态里的,跟中断的处理类似。
e) 进程 A 的被切换瞬间的 CPU 寄存器值保存在某个地方;
f) 恢复进程 B 之前保存的 CPU 寄存器值,这样就可以运行进程 B 了。
可通过下图理解下。
进程和线程的概念
在 Linux 中:资源分配的单位是进程,调度的单位是线程。
用线程来处理下半部中断原理
内核会提供一个worker线程,这个线程里有个work queue 队列;在这个work queue中放一个work struct 结构体,这个结构体提供一个.fun成员就是要执行的函数。
也就是说,在一个进程里,可能有多个线程,这些线程共用打开的文件句柄、全局变量等等。
这里我理解线程就是任务,他们可以访问这个进程(相当于单片机中的工程)的定义的一些全局变量
而这些线程,之间是互相独立的,“同时运行”,也就是说:每一个线程,都有自己的栈。
Linux中系统对中断处理方法
Linux系统对中断处理的两个原则
1不能进行中断嵌套,也就是说当前中断响应时,即使优先级更高的中断发生也不能打断当前中断去响应
2中断的处理越快越好。
Linux中的中断的扩展
硬件中断
硬件中断:每个硬件产生的中断比如按键产生的中断,这类中断称为硬件中断。先可以认为硬件中断是由数组实现的。
数组中存放的是函数指针。
当A中断发生时,相应的A函数将会被调用。
软件中断:
软件中断和硬件中断相比,软件中断是认为制造的中断,也有相应的中断号和对应的中断函数,此外还有一个flage用于标记是否产生了中断。那么存在以下两个问题。
1软件中断何时生产?
由软件决定,对于 X 号软件中断,只需要把它的 flag 设置为 1 就表示发生了该中断。
2软件中断何时处理?
在处理完硬件中断后,再去处理软件中断。软件中断相当于有硬件中断响应后会遍历一下这个数组,检查是否有flage为1,为1响应响应的软件中断
用上下两部分(硬件中断、软件中断分开)的方式处理中断
这里注意硬件中断不能够被打断,软件中断可以被实时发生的硬件中断打断
硬件中断发生时,开始处理,preempt_count(这里简称pct)++为,然后执行中断上半部(硬件中断),硬件中断执行完毕pct--为0,这时判断pct?(pct为0故4为假)执行N,pct++为1然后开启中断(开启中断的意思是可以响应其他硬件中断),处理下半部中断(软件中断),这里分两种情况1、处理软件中断过程中如果没有其他硬件中断打断,则继续处理软件中断,执行完毕后关中断(这时不能响应硬件中断了),然后关中断(硬件中断不能响应),pct-- 为0。2、处理软件中断过程中如果有其他硬件中断(中断B)打断,这时跳到B中断的开始处理处pct++为2 硬件中断B处理,然后pct--为1判断pct,pct为真完成处理,回到硬件中断A的软件中断处,继续处理A和B的软件中断。
实现用线程来处理下半部中断的方法
1先构造一个worker结构体里面提供.func(要执行的函数)
2中断上半部执行时将worker放入work queue中。
线程化的中断进行处理 threaded irq
对每一个中断都提供一个中断线程。应对于多核cpu。因为一个中断线程只能在一个核上运行,多创建几个可以在多个核的cpu上运行。
内核提供了一个函数 request_threaded_irq,这个函数中的参数irq为中断号查询哪个中断,handler 为上半部中断,上半部中断可以为空这样上半部中断都可以在线程中运行。你可以thread_fn,系统会为这个函数创建一个内核线程,发生中断时,内核线程就会执行这个函数。
新技术 threaded irq,为每一个中断都创建一个内核线程;多个中断的内核线程可以分配到多个 CPU 上执行,这提高了效率。
这里只是学习时的个人理解仅供个人学习和参考,感谢韦东山老师资料提供的文档,如有侵权即刻删除