|
|
|
|
|
|
|
|
|
|
|
forget_original_parent()定义:linux/kernel/exit.c 673/* 674 * When we die, we re-parent all our children. 675 * Try to give them to another thread in our thread 676 * group, and if no such member exists, give it to 677 * the child reaper process (ie "init") in our pid 678 * space. 679 */ 680static void 681forget_original_parent(struct task_struct *father, struct list_head *to_release) 682{ 683 struct task_struct *p, *reaper = father; 684 struct list_head *_p, *_n; 685 686 do { 687 reaper = next_thread(reaper); 688 if (reaper == father) { 689 reaper = child_reaper(father); 690 break; 691 } 692 } while (reaper->exit_state); /**next_thread(reaper)找到当前线程组另一个线程。如果if判断条件不成立,找到新线程是孤儿进程新父亲 if条件成立,那么说明当前线程组没有其他线程,那么只有init为其父进程 694 /* 695 * There are only two places where our children can be: 696 * 697 * - in our child list 698 * - in our ptraced child list 699 * 700 * Search them and reparent children. 701 */ 702 list_for_each_safe(_p, _n, &father->children) { 703 int ptrace; 704 p = list_entry(_p, struct task_struct, sibling); 706 ptrace = p->ptrace; 707 708 /* if father isn't the real parent, then ptrace must be enabled */ /**当前退出的线程不是其真正的父亲,那么必然是被跟踪的进程.否则在系统日志打印错误。 709 BUG_ON(father != p->real_parent && !ptrace); /**如果当前退出进程是其真正的父亲,为退出进程的子进程设置新的父进程 711 if (father == p->real_parent) { 712 /* reparent with a reaper, real father it's us */ 713 choose_new_parent(p, reaper); 714 reparent_thread(p, father, 0); 715 } /**如果当前EXIT_ZOMEBIE状态.父进程关系发生了改变,则应该向新的父进程发送信号 else { 716 /* reparent ptraced task to its real parent */ /**本代码进程是跟踪即将退出的进程,被挂到退出进程的子链表上,后面详细解释. _ptrace_unlink(p)解除与退出进程的父子关系(因为本进程即将退出),并挂到生父进程的子链表中。 717 __ptrace_unlink (p); 718 if (p->exit_state == EXIT_ZOMBIE && p->exit_signal != -1 && 719 thread_group_empty(p)) 720 do_notify_parent(p, p->exit_signal); 721 } /**如果子进程为僵尸状态,且退出时不给父进程信号就将其收集起来,到时候统一退出处理 723 /* 724 * if the ptraced child is a zombie with exit_signal == -1 725 * we must collect it before we exit, or it will remain 726 * zombie forever since we prevented it from self-reap itself 727 * while it was being traced by us, to be able to see it in wait4. 728 */ 729 if (unlikely(ptrace && p->exit_state == EXIT_ZOMBIE && p->exit_signal == -1)) 730 list_add(&p->ptrace_list, to_release); 731 } /**为当前退出进程,跟踪子进程设置新的父亲 732 list_for_each_safe(_p, _n, &father->ptrace_children) { 733 p = list_entry(_p, struct task_struct, ptrace_list); 734 choose_new_parent(p, reaper); 735 reparent_thread(p, father, 1); 736 } 737} |
在694后续代码,主要遍历了子进程链表(father->children)和跟踪子进程链表(father->ptrace_children),给每个子进程设置 新的父进程。当一个进程被跟踪时,它被暂且设为调式进程的子进程。此时如果父进程退出,系统会为它们重新找到一个父进程。
对部分代码详细解释:
对BUG_ON定义: 23#ifndef HAVE_ARCH_BUG 24#define BUG() do { \ 25 printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __FUNCTION__); \ 26 panic("BUG!"); \ 27} while (0) 28#endif 30#ifndef HAVE_ARCH_BUG_ON 31#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while(0) |
作用:一些内核调用可以用来方便标记bug,提供断言并输出信息。最长用的两个是BUG()和BUG_ON()。当被调用的时候,它们会引发oops,导致栈的回溯和错误信息的打印。为什么这些声明会导致oops跟硬件的体系结构是相关的。大部分体系结构把BUG()和BUG_ON()定义成某种非法操作,这样自然会产生需要的oops。你可以把这些调用当作断言使用,想要断言某种情况不该发生: if (bad_thing) BUG(); 或者使用更好的形式: BUG_ON(bad_thing);
了解这个函数得区分几种子进程: 1 parent == real_parent 的子进程 这是本进程的子进程,并且没有被ptrace,处于本进程的children list上。 2 parent == father && parent != real_parent的子进程 被本进程ptrace的其它进程的子进程,处于本进程的children list上。 3 real_parent == father && parent != real_parent的子进程 本进程的子进程,但正在被其它进程ptrace,处于本进程的ptrace_children list上。 其中代码711~715和732~737对上述的(1)和(3)分别进程操作,设置其父进程为新找的父进程。 choose_new_parent()只是为子进程设置新的父亲,这个源代码很简单,看完我信心倍增。
注意:716~721是对第2种状态操作,和退出进程解除跟踪关系,将跟踪进程加入其生父进程。
|
|
|
|
|
|
|
|
|
|
|
|
|