`
kongweile
  • 浏览: 517341 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Linux 2.6.32的内核栈和用户空间栈关系

 
阅读更多

.进程的堆栈

内核在创建进程的时候,在创建task_struct的同事,会为进程创建相应的堆栈。每个进程会有两个栈,一个用户栈,存在于用户空间,一个内核栈,存在于内核空间。当进程在用户空间运行时,cpu堆栈指针寄存器里面的内容是用户堆栈地址,使用用户栈;当进程在内核空间时,cpu堆栈指针寄存器里面的内容是内核栈空间地址,使用内核栈。

2.进程用户栈和内核栈的切换

 

当进程因为中断或者系统调用而陷入内核态之行时,进程所使用的堆栈也要从用户栈转到内核栈。

进程陷入内核态后,先把用户态堆栈的地址保存在内核栈之中,然后设置堆栈指针寄存器的内容为内核栈的地址,这样就完成了用户栈向内核栈的转换;当进程从内核态恢复到用户态之行时,在内核态之行的最后将保存在内核栈里面的用户栈的地址恢复到堆栈指针寄存器即可。这样就实现了内核栈和用户栈的互转。

那么,我们知道从内核转到用户态时用户栈的地址是在陷入内核的时候保存在内核栈里面的,但是在陷入内核的时候,我们是如何知道内核栈的地址的呢?

关键在进程从用户态转到内核态的时候,进程的内核栈总是空的。这是因为,当进程在用户态运行时,使用的是用户栈,当进程陷入到内核态时,内核栈保存进程在内核态运行的相关信心,但是一旦进程返回到用户态后,内核栈中保存的信息无效,会全部恢复,因此每次进程从用户态陷入内核的时候得到的内核栈都是空的。所以在进程陷入内核的时候,直接把内核栈的栈顶地址给堆栈指针寄存器就可以了。

3.内核栈的实现

        内核栈在kernel-2.4和kernel-2.6里面的实现方式是不一样的。

 在kernel-2.4内核里面,内核栈的实现是:

 Union task_union {

                   Struct task_struct task;

                   Unsigned long stack[INIT_STACK_SIZE/sizeof(long)];

 };

 其中,INIT_STACK_SIZE的大小只能是8K。

 内核为每个进程分配task_struct结构体的时候,实际上分配两个连续的物理页面,底部用作task_struct结构体,结构上面的用作堆栈。使用current()宏能够访问当前正在运行的进程描述符。

 注意:这个时候task_struct结构是在内核栈里面的,内核栈的实际能用大小大概有7K。

 内核栈在kernel-2.6里面的实现是(kernel-2.6.32):

 Union thread_union {

                   Struct thread_info thread_info;

                   Unsigned long stack[THREAD_SIZE/sizeof(long)];

 };

 其中THREAD_SIZE的大小可以是4K,也可以是8K,thread_info占52bytes。

 当内核栈为8K时,Thread_info在这块内存的起始地址,内核栈从堆栈末端向下增长。所以此时,kernel-2.6中的current宏是需要更改的。要通过thread_info结构体中的task_struct域来获得于thread_info相关联的task。更详细的参考相应的current宏的实现。

 struct thread_info {

                   struct task_struct *task;

                   struct exec_domain *exec_domain;

                   __u32 flags;

        __u32 status;

                   __u32 cpu;

                   …  ..

 };

         注意:此时的task_struct结构体已经不在内核栈空间里面了。

4. 进程上下文

        当程序执行了系统调用或者触发某个异常而陷入内核空间,我们称内核代表进程执行并处于进程上下文环境,即进程切换现场就称为进程上下文,包含了一个进程所具有的全部信息,一般包括:进程控制块(PCB)、有关程序段和相应的数据集。

5. 进程控制块:

 进程控制块是进程在内存中的静态存在方式,linux用task_struct表示一个进程,那么进程的静态描述符必须保证一个进程在获得cpu并重新进入运行态时,能够精确的接着上次运行的位置继续运行,相关的程序段、数据以及CPU现场信息都要保存下来,cpu的现场信息主要包括内部寄存器和堆栈的基本数据。

 进程控制块一般可以分为:进程描述信息、进程控制信息、进程相关的资源信息和CPU现场信息保护机制。

 

6. 进程的切换

        当一个进程的时间片用完了,或者被抢占了,进程需要让出CPU给其他的进程来运行,内核就需要进行进程切换操作。

        在linux里面,显示的进行进程调度的函数是schedule()函数。Kernel-2.6.32在kernel/sched.c文件里面实现:

         Asmlinkage void __sched schedule(void)

 {

         Struct task_struct *prev,*next;

         Unsigned long *switch_count;

         Struct rq *rq;

         … …

 }

分享到:
评论

相关推荐

    linux2.6.32补丁

    "linux2.6.32补丁"指的是针对Linux内核2.6.32版本的更新文件,通常以.patch或.bz2等格式提供。这些补丁包含了对原始源代码的修改,用于解决安全问题、增加新功能或改进现有功能。在本例中,我们有两个补丁文件:...

    linux-headers-2.6.32-25元代码

    2.6.32版是Linux历史上的一个重要里程碑,它引入了许多优化和改进,使得内核更加稳定、高效。学习这个版本的内核,我们可以了解到以下关键知识点: 1. **进程管理**:Linux内核通过进程控制块(PCB)来管理和调度...

    深入理解linux内核1

    在实际操作中,Linux内核还包含许多其他重要组件,如虚拟文件系统、内存管理、进程调度、网络协议栈等。这些组件协同工作,使得Linux成为一个强大、稳定且灵活的操作系统,广泛应用于服务器、嵌入式设备和个人电脑。...

    linux内核学习.rar

    6. **网络协议栈**:Linux内核实现了完整的TCP/IP协议族,包括网络接口层、网络层、传输层和应用层,为各种网络服务提供底层支持。 7. **系统调用**:系统调用是用户空间程序与内核通信的桥梁,如open()用于打开...

    Linux学习心得——内存管理方法

    内核空间和用户空间之间的交互主要通过系统调用来完成,例如read、write等系统调用,它们允许用户空间进程与内核空间进行数据交换。 #### 6. Linux缺页处理 缺页处理是Linux内存管理中的一个重要概念,当进程尝试...

    嵌入式Linux开发教程_上册

    自1991年首次发布以来,Linux内核不断发展和完善,成为了全球范围内最为流行和广泛使用的开源操作系统内核之一。 **1.1.2 特点** Linux内核具有多个显著特点: - **开源免费**:Linux内核遵循GNU通用公共许可证...

    Linux kernel source code part 6

    《Linux内核源码解析 第六部分》是针对Linux内核2.6.32版本的一个深入学习资源,尤其适合那些对操作系统原理感兴趣的开发者和学习者。Linux内核是开源的操作系统核心,它负责管理系统的硬件资源,调度进程,确保多...

    嵌入式Linux开发教程 (上册) 周立功

    - **自定义能力强**:用户可以根据具体需求定制内核和用户空间的应用程序。 **1.3.2 嵌入式Linux的产品形态** 嵌入式Linux产品形态多样,主要包括: - **开发板**:用于开发和测试嵌入式系统的硬件平台。 - **软件...

    Linux kernel code part4

    Linux kernel 2.6.32 是一个相对较为旧但仍然具有研究价值的版本,对于理解操作系统原理和内核开发来说,是一个很好的学习材料。 在Linux内核源码中,你可以深入学习以下几个关键知识点: 1. **进程管理**:Linux...

    关于Linux线程的线程栈以及TLS

    本文描述LinuxNPTL的线程栈简要实现以及线程本地存储的原理,实验环境中Linux内核版本为2.6.32,glibc版本是2.12.1,Linux发行版为ubuntu,硬件平台为x86的32位系统。b.对于LinuxNPTL线程,有很多话题。本文挑选了...

    linux kernel 系列-1.rar

    此外,3.x版本还加强了安全特性,如内核地址空间布局随机化(KASLR)和内核自我保护项目(KSP)。 了解这些不同版本的内核源代码,开发者可以对比学习内核如何随时间发展和进化。比如,你可以研究从2.6到3.x版本中调度...

    嵌入式Linux开发教程 (上册 下册)

    自1991年首次发布以来,Linux内核不断发展和完善,已成为世界上最稳定且广泛使用的开源操作系统之一。 **1.1.2 特点** - **开放源代码:**Linux内核是完全开放源代码的,任何人都可以自由获取并修改其代码。 - **...

    基于X86裁剪小型linux系统.docx

    内核版本命名通常包含主版本号、次版本号和修订版本号,例如2.6.32。 **4. Linux内核版本命名** Linux内核版本命名系统反映了其发展和稳定性的状态。例如,偶数主版本号表示稳定版本,奇数主版本号则代表开发版本。...

    Fastsocket——Speed up your socket.pdf

    为了解决这个问题,人们尝试了各种方法,如硬件辅助(如NIC卸载功能),数据平面模式(如DPDK,需要自定义TCP/IP栈),以及修改Linux内核(如Linux上游项目)和应用程序代码(如Megapipe OSDI)。然而,这些方法要么...

Global site tag (gtag.js) - Google Analytics