1、进程的概念
进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
2、轻量级进程
轻量级进程由clone()系统调用创建,参数是CLONE_VM,即与父进程是共享进程地址空间和系统资源。轻量级进程有自己独立的用户空间栈和内核空间栈,并且可以被linux操作系统像普通进程一样被调度。
3、线程的概念
linux系统中用户线程就是轻量级进程,因为用户线程就是由轻量级进程实现的。
4、进程的内存分布
可执行程序文件必须被加载到内存中才能真正跑起来,程序被加载到内存中如上图所示,标注出来的地址是虚拟地址,也就是用户空间为低位的3G,内核空间为高位的1G。
.text区域:存放的是程序的代码段,该区域只读
.data区域:存放的是已经初始化的静态或全局变量
.bss区域:存放的是未初始化的静态或全局变量
heap区域:程序中的堆,程序中动态申请的内存就是在这个区域,会向上增长
map区域:加载的动态库等会映射到这个区域,那么这个区域会不会被heap或者stack覆盖呢,有可能,但是系统会做好处理的。
stack区域:程序中的栈,程序执行过程中的函数调用相关的信息或者局部变量会放在这个区域,会向下增长。
heap和stack都加了随机偏移,这样做的目的是为了安全吧,增加被攻击的难度。
5、线程的内存分布
根据上面的了解我们知道线程(轻量级进程)有自己独立的用户空间栈和内核空间栈,所以在内存分布多了独立的栈,.text,.data,.bss和heap是共享的,包括打开的文件描述符等。用户的空间栈大小默认是 8M,内核空间栈大小是 8k。
6、内核栈
linux-4.10/arch/arm/include/asm/thread_info.h
/*
46 * low level task data that entry.S needs immediate access to.
47 * __switch_to() assumes cpu_context follows immediately after cpu_domain.
48 */
49 struct thread_info {
50 unsigned long flags; /* low level flags */
51 int preempt_count; /* 0 => preemptable, <0 => bug */
52 mm_segment_t addr_limit; /* address limit */
53 struct task_struct *task; /* main task structure */
54 __u32 cpu; /* cpu */
55 __u32 cpu_domain; /* cpu domain */
56 struct cpu_context_save cpu_context; /* cpu context */
57 __u32 syscall; /* syscall number */
58 __u8 used_cp[16]; /* thread used copro */
59 unsigned long tp_value[2]; /* TLS registers */
60 #ifdef CONFIG_CRUNCH
61 struct crunch_state crunchstate;
62 #endif
63 union fp_state fpstate __attribute__((aligned(8)));
64 union vfp_state vfpstate;
65 #ifdef CONFIG_ARM_THUMBEE
66 unsigned long thumbee_state; /* ThumbEE Handler Base register */
67 #endif
68 };
linux-4.10/include/linux/sched.h
struct task_struct {
1512 #ifdef CONFIG_THREAD_INFO_IN_TASK
1513 /*
1514 * For reasons of header soup (see current_thread_info()), this
1515 * must be the first element of task_struct.
1516 */
1517 struct thread_info thread_info;
1518 #endif
1519 volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
1520 void *stack;
1521 atomic_t usage;
1522 unsigned int flags; /* per process flags, defined below */
1523 unsigned int ptrace;
1524
1525 #ifdef CONFIG_SMP
1526 struct llist_node wake_entry;
1527 int on_cpu;
1528 #ifdef CONFIG_THREAD_INFO_IN_TASK
1529 unsigned int cpu; /* current CPU */
1530 #endif
1531 unsigned int wakee_flips;
1532 unsigned long wakee_flip_decay_ts;
1533 struct task_struct *last_wakee;
...
2009 };
task_sturce 就是进程(轻量级进程)对应的数据结构,linux kernel就是通过它来调度对应的进程。创建内核栈的时候会把thread_info 结构体放在栈底,使用栈的时候是从栈顶开始,往下增长。thread_info中的task指向对应的task_struct结构体,而task_stuct结构体中的stack是指向栈底的指针。