linux内核—进程栈线程栈

进程栈:

进程用户空间的管理在task_struct 的mm_struct *mm成员中体现, mm中的成员定义了用户空间的布局情况如图一。 用户空间的栈起始于STACK_TOP, 如果设置了PF_RANDOMIZE,则起始点会减少一个小的随机量,每个体系结构都必须定义STACK_TOP, 大多数都设置为TASK_SIZE, 在32位机上该值为0XC0000000。经过随机处理后,进程栈的起始地址将存放在mm->start_stack中,可以通过cat /proc/xxx/stat 查看。
  如图,栈从上而下扩展,而用于内存映射的区域起始于mm->mmap_base,mm->mmap_base通过调用mmap_base函数来初始化,为了确保栈不与mmap区域不发生冲突,两者之间设置了一个安全间隙。
在这里插入图片描述

线程栈:

线程包含了表示进程内执行环境必需的信息,其中包括进程中标示线程的线程ID,一组寄存器值,栈,调度优先级和策略,信号屏蔽字,errno变量以及线程私有数据。进程的所有信息对该进程的所有线程都是共享的,包括可执行的程序文本,程序的全局内存和堆内存,栈以及文件描述符,所以线程的mm_struct *mm指针变量和所属进程的mm指针变量相同。
  在创建线程的时候,可以通过pthread_attr_t来初始化线程的属性,包括线程的栈布局信息,如栈起始地址stackaddr,栈大小stacksize。可以通过pthread_attr_setguardsize初始化线程栈末尾之后用以避免栈溢出的缓冲区的大小,如果应用程序溢出到此缓冲区中,这个错误可能会导致 SIGSEGV 信号被发送给该线程, 从而造成段错误,缓冲区默认设置为PAGESIZE个字节。因为线程的mm->start_stack和所属进程相同,所以线程栈的起始地址并没有存放在task_struct中,应该只是使用attr中的stackaddr,来初始化task_struct->thread-> sp(sp指向struct pt_regs对象,该结构体用于保存用户进程或者线程的寄存器现场)。

总结

线程栈的空间开辟在所属进程的堆区,线程与其所属的进程共享进程的用户空间,所以线程栈之间可以互访。线程栈的起始地址和大小存放在pthread_attr_t 中,栈的大小并不是用来判断栈是否越界,而是用来初始化避免栈溢出的缓冲区的大小(或者说安全间隙的大小)
ulimit -s可以查看线程栈大小;进程栈一般要比线程栈大2M左右,不是固定值

猜你喜欢

转载自blog.csdn.net/chengcheng1024/article/details/114685788