在3.16-rc4内核源码中,内核给每个进程分配的内核栈大小为8KB。这个内核栈被称为异常栈,在进程的内核空间运行时或者执行异常处理程序时,使用的都是异常栈,看下异常栈的代码(include/linux/sched.h):

 union thread_union {
struct thread_info thread_info;
unsigned long stack[THREAD_SIZE/sizeof(long)];
};

THREAD_SIZE值为8KB,因此内核为进程的异常栈(内核栈)分配了两个页框大小(页框大小4KB)。另外,进程的thread_info结构体保存在栈顶部。

此外,内核为每个cpu分配一个硬中断栈和一个软中断栈(这两个栈也是内核栈),用来执行中断服务例程和下半部(软中断),看看代码(arch/x86/kernel/irq_32.c)。这两个栈属于cpu,不属于进程,这和异常栈是有区别的。

 DEFINE_PER_CPU(struct irq_stack *, hardirq_stack);
DEFINE_PER_CPU(struct irq_stack *, softirq_stack);

定义了两个数组hardirq_stack和softirq_stack,每个数组元素对应一个cpu,指向了该cpu的硬中断栈或者软中断栈。再来看下struct irq_stack结构体(arch/x86/include/asm/processor.h):

 struct irq_stack {
u32 stack[THREAD_SIZE/sizeof(u32)];
} __aligned(THREAD_SIZE);

可见,硬中断栈和软中断栈的大小均为8KB。

内核在执行中断处理程序时,在do_IRQ函数中会调用handle_irq函数,在handle_irq函数中要进行堆栈切换,代码如下(arch/x86/kernel/irq_32.c):

 bool handle_irq(unsigned irq, struct pt_regs *regs)
{
struct irq_desc *desc;
int overflow; overflow = check_stack_overflow(); desc = irq_to_desc(irq);
if (unlikely(!desc))
return false; if (user_mode_vm(regs) || !execute_on_irq_stack(overflow, desc, irq)) {
if (unlikely(overflow))
print_stack_overflow();
desc->handle_irq(irq, desc);
} return true;
}

第12行中执行execute_on_irq_stack函数来判断是否需要堆栈切换,如果不需要,则执行if体的中断服务例程,即在当前堆栈中执行中断服务例程,如果需要切换堆栈,则在execute_on_irq_stack函数中切换堆栈并在该函数中(新堆栈中)执行中断服务例程。下面看下execute_on_irq_stack代码(arch/x86/kernel/irq_32.c):

 static inline int
execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
{
struct irq_stack *curstk, *irqstk;
u32 *isp, *prev_esp, arg1, arg2; curstk = (struct irq_stack *) current_stack();
irqstk = __this_cpu_read(hardirq_stack); /*
* this is where we switch to the IRQ stack. However, if we are
* already using the IRQ stack (because we interrupted a hardirq
* handler) we can't do that and just have to keep using the
* current stack (which is the irq stack already after all)
*/
if (unlikely(curstk == irqstk))
return ; isp = (u32 *) ((char *)irqstk + sizeof(*irqstk)); /* Save the next esp at the bottom of the stack */
prev_esp = (u32 *)irqstk;
*prev_esp = current_stack_pointer; if (unlikely(overflow))
call_on_stack(print_stack_overflow, isp); asm volatile("xchgl %%ebx,%%esp \n"
"call *%%edi \n"
"movl %%ebx,%%esp \n"
: "=a" (arg1), "=d" (arg2), "=b" (isp)
: "" (irq), "" (desc), "" (isp),
"D" (desc->handle_irq)
: "memory", "cc", "ecx");
return ;
}

第7行获取当前堆栈的指针,第8行获取本地cpu的硬中断栈指针,第16行对二者进行比较,如果相等,则不需要切换堆栈(说明当前堆栈就是硬中断栈,也说明是在中断处理程序中时又发生了中断)。如果不相等,就要进行堆栈切换,第22-23行将当前堆栈指针保存在将要切换到的堆栈中(用于返回)。第28行,交换ebx和esp寄存器的值(实现了堆栈切换,将中断栈指针给了esp),第29行跳转到相应的中断服务例程,第30行从中断服务例程返回后,又将原来的堆栈指针赋给esp,切换到原先堆栈。第33行将中断服务例程函数名存放在%edi中。

