linux的进程与线程,task_struct结构体

linux 的进程与线程在源码中都对应到同一个结构体task_struct, 它位于include/linux/sched.h中, 他有很多很多成员, 下面我们分析一下主要成员及其作用。

1. 任务列表

有了任务列表, 操作系统就能知道当前任务的下一个任务和上一个任务了。
为什么是双向链表呢?因为可以高效的删除, 并且可以反向遍历。
至于为什么不是数组? 因为要频繁的创建删除, 数组咋行呢。

struct list_head tasks; // 双向链表, 维护任务列表

2. 任务ID

这里的pid_t类型是一个int, 为什么有一个pid还需要有一个tgid呢, 这是因为进程和线程在操作系统眼里都是一个task_struct, 但是总归要区分不是, pid就是这个task_struct的id, tgid则是这个task_struct所属于的group id。
换言之:

  • task_struct是进程, pid == tgid
  • task_struct是线程, pid != tgid
    那为什么需要一个group_leader呢?可以注意到它是一个指针, 自然是为了快速访问这个task_struct的老大了!
pid_t pid; // process ID
pid_t tgid; // thread group ID
struct task_struct *group_leader;

3. 信号处理

上面提到,一个task_struct是有leader的,当操作系统要给一个小组发信号,当然是要发给leader,再由leader转发给小组的每个人,那这些信号是怎么处理的呢?
这里定义了哪些信号被阻塞暂不处理(blocked),哪些信号尚等待处理(pending),哪些信号正在通过信号处理函数进行处理(sighand)。处理的结果可以是忽略,可以是结束进程等等。
这里real_blocked在kvm_main文件和signal文件的do_sigtimedwait里都用到了,但是具体作用没理解...
信号处理函数默认使用用户态的函数栈,当然也可以开辟新的栈专门用于信号处理,这就是 sas_ss_xxx 这三个变量的作用。

/* Signal handlers: */
struct signal_struct		*signal;
struct sighand_struct __rcu		*sighand;
sigset_t			blocked;
sigset_t			real_blocked;
/* Restored if set_restore_sigmask() was used: */
sigset_t			saved_sigmask;
struct sigpending		pending;
unsigned long			sas_ss_sp;
size_t				sas_ss_size;
unsigned int			sas_ss_flags;

4. 任务状态

主要是由 task->state 和 task->exit_state 两块组成,他们都是一个个bit,定义如下:

/*
 * Task state bitmask. NOTE! These bits are also
 * encoded in fs/proc/array.c: get_task_state().
 *
 * We have two separate sets of flags: task->state
 * is about runnability, while task->exit_state are
 * about the task exiting. Confusing, but this way
 * modifying one set can't modify the other one by
 * mistake.
 */

/* Used in tsk->state: */
#define TASK_RUNNING			0x00000000
#define TASK_INTERRUPTIBLE		0x00000001
#define TASK_UNINTERRUPTIBLE		0x00000002
#define __TASK_STOPPED			0x00000004
#define __TASK_TRACED			0x00000008
/* Used in tsk->exit_state: */
#define EXIT_DEAD			0x00000010
#define EXIT_ZOMBIE			0x00000020
#define EXIT_TRACE			(EXIT_ZOMBIE | EXIT_DEAD)
/* Used in tsk->state again: */
#define TASK_PARKED			0x00000040
#define TASK_DEAD			0x00000080
#define TASK_WAKEKILL			0x00000100
#define TASK_WAKING			0x00000200
#define TASK_NOLOAD			0x00000400
#define TASK_NEW			0x00000800
#define TASK_RTLOCK_WAIT		0x00001000
#define TASK_FREEZABLE			0x00002000
#define __TASK_FREEZABLE_UNSAFE	       (0x00004000 * IS_ENABLED(CONFIG_LOCKDEP))
#define TASK_FROZEN			0x00008000
#define TASK_STATE_MAX			0x00010000

#define TASK_ANY			(TASK_STATE_MAX-1)

/*
 * DO NOT ADD ANY NEW USERS !
 */
#define TASK_FREEZABLE_UNSAFE		(TASK_FREEZABLE | __TASK_FREEZABLE_UNSAFE)

/* Convenience macros for the sake of set_current_state: */
#define TASK_KILLABLE			(TASK_WAKEKILL | TASK_UNINTERRUPTIBLE)
#define TASK_STOPPED			(TASK_WAKEKILL | __TASK_STOPPED)
#define TASK_TRACED			__TASK_TRACED

