文章目录
进程基本概念
1. 进程管理包括哪些内容
- 进程是怎么创建的?
- 进程控制块
- 进程的生命周期
- 进程切换,如何切换?
- 进程调度,如何调度?
- 多核调度,比较难?负载均衡?
2. linux4.0的task_struct
2.1 与进程相关的信息
- state: 用来记录进程的状态
- pid: 这个是进程唯一的进程标识符(Process Identifier)
- flag: 用来描述进程属性的一些标志位
- exit_code 和exit_signal :用来存放进程退出值和终止信号,这样父进程可以知道子进程的退出原因。
- pdeath_signal: 父进程消亡时发出的信号。
- comm: 存放可执行程序的名称。
- real_cred 和cred: 用来存放进程的一些认证信息。
2.2 与调度相关的信息
- **prio: ** 保存着进程的动态优先级,是调度类优先考虑的优先级。
- static_prio: 静态优先级。内核不存储nice值,取而代之的是static_prio。
- normal_prio: 基于static_prio和调度策略计算出来的优先级。
- rt_priority: 实时进程的优先级。
- sched_class: 调度类。
- se: 普通进程调度实体。
- rt: 试试进程调度实体。
- dl: deadline进程调度实体。
- policy: 进程的类型,比如普通进程还是实时进程。
- cpu_allowed: 进程可以在哪几个CPU上运行。
2.3 与进程之间的关系
- real_parent: 指向当前进程的父进程的task_struct数据结构。
- children: 指向当前进程的子进程的链表。
- sibling: 指向当前进程的兄弟进程的链表。
- group_leader: 进程组的组长。
2.4 与内存管理和文件管理相关信息
- mm: 指向进程所管理的内存的一个总的抽象的数据结构mm_struct。
- fs: 保存一个指向文件系统信息的指针。
- files: 保存一个指向进程的文件描述符表的指针。
2.5 task_struct总结
- 进程的运行状态
- 程序计数器
- CPU寄存器,保存上下文
- 内存管理信息
- 统计信息
- 文件相关的信息。
3. 进程的生命周期
3.1 进程状态
-
经典操作系统中进程状态图。
-
Linux内核里的进程状态
#define TASK_RUNNING 0 #define TASK_INTERRUPTIBLE 1 #define TASK_UNINTERRUPTIBLE 2 #define __TASK_STOPPED 4 #define __TASK_TRACED 8 /* in tsk->exit_state */ #define EXIT_DEAD 16 #define EXIT_ZOMBIE 32
-
TASK_RUNNING: 可执行的状态,但是不代表其正在运行。可能是在就绪队列中。所以在Linux中进程的就绪态和运行态是很模糊的,没有明确定义两个宏来表示。
-
TASK_INTERRUPTIBLE: 可中断睡眠状态。当进程等待某个资源时,进程会设置为TASK_INTERRUPTIBLE状态,当可用资源到来时,就设置为TASK_RUNNING状态。
-
TASK_UNINTERRUPTIBLE: 不可中断睡眠状态。当其他进程向其发送信号时,它是没有任何反应的。top、ps命令查看,其是D状态。
-
__TASK_STOPPED: 进程终止。
-
EXIT_DEAD: 进程消亡。
-
EXIT_ZOMBIE: 进程已经消亡了,但是task_struct结构体还没有释放。
-
3.2 进程状态设置
-
进程状态设置
p->state = TASK_RUNNING;
建议使用Linux提供的API:
#define set_task_state(tsk, state_value) \ do { \ (tsk)->task_state_change = _THIS_IP_; \ set_mb((tsk)->state, (state_value)); \ } while (0) #define set_current_state(state_value) \ set_mb(current->state, (state_value))
3.3 进程标识符ID
-
进程标识符PID(Process Identifier): 用来识别进程的唯一号码。
-
PID的类型是一个int类型,所以默认最大值是32768。
-
为了循环使用PID编号,内核使用bitmap机制来管理当前已经分配的PID编号和空闲的PID编号。
-
getpid()系统调用返回当前进程的tgid值,而不是线程的pid值。
-
系统调用gettid()会返回线程的PID。
tgid和pid区别
posix标准规定:在一个线程组里面,必须使用相同的pid。
所以给一个组里面发送信号,组里的所有线程都能收到。
3.4 系统第一个进程是怎么初始化的?
-
系统中第一个进程的名字有哪些
- 0号进程
- idle进程
- swapper进程
-
如何获取当前进程的task_struct数据结构?
-
简单的例子,用sp指针对齐8K,就可以获取struct task_struct结构体。
-
当前linux内核栈和task_struct之间的关系
为什么要把struct task_struct从 kernel stack中拧出来?
原因是struct thread_info大小是固定的,不会随着内核的发展而越来越大,但是struct task_struct结构体可能会越来越大,但是kernel 栈的空间确是固定的,所以留给内核栈的空间就比较多了。
-
linux内核中获取task_struct 的API,ARM64
register unsigned long current_stack_pointer asm ("sp"); static inline struct thread_info *current_thread_info(void) { return (struct thread_info *) (current_stack_pointer & ~(THREAD_SIZE - 1)); } #define get_current() (current_thread_info()->task) #define current get_current()
-
task_struct和struct thread_info的关系
- 在进程中常被访问的字段。
- thread_info与体系结构相关。
-