《linux 内核分析》 第6周 进程创建及描述
王一+ 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
一、task_struct
操作系统的三大核心功能:1、进程管理 2、内存管理 3、 文件系统
摘抄task_struct,并注释
//进程状态
1236 volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */
//进程的内核堆栈
1237 void *stack;
1238 atomic_t usage;
//每个进程的状态
1239 unsigned int flags; /* per process flags, defined below */
1240 unsigned int ptrace;
1241
1251 int on_rq;
1252 //进程调度相关代码
1253 int prio, static_prio, normal_prio;
1254 unsigned int rt_priority;
1255 const struct sched_class *sched_class;
1256 struct sched_entity se;
1257 struct sched_rt_entity rt;
1258#ifdef CONFIG_CGROUP_SCHED
1259 struct task_group *sched_task_group;
1260#endif
1261 struct sched_dl_entity dl;
1262
1263#ifdef CONFIG_PREEMPT_NOTIFIERS
1264 /* list of struct preempt_notifier: */
1265 struct hlist_head preempt_notifiers;
1266#endif
1290
1291#if defined(CONFIG_SCHEDSTATS) || defined(CONFIG_TASK_DELAY_ACCT)
1292 struct sched_info sched_info;
1293#endif
1294 //进程的链表
1295 struct list_head tasks;
1300//进程虚拟内存地址相关代码
1301 struct mm_struct *mm, *active_mm;
1302#ifdef CONFIG_COMPAT_BRK
1303 unsigned brk_randomized:1;
1304#endif
1305 /* per-thread vma caching */
1306 u32 vmacache_seqnum;
1307 struct vm_area_struct *vmacache[VMACACHE_SIZE];
1308#if defined(SPLIT_RSS_COUNTING)
1309 struct task_rss_stat rss_stat;
1310#endif
1311 //任务状态及信号相关状态
1312 int exit_state;
1313 int exit_code, exit_signal;
1314 int pdeath_signal; /* The signal sent when the parent dies */
1315 unsigned int jobctl; /* JOBCTL_*, siglock protected */
1316
1317 /* Used for emulating ABI behavior of previous Linux versions */
1318 unsigned int personality;
1319
1320 unsigned in_execve:1; /* Tell the LSMs that the process is doing an
1321 * execve */
1322 unsigned in_iowait:1;
1323
1324 /* Revert to default priority/policy when forking */
1325 unsigned sched_reset_on_fork:1;
1326 unsigned sched_contributes_to_load:1;
1327
1328 unsigned long atomic_flags; /* Flags needing atomic access. */
1329// 进程标示符
1330 pid_t pid;
1331 pid_t tgid;
1332
1337 /*
1338 * pointers to (original) parent process, youngest child, younger sibling,
1339 * older sibling, respectively. (p->father can be replaced with
1340 * p->real_parent->pid)
1341 */
1342 struct task_struct __rcu *real_parent; /* real parent process */
1343 struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */
//进程树有关
1344 /*
1345 * children/sibling forms the list of my natural children
1346 */
1347 struct list_head children; /* list of my children */
1348 struct list_head sibling; /* linkage in my parent's children list */
1349 struct task_struct *group_leader; /* threadgroup leader */
1350
1351 /*
1352 * ptraced is the list of tasks this task is using ptrace on.
1353 * This includes both natural children and PTRACE_ATTACH targets.
1354 * p->ptrace_entry is p's link on the p->parent->ptraced list.
1355 */
1356 struct list_head ptraced;
1357 struct list_head ptrace_entry;
1358
1359 /* PID/PID hash table linkage. */
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; /* for vfork() */
1365 int __user *set_child_tid; /* CLONE_CHILD_SETTID */
1366 int __user *clear_child_tid; /* CLONE_CHILD_CLEARTID
1411 //这个任务的cpu相关的数据
1412 struct thread_struct thread;
1413/* filesystem information */
1414 struct fs_struct *fs;
1415/* open file information */
1416 struct files_struct *files;
1417/* namespaces */
1418 struct nsproxy *nsproxy;
1419/* signal handlers */
1420 struct signal_struct *signal;
1421 struct sighand_struct *sighand;
1487/* journalling filesystem info */
1488 void *journal_info;
1489//块设备信息链表
1490/* stacked block device info */
1491 struct bio_list *bio_list;
1492
1493#ifdef CONFIG_BLOCK
1494/* stack plugging */
1495 struct blk_plug *plug;
1496#endif
进程的状态切换过程:
进程树和相互的关系:
进程的内核堆栈和thread_info的关系:
进程堆栈和thread_info使用一个空间,通过使用union的方式来定义,他们的地址开始于2^13的地址,分两个page(8k);
这样就可以通过esp来获取thread_info的地址:
__asm__(
"andl %%esp,%0; "
:
"=r"
(ti) :
"0"
(~(THREAD_SIZE - 1)));//通过屏蔽esp低13位,返回ti
二、进程的创建
进程的创建
1、创建线程需要调用通过调用fork系统调用,实现创建子进程,子进程在内核态创建之后,在内核态运行,而父线程返回到主线程运行。
子线程是在ret_from_fork之后执行。
2、、fork创建的过程分析
1)、在此系统中系统调用fork实际上是调用sys_clone,它和其他的两个系统调用都是调用的do_fork();
2)、在do_fork中调用copy_process()来进行进程的复制和修改;
p = copy_process(clone_flags, stack_start, stack_size,
child_tidptr, NULL, trace);
3)、在copy_process()中调用dup_task_struct()来实现创建task_struct空间,thread_info和内核堆栈的空间,并且复制task_struct和thread_infgo;
arch_dup_task_struct(tsk, orig);//复制task_struct;
setup_thread_stack(tsk, orig);//复制thread_info;
4)、在copy_process 中对子线程的task_struct进行设置,然后将复制进程信息。在copy_thread 中将sp和ip指向内核堆栈中的sp和ip,
struct pt_regs *childregs = task_pt_regs(p);
struct pt_regs {
unsigned long bx;
unsigned long cx;
unsigned long dx;
unsigned long si;
unsigned long di;
unsigned long bp;
unsigned long ax;// 系统调用号和参数
unsigned long ds;
unsigned long es;
unsigned long fs;
unsigned long gs;
unsigned long orig_ax; //原来的系统的寄存器保存
unsigned long ip;
unsigned long cs;
unsigned long flags; //本部分为系统自动存储的信息
unsigned long sp;
unsigned long ss;
};
p->thread.sp = (unsigned long) childregs;
p->thread.ip = (unsigned long) ret_from_fork;
5)、ENTRY(ret_from_fork) 中jmp syscall_exit(在系统调用system_call中);
retoreALL;iret,返回到用户态;
三)实验调试、
电脑出现问题,无法调试,使用source insight 查看代码: