[纵目科技/飞凌科技]
1、驱动里为什么要有并发、互斥的控制?
内核中的很多事情是需要多线程、多进程来实现的,并发(concurrency)指的是多个执行单元同时、并行被执行,而并发的执行单元对共 享资源(硬件资源和软件上的全局变量、静态变量等)的访问则很容易导致竞态(race conditions)。
解决竞态问题的途径是保证对共享资源的互斥访问,所谓互斥访问就是指一个执行单元 在访问共享资源的时候,其他的执行单元都被禁止访问。
访问共享资源的代码区域被称为临界区,临界区需要以某种互斥机 制加以保护,中断屏蔽,原子操作,自旋锁,和信号量都是linux设备驱动中可采用的互斥途径。
2、有几种情况会导致竟态的发生?
- 对称多处理器(SMP)多个CPU,使用共同的系统总线,因此可访问共同的外设和存储器。
- 单CPU内进程与抢占它的进程 [进程与进程]
- 中断(硬中断、软中断、Tasklet、底半部)与进程之间 [进程与中断]
- 中断与中断 (中断被更高优先级的中断打断)
只要并发的多个执行单元存在对共享资源的访问,竞态就有可能发生。
如果中断处理程序访问进程正在访问的资源,则竞态也会会发生。
多个中断之间本身也可能引起并发而导致竞态(中断被更高优先级的中断打断)。
3、有几种方法来保护临界资源?他们的区别是什么?
1.中断屏蔽
2.原子操作----->进程与进程 (原子操作不能被中断打破。)
3.自旋锁 ----> SMP (自旋锁就是忙等锁、可能导致系统死锁、不能调用引起进程调度的函数)
4. 信号量------->进程与进程 , 进程与中断
(休眠锁(可以在自己允许的情况下,让多个进程访问自己的资源、可休眠)
工作中 ioctl 常加自旋锁,保护资源,LED要灭就灭,要亮就亮。
因为你不知道,有几个进程或线程在调用这个设备的ioctl
4、用户态如何保护临界资源,有几种方法,区别是什么?
互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排他性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。
同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况下允许多个访问者同时访问资源。
互斥锁 mutex
信号量
互斥锁用于线程的互斥,信号量用于线程的同步。
一个互斥锁只能用于一个资源的互斥访问,它不能实现多个资源的多线程互斥问题
信号量可以实现多个同类资源的多线程互斥和同步。当信号量为单值信号量时,也可以完成一个资源的互斥访问。
5、如何理解中断的上半部和下半部?(飞凌科技)
上半部的功能是响应中断。(响应的过程中不能被中断)------》 很快。
下半部的功能是处理比较复杂的过程。(可被中断),一般通过软中断 ,tasklet,和工作队列来实现的.
6、如何理解中断底半部?
三种方式来实现:软中断、tasklet 、workqueue
软中断: 在内核中不推荐(异常)
tasklet:运行在中断上下文,不能有长的延时函数(不需要睡眠的时候用)
workqueue :运行在进程上下文,可以有长延时函数(需要睡眠的时候用)
工作队列(work queue)是另外一种将工作推后执行的形式,它和前面讨论的tasklet有所不同。工作队列可以把工作推后,交由一个内核线程去执行,也就是说,这个下半部分可以在进程上下文中执行。这样,通过工作队列执行的代码能占尽进程上下文的所有优势。最重要的就是工作队列允许被重新调度甚至是睡眠。
7、什么中断上下文?什么是进程上下文?
进程上下文:(用户态和内核态切换)
(1)进程上文:其是指进程由用户态切换到内核态是需要保存用户态时cpu寄存器中的值,进程状态以及堆栈上的内容,即保存当前进程的进程上下文,以便再次执行该进程时,能够恢复切换时的状态,继续执行。
(2)进程下文:其是指切换到内核态后执行的程序,即进程运行在内核空间的部分。
一个程序执行了系统调用或者触发某个异常(软中断),此时就会陷入内核空间,内核此时代表进程执行,并处于进程上下文中。
中断上下文:(内核态和硬件)
(1)中断上文:硬件通过中断触发信号,导致内核调用中断处理程序,进入内核空间。中断上文可以(主要是当前被中断的进程环境,要被保存,方便恢复)
(2)中断下文:执行在内核空间的中断服务程序。
程序在执行过程中通常有用户态和内核态两种状态,CPU对处于内核态根据上下文环境进一步细分,因此有了下面三种状态:
(1)内核态,运行于进程上下文,内核代表进程运行于内核空间。
(2)内核态,运行于中断上下文,内核代表硬件运行于内核空间。
(3)用户态,运行于用户空间。
8、驱动中常用的申请内存的函数?都有什么区别?
kmalloc()、kzalloc()、vmalloc() 的共同特点是:
- 用于申请内核空间的内存;
- 内存以字节为单位进行分配;
- 所分配的内存虚拟地址上连续;
kmalloc()、kzalloc()、vmalloc() 的区别是:
- kzalloc 是强制清零的 kmalloc 操作;(以下描述不区分 kmalloc 和 kzalloc)
- kmalloc 分配的内存大小有限制(128KB),而 vmalloc 没有限制;
- kmalloc 可以保证分配的内存物理地址是连续的,但是 vmalloc 不能保证;
- kmalloc 分配内存的过程可以是原子过程(使用 GFP_ATOMIC),而 vmalloc 分配内存时则可能产生阻塞;
- kmalloc 分配内存的开销小,因此 kmalloc 比 vmalloc 要快;
一般情况下,内存只有在要被 DMA 访问的时候才需要物理上连续,但为了性能上的考虑,内核中一般使用 kmalloc(),而只有在需要获得大块内存时才使用 vmalloc()。例如,当模块被动态加载到内核当中时,就把模块装载到由 vmalloc() 分配的内存上。
9、同一个进程可以在两个核上跑吗
能不能跑,要看 cache 的一致性。我们知道 在CPU与memory 之间,有一个 cache。 CPU访问一个数据的时候,如果被cache命中的话,
CPU就会很快的读取出数据,这个速度远大于从 memory 中读取的数据。如果一个CPU有多个核,要看这几个核是不是共享cache。共享cache还好。
cpu <---> cache <---> memory
如果不是共享cache,那就保持cache的一致性,但也是有专门的协议来保证的,比如MESI等。
cache的不一致,是因为同样一份数据在多个cache中存在多份拷贝,如果数据在一个cache中被写另一个cache却不知道,就会有不一致。对于多核共享cache最基本的方法就是写失效和写更新两种。每个核的专有cache要时刻监听总线上的写cache请求,一旦监听到总线要写的cache块自己肚子里也有,就将自己肚子里的cache块置为失效(写失效),等到下次该块cache miss再重新load最新的数据。或者在总线更新某块的时候,刚好自己肚子里也有一份该块的拷贝,顺便把自己内部的cache块也更新了(写更新),就可以保证自己一直是最新的数据。
从硬件原理上来讲,主要就是做到写操作即时即刻的传递给所有的核/cache。写操作一定要广播出去,只要通知到位,就有办法。