在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. 对象的继承关系在数据库中的实现方式和PowerDesigner设计

    原文:对象的继承关系在数据库中的实现方式和PowerDesigner设计 在面向对象的编程中,使用对象的继承是一个非常普遍的做法,但是在关系数据库管理系统RDBMS中,使用的是外键表示实体(表)之间的 ...

  2. 1、Web容器的理解&Tomcat的安装与配置

    Web容器的理解 <Java Web开发实战经典——基础篇>一书中对Web容器这一概念阐述得很好,借用其观点对Web容器加以理解: 想要运行一个Java Web的程序,则必须有相应的Web ...

  3. BeanFactory 和 ApplicationContext

    Spring通过一个配置文件描述Bean及Bean直接的依赖关系,利用Java语言的反射功能实例化Bean并建立Bean之间的依赖关系.Sprig的IoC容器在完成这些底层工作的基础上,还提供了Bea ...

  4. openfire+spark+smack实现即时通讯

    近公司项目需要用到即时通讯功能,经过调研发现openfire+spark+smack可以实现.在网上找了很久,资料都十分有限,即使有些朋友实现了也说的不清不楚.于是决定自己研究,耗时一周的时间实现了文 ...

  5. 怎么在eclipse里调试WebDriver的源代码

    当你看完WebDriver的工作原理这篇博客以后,是不是也跃跃欲试想印证文章里的理论是不是正确,想自己也看下webdriver的源代码,并且调试下,通过代码来更深入的了解WebDriver的工作原理. ...

  6. Nginx+Tomcat+Memcached 集群

    写过一篇 Apache Httpd+Tomcat 的集群, 现在来看看Nginx+Tomcat+Memcached是怎么集群的. 先看看用的版本和工具: Nginx: nginx-1.8.1 Tomc ...

  7. mysql定时计划任务,ON COMPLETION [NOT] PRESERVE 当单次计划任务执行完毕后或当重复性的计划任务执行到了ENDS阶段。而声明PRESERVE的作用是使事件在执行完毕后不会被Drop掉

    当为on completion preserve 的时候,当event到期了,event会被disable,但是该event还是会存在当为on completion not preserve的时候,当 ...

  8. 国内顺利使用Google的另类技巧

    在特殊的地方和特殊的时间,流畅顺利使用Google的方法也会变得很特殊.本文不定期保持维护更新,删除不能用的,增加新的网址. 分享一些奇葩的Google使用方法,通过下列网址也可以使用Google来搜 ...

  9. crontab无法调用java的问题解决

    本来想将写的代码挂在crontab下运行,谁知道无法运行,没有任何输出,试着用ls -al >> 1.log试了一下,确定crontab是正常运行的. 从网站上找了下问题,原因出在cron ...

  10. bzoj2431: [HAOI2009]逆序对数列

    dp. f[i][j]表示放置第i个数有j个逆序对的方案数. s[i][j]维护前缀和(f[i][0]~f[i][j]). 状态转移方程 f[i][j]=s[i-1][j]-s[i-1][max(j- ...