内核源码分析之linux内核栈(基于3.16-rc4)的更多相关文章

  1. 内核源码分析之tasklet(基于3.16-rc4)

    tasklet是在HI_SOFTIRQ和TASKLET_SOFTIRQ两个软中断的基础上实现的(它们是在同一个源文件中实现,由此可见它们的关系密切程度),它的数据结构和软中断比较相似,这篇博文将分析t ...

  2. 内核源码分析之软中断(基于3.16-rc4)

    1.和软中断相关的数据结构: softing_vec数组(kernel/softirq.c) static struct softirq_action softirq_vec[NR_SOFTIRQS] ...

  3. Linux内核源码分析方法

    一.内核源码之我见 Linux内核代码的庞大令不少人“望而生畏”,也正因为如此,使得人们对Linux的了解仅处于泛泛的层次.如果想透析Linux,深入操作系统的本质,阅读内核源码是最有效的途径.我们都 ...

  4. Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7)

    http://blog.chinaunix.net/uid-20543672-id-3157283.html Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3 ...

  5. Linux内核源码分析 day01——内存寻址

    前言 Linux内核源码分析 Antz系统编写已经开始了内核部分了,在编写时同时也参考学习一点Linux内核知识. 自制Antz操作系统 一个自制的操作系统,Antz .半图形化半命令式系统,同时嵌入 ...

  6. 【转】Linux内核源码分析方法

    一.内核源码之我见 Linux内核代码的庞大令不少人“望而生畏”,也正因为如此,使得人们对Linux的了解仅处于泛泛的层次.如果想透析Linux,深入操作系统的本质,阅读内核源码是最有效的途径.我们都 ...

  7. Linux内核源码分析方法_转

    Linux内核源码分析方法 转自:http://www.cnblogs.com/fanzhidongyzby/archive/2013/03/20/2970624.html 一.内核源码之我见 Lin ...

  8. Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7)【转】

    原文地址:Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://bl ...

  9. Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7)【转】

    原文地址:Linux内核源码分析--内核启动之(4)Image内核启动(setup_arch函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.c ...

随机推荐

  1. linux 查看某一端口的占用情况

    查看某一端口的占用情况: lsof -i:端口号,例如查看端口21是否被占用 lsof -i: 实例:查看端口是否被占用,如果被占用结束掉该端口 [root@localhost splunk]# ls ...

  2. openfire开发

    openfire github地址:https://github.com/igniterealtime/Openfire 1.下载源代码:http://www.igniterealtime.org/d ...

  3. tcpdump抓SQL

    前言:假设如果有个服务器几十个链接突然达到上千个链接,show processlist,general_log,还有慢查询日志这些都不能用,你怎么把这些链接过来的SQL情况了解清楚,如果你觉得那些好用 ...

  4. Could not write to output file 'c:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\xx'

    1.清了C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files 2.给上述文件夹EveryOne和IIS_Use ...

  5. NFC(1)NFC简介,3种模式

    简介 NFC(Near Field Communication,近场通信),是一种数据传输技术.但与Wi-Fi.蓝牙.红外线等数据传输技术的一个主要差异就 是有效距离一般不能超过4厘米. NFC支持如 ...

  6. Generic Data Access Layer泛型的数据访问层

    http://www.codeproject.com/Articles/630277/Generic-Data-Access-Layer-GDA-Part-I http://www.codeproje ...

  7. 分解成3NF的保持函数依赖的分解算法:

    转换成3NF的保持函数依赖的分解算法: ρ={R1<U1,F1>,R2<U2,F2>,...,Rk<Uk,Fk>}是关系模式R<U,F>的一个分解,U= ...

  8. 进程间通信机制<转>

    1   文件映射 文件映射(Memory-Mapped Files)能使进程把文件内容当作进程地址区间一块内存那样来对待.因此,进程不必使用文件I/O操作,只需简单的指针操作就可读取和修改文件的内容. ...

  9. find-all-duplicates-in-an-array(典型的数组中的重复数,不错,我做出来了,可是发现别人有更好的做法)

    https://leetcode.com/problems/find-all-duplicates-in-an-array/ 典型的数组中的重复数.这次是通过跳转法,一个个跳转排查的.因为查过的不会重 ...

  10. POJ 1276 (多重背包) Cash Machine

    题意: 有n种纸币,已知每种纸币的面值和数量,求所能凑成的不超过cash的最大总面值. 分析: 这道题自己写了一下TLE了,好可耻.. 找了份比较简洁的代码抄过来了..poj1276 #include ...