task_struct
PCB(Process Control Block)相信学过操作系统的童鞋都知道这是进程控制块,是用来描述进程基本信息的数据结构
linux的PCB就是task_struct
重要属性:
1.进程状态
2.进程标识符
3.进程内核栈 thread_union联合体来表示进程的内核栈
1. union thread_union {
2. struct thread_info thread_info;
3. unsigned long stack[THREAD_SIZE/sizeof(long)];
4. };
4.标记
5.进程地址空间 mm_struct
mm指向进程所拥有的内存描述符,而active_mm指向进程运行时所使用的内存描述符。对于普通进程而言,这两个指针变量的值相同。但是,内核线程不拥有任何内存描述符,所以它们的mm成员总是为NULL。当内核线程得以运行时,它的active_mm成员被初始化为前一个运行进程的active_mm值
6.信号处理
其他
进程状态
https://www.cnblogs.com/diegodu/p/9167671.html D状态 进程各种状态
与TASK_INTERRUPTIBLE状态类似,进程处于睡眠状态,但是此刻进程是不可中断的。不可中断,指的并不是CPU不响应外部硬件的中断,而是指进程不响应异步信号。
绝大多数情况下,进程处在睡眠状态时,总是应该能够响应异步信号的。否则你将惊奇的发现,kill -9竟然杀不死一个正在睡眠的进程了!于是我们也很好理解,为什么ps命令看到的进程几乎不会出现TASK_UNINTERRUPTIBLE状态,而总是TASK_INTERRUPTIBLE状态。
而TASK_UNINTERRUPTIBLE状态不响应异步信号,只能等待特定信号将其唤醒;存在的意义就在于,内核的某些处理流程是不能被打断的;一般用于IO
Linux上下文切换过程
Linux上下文切换过程的分析
https://wiki.n.miui.com/pages/viewpage.action?pageId=139141809
如:发生中断时
1、关中断
2、将cpsr的值保存到目标模式的spsr中
3、通过修改cpsr的模式位,切换到目标模式。
4、将当前pc值加上一定偏移(0或4),写入到目标模式的lr中。
5、将pc值指向异常向量表
https://blog.csdn.net/maochengtao/article/details/45512039 (关键寄存器)
pc (program count程序计数器) 正在取码的指令,发生中断时,一般认为是正在执行的下一条指令;也就是返回继续执行的地址 r15
sp(stack pointer 堆栈指针) r13
lr(link register 连接寄存器) 发生中断时保存pc r14
cpsr 用于保存当前arm的处理模式
https://www.cnblogs.com/yanghaizhou/p/7705520.html
在linux内核中进程以及线程(多线程也是通过一组轻量级进程实现的)都是通过task_struct结构体来描述的,我们称它为进程描述符。而thread_info则是一个与进程描述符相关的小数据结构,它同进程的内核态栈stack存放在一个单独为进程分配的内存区域。由于这个内存区域同时保存了thread_info和stack,所以使用了联合体来定义,相关数据结构如下(基于4.4.87版本内核):
struct thread_info {
unsigned long flags; /* low level flags */
mm_segment_t addr_limit; /* address limit */
struct task_struct *task; /* main task structure */ int preempt_count; /* 0 => preemptable, <0 => bug */
int cpu; /* cpu */ };
这样设计的好处就是,得到stack,thread_info或task_struct任意一个数据结构的地址,就可以很快得到另外两个数据的地址
thread_info
https://blog.csdn.net/gatieme/article/details/51577479
内核还需要存储每个进程的PCB信息, linux内核是支持不同体系的的, 但是不同的体系结构可能进程需要存储的信息不尽相同, 这就需要我们实现一种通用的方式, 我们将体系结构相关的部分和无关的部门进行分离
用一种通用的方式来描述进程, 这就是struct task_struct, 而thread_info就保存了特定体系结构的汇编代码段需要访问的那部分进程的数据,我们在thread_info中嵌入指向task_struct的指针, 则我们可以很方便的通过thread_info来查找task_struct
thread_info是体系结构相关的
https://blog.csdn.net/zhuoxiuwu/article/details/77850724
mm_struct
mm_struct结构,每个进程都有自己独立的 mm_struct 结构(mm_struct内存描述符)
一个虚拟存储器空间包含以下内容
Text Segment、Data Segment、BBS
TextSegment 表示程序的代码段
DataSegment 表示 已经初始化且初值非0的全局变量和静态局部变量
BBS表示未初始化或初始值为0的全局变量和静态局部变量
操作系统负责这些段的加载并分配内存空间,这些段在编译期就分段完成。
Stack(栈)
栈:用于存放 局部变量、函数参数、函数返回地址
Heap(堆)
动态分配的内存,由用户自己管理和释放,堆的大小可以在运行时动态地拓展和收缩(C函数调用),
因为空闲地址空间时不连续的,堆在操作系统中是用链表来存储的。
Kernerl Space(内核空间)
内核空间 属于操作系统的一部分,常驻内存。操作系统不允许普通的用户应用程序读写这个区域的内容或者直接调用内核空间定义的函数。
虚拟存储器在内核中的结构图
进程与线程的区别
https://blog.csdn.net/freeelinux/article/details/53782986
线程仅仅被视为一个与其他进程共享某些资源的进程,而是否共享地址空间几乎是进程和 Linux 中所谓线程的唯一区别。线程创建的时候,加上了 CLONE_VM 标记,这样 线程的内存描述符 将直接指向 父进程的内存描述符
9. if (clone_flags & CLONE_VM) {
10. /*
11. * current 是父进程而 tsk 在 fork() 执行期间是共享子进程
12. */
13. atomic_inc(¤t->mm->mm_users);
14. tsk->mm = current->mm;
15. }
总结
1.task_struct 关键属性:状态,pid(唯一标识),进程内核栈(thread_info体系结构特有信息,stack内核栈,thread_info指向task_struct;三者知道一个,可以很方便的找到其他两个),内存描述符(mm_struct)->指向虚拟地址空间,包括(text代码段,data数据段,bbs,heap,mmap segment内存映射段,stack)
2.linux进程和线程的区别
线程仅仅被视为一个与其他进程共享某些资源的进程,而是否共享地址空间几乎是进程和 Linux 中所谓线程的唯一区别