白杰 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程
http://mooc.study.163.com/course/USTC-1000029000
一、理论分析
- 进程控制块PCB,OS中最重要的数据结构之一,存放OS用于描述进程情况及控制进程运行所需的全部信息。Linux内核中PCB是一个由task_struct定义的数据结构,定义在:
/include/linux/sched.h
中,主要包含以下内容:
- 进程状态
- 进程的内核堆栈
- 进程的标志位
- 运行队列
- 进程优先级
- 进程调度
- 进程链表
- 进程地址空间
- 进程内存管理
- 进程标识符
- 父子进程关系
- 进程间通信
- 进程切换
- 文件系统
- 其他信息
- 相关代码如下:
struct task_struct {
volatile long state;
void *stack;
atomic_t usage;
unsigned int flags;
unsigned int ptrace;
...
```
int on_rq;
int prio, static_prio, normal_prio;
unsigned int rt_priority;
const struct sched_class *sched_class;
struct sched_entity se;
struct sched_rt_entity rt;
...
...
struct list_head tasks;
struct mm_struct *mm, *active_mm;
...
...
pid_t pid;
pid_t tgid;
...
...
1337
1342 struct task_struct __rcu *real_parent;
1343 struct task_struct __rcu *parent;
1344
1347 struct list_head children;
1348 struct list_head sibling;
1349 struct task_struct *group_leader;
1350
1351
1356 struct list_head ptraced;
1357 struct list_head ptrace_entry;
1358
1359
1360 struct pid_link pids[PIDTYPE_MAX];
1361 struct list_head thread_group;
1362 struct list_head thread_node;
1363
1364 struct completion *vfork_done;
1365 int __user *set_child_tid;
1366 int __user *clear_child_tid;
1367
1368 cputime_t utime, stime, utimescaled, stimescaled;
1369 cputime_t gtime;
...
...
1411
1412 struct thread_struct thread;
1413
1414 struct fs_struct *fs;
1415
1416 struct files_struct *files;
1417
1418 struct nsproxy *nsproxy;
1419
1420 struct signal_struct *signal;
1421 struct sighand_struct *sighand;
1422
1423 sigset_t blocked, real_blocked;
1424 sigset_t saved_sigmask;
1425 struct sigpending pending;
1426
1427 unsigned long sas_ss_sp;
1428 size_t sas_ss_size;
1429 int (*notifier)(void *priv);
1430 void *notifier_data;
1431 sigset_t *notifier_mask;
1432 struct callback_head *task_works;
1433
1434 struct audit_context *audit_context;
1435 ...
...
1595
1598 struct pipe_inode_info *splice_pipe;
1599
1600 struct page_frag task_frag;
...
};
- 内核中进程的状态转换如下图:
在/include/linux/sched.h中定义了很多task的状态,主要的几个状态如下:
#define TASK_RUNNING 0
#define TASK_INTERRUPTIBLE 1
#define TASK_UNINTERRUPTIBLE 2
- 子进程的创建
fork, vfork和clone都是用户态用来创建一个子进程的系统调用,都是通过调用do_fork()来创建新进程的。
- 用户态中fork系统调用通过int 0x80陷入内核态,并保存现场。
- 执行do_fork()来创建子进程,过程如下:
- 复制一个PCB
- 分配一个新的内核堆栈
- 修改复制过来的数据,比如pid、进程链表、eip等
- 父进程从ISR中返回,恢复现场,IRET到fork的下一条代码执行