对于Linux内核重入我做了一下一些分析。

首先要界定一个范围(代码段,函数)然后才能够讨论重入。

比如以函数A,B分别为一个范围。在运行A的时候发生中断,调用B,B运行完了又返回A,这个时候称B进入A。

假如A=B,那么称A重入A,或能够说有两个A的实例在运行。

重入导致的问题主要就是由于这两个A能够会几乎同时访问一些堆中的变量而出现不一致。解决这个问题的办法有几个:

干脆不允许某个函数(某段代码)重入,也就是假如A运行,当发生中断的时候,调用A,发现已有A运行了,则返回,不再运行这个新的A.bottom half采用这个办法。

或对一些临界区上锁。

或干脆关中断。

内核的重入,首先界定的范围就是整个处于内核级的代码段。

因此,内核的重入能够说是经常发生的,比如中断发生时。

内核的重入有两种情况:

1和进程无关的中断发生时,CPU已在内核中运行,也就是中断嵌套。一般内核会做一定的保护,比如关中断,锁临界区等。但是这种中断有一个特点,就是先进后出的栈的模式,因此,用一个栈足矣。

2和进程相关的转换。假如总是在内核返回到用户级代码段时才转换,那么这个意义上的重入就不存在,用一个内核栈就能够了。更有一种可能是在内核中就转换,由于进程执行并不是按照先进先出的模式,因此,每个进程都有一个内核栈。

更有一个问题,上面和进程无关的中断一般访问和进程无关的数据,所以需要保护的数据比较少。在这种重入中,几个进程的内核实例会访问和进程相关的共有数据,会导致不一致,而这种临界区会比较多,所以上锁可能会比较麻烦,Linux采用的是一种非透明的转换,即当前进程的内核部分必须主动放弃CPU,才可能转换。这样使内核同步比较简单。所以Linux内核的重入是一定条件下的重入,非抢占式的重入。