#define TASK_IDLE			(TASK_UNINTERRUPTIBLE | TASK_NOLOAD)

/* Convenience macros for the sake of wake_up(): */
#define TASK_NORMAL			(TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)

/* get_task_state(): */
#define TASK_REPORT			(TASK_RUNNING | TASK_INTERRUPTIBLE | \
					 TASK_UNINTERRUPTIBLE | __TASK_STOPPED | \
					 __TASK_TRACED | EXIT_DEAD | EXIT_ZOMBIE | \
					 TASK_PARKED)

#define task_is_running(task)		(READ_ONCE((task)->__state) == TASK_RUNNING)

#define task_is_traced(task)		((READ_ONCE(task->jobctl) & JOBCTL_TRACED) != 0)
#define task_is_stopped(task)		((READ_ONCE(task->jobctl) & JOBCTL_STOPPED) != 0)
#define task_is_stopped_or_traced(task)	((READ_ONCE(task->jobctl) & (JOBCTL_STOPPED | JOBCTL_TRACED)) != 0)

贴一张极客时间里图:

5. 进程调度

调度有很多策略,这里写不下,我们先简单知道task_struct里有进程调度的策略、优先级等信息


//是否在运行队列上
int        on_rq;
//优先级
int        prio;
int        static_prio;
int        normal_prio;
unsigned int      rt_priority;
//调度器类
const struct sched_class  *sched_class;
//调度实体
struct sched_entity    se;
struct sched_rt_entity    rt;
struct sched_dl_entity    dl;
//调度策略
unsigned int      policy;
//可以使用哪些CPU
int        nr_cpus_allowed;
cpumask_t      cpus_allowed;
struct sched_info    sched_info;

6. 运行统计

u64        utime; //用户态消耗的CPU时间
u64        stime; //内核态消耗的CPU时间
unsigned long      nvcsw; //自愿(voluntary)上下文切换计数
unsigned long      nivcsw; //非自愿(involuntary)上下文切换计数
u64        start_time; //进程启动时间,不包含睡眠时间
u64        real_start_time; //进程启动时间,包含睡眠时间

7. 进程亲缘关系

通常情况下,real_parent 和 parent 是一样的,但是也会有另外的情况存在。例如,bash 创建一个进程,那进程的 parent 和 real_parent 就都是 bash。如果在 bash 上使用 GDB 来 debug 一个进程,这个时候 GDB 是 parent,bash 是这个进程的 real_parent。
这里会发现怎么有group_leader?上面不是说过了吗?
其实group_leader和parent是俩概念,group_leader是小组领导,如果系统发送一个信号,领导要分发出去,但是这个领导可不一定是parent:

举个例子
假如有一个shell进程(pid=100),启动了两个进程A(pid=200)和B(pid=300),这两个进程又都分别fork了子进程C(pid=201)和D(pid=301)
那么A和C就是一组,B和D是一组。A的group_leader是A,但是A的parent是shell

/*
 * Pointers to the (original) parent process, youngest child, younger sibling,
 * older sibling, respectively.  (p->father can be replaced with
 * p->real_parent->pid)
*/

/* Real parent process: */
struct task_struct __rcu	*real_parent;

/* Recipient of SIGCHLD, wait4() reports: */
struct task_struct __rcu	*parent;

/*
 * Children/sibling form the list of natural children:
*/
struct list_head		children;
struct list_head		sibling;
struct task_struct		*group_leader;

8. 进程权限

/* Process credentials: */

/* Tracer's credentials at attach: */
const struct cred __rcu		*ptracer_cred;

/* Objective and real subjective task credentials (COW): */
const struct cred __rcu		*real_cred;

/* Effective (overridable) subjective task credentials (COW): */
const struct cred __rcu		*cred;

9. 内存管理

内存布局很复杂,需要专门讲一下

struct mm_struct                *mm;
struct mm_struct                *active_mm;

10. 文件系统

/* Filesystem information: */
struct fs_struct		*fs;

/* Open file information: */
struct files_struct		*files;

11. 内核栈

存储了这样一个指针,它指向了内核栈的地址,内核栈的最高地址存储的是pt_regs(存储了寄存器变量),最低地址是thread_info,thread_info是针对不同cpu有不同的信息

#ifdef CONFIG_THREAD_INFO_IN_TASK
/*
 * For reasons of header soup (see current_thread_info()), this
 * must be the first element of task_struct.
 */
struct thread_info		thread_info;
#endif
void				*stack;
posted @ 2023-04-27 10:52  miyanyan  阅读(385)  评论(0编辑  收藏  举报