内核版本:2.6.32.60
linux信号传递阶段发生在异常/中断返回到用户态时;当内核由内核态返回到用户态时,如果有信号pending到当前进程,内核就将信号传递给进程并做信号处理
I.异常/中断返回
i.信号传递
由以下注释可以看出异常/中断或系统调用(特殊的中断)退出时,都会去检测pending的信号并做处理
/* arch/x86/kernel/entry_32.S */
6 /*
7 * entry.S contains the system-call and fault low-level handling routines.
8 * This also contains the timer-interrupt handler, as well as all interrupts
9 * and faults that can result in a task-switch.
10 *
11 * NOTE: This code handles signal-recognition, which happens every time
12 * after a timer-interrupt and after each system call.
42 */
ii.异常/中断返回
336 /*
337 * Return to user mode is not as complex as all this looks,
338 * but we want the default path for a system call return to
339 * go as quickly as possible which is why some of this is
340 * less clear than it otherwise should be.
341 */
342
343 # userspace resumption stub bypassing syscall exit tracing
344 ALIGN
345 RING0_PTREGS_FRAME
346 ret_from_exception:
347 preempt_stop(CLBR_ANY)
348 ret_from_intr:
349 GET_THREAD_INFO(%ebp)
350 check_userspace:
351 movl PT_EFLAGS(%esp), %eax # mix EFLAGS and CS
352 movb PT_CS(%esp), %al
353 andl $(X86_EFLAGS_VM | SEGMENT_RPL_MASK), %eax
354 cmpl $USER_RPL, %eax
355 jb resume_kernel # not returning to v8086 or userspace
356
357 ENTRY(resume_userspace)
358 LOCKDEP_SYS_EXIT
359 DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt
360 # setting need_resched or sigpending
361 # between sampling and the iret
362 TRACE_IRQS_OFF
363 movl TI_flags(%ebp), %ecx
364 andl $_TIF_WORK_MASK, %ecx # is there any work to be done on
365 # int/exception return?
366 jne work_pending
367 jmp restore_all
368 END(ret_from_exception)
由于异常/中断可以插入到中断(中断嵌套)、内核态、用户态的执行路径中,所以在异常/中断返回时要区别是返回到用户态还是内核态;
段寄存器的低两位bit0,bit1表示Requested Privilege Level (RPL),值范围0~3,即表示有4个级别,linux只用了0和3,分别表示内核态和用户态。
EFLAGS寄存器的第17位VM表示Virtual-8086 Mode
所以取出保存在内核堆栈中的被中断时的寄存器CS与EFLAGS,如果原执行流程是Virtual-8086 Mode或用户态,则做用户态恢复resume_userspace;否则做内核态恢复resume_kernel
返回用户态是,检测进程thread_info中的标识位,如果有pending的事件要做,调用work_pending去处理(主要就是处理信号);否则直接恢复寄存器、堆栈等后返回用户态,继续执行用户态指令
iii.系统调用
517 ENTRY(system_call)
518 RING0_INT_FRAME # can't unwind into user space anyway
519 pushl %eax # save orig_eax
520 CFI_ADJUST_CFA_OFFSET 4
521 SAVE_ALL
522 GET_THREAD_INFO(%ebp)
523 # system call tracing in operation / emulation
524 testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%ebp)
525 jnz syscall_trace_entry
526 cmpl $(nr_syscalls), %eax
527 jae syscall_badsys
528 syscall_call:
529 call *sys_call_table(,%eax,4)
530 movl %eax,PT_EAX(%esp) # store the return value
531 syscall_exit:
532 LOCKDEP_SYS_EXIT
533 DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt
534 # setting need_resched or sigpending
535 # between sampling and the iret
536 TRACE_IRQS_OFF
537 movl TI_flags(%ebp), %ecx
538 testl $_TIF_ALLWORK_MASK, %ecx # current->work
539 jne syscall_exit_work
540
541 restore_all:
684 syscall_exit_work:
685 testl $_TIF_WORK_SYSCALL_EXIT, %ecx
686 jz work_pending
687 TRACE_IRQS_ON
688 ENABLE_INTERRUPTS(CLBR_ANY) # could let syscall_trace_leave() call
689 # schedule() instead
690 movl %esp, %eax
691 call syscall_trace_leave
692 jmp resume_userspace
693 END(syscall_exit_work)
1.系统调用时,eax存放系统调用号,根据系统调用号去调用相应的系统服务例程
2.在系统调用退出时,会检测进程thread_info中的标识位,如果有pending的事件要做,调用work_pending去处理(主要就是处理信号);否则直接恢复寄存器、堆栈等后返回用户态,继续执行用户态指令
注:ENTRY(system_call)与ENTRY(interrupt)[common_interrupt]的区别,syscall会把eax即系统调用号压入堆栈中;后面会用内核堆栈中的该值(由syscall_get_nr取出)判断是否是系统调用由用户态切入内核态。
iv.work_pending
从上面可以看出不论是异常/中断或是系统调用返回到用户态都会调用work_pending,去做pending处理(主要就是处理信号)
101 #define resume_userspace_sig resume_userspace
623 # perform work that needs to be done immediately before resumption
624 ALIGN
625 RING0_PTREGS_FRAME # can't unwind into user space anyway
626 work_pending:
627 testb $_TIF_NEED_RESCHED, %cl
628 jz work_notifysig
629 work_resched:
630 call schedule
631 LOCKDEP_SYS_EXIT
632 DISABLE_INTERRUPTS(CLBR_ANY) # make sure we don't miss an interrupt
633 # setting need_resched or sigpending
634 # between sampling and the iret
635 TRACE_IRQS_OFF
636 movl TI_flags(%ebp), %ecx
637 andl $_TIF_WORK_MASK, %ecx # is there any work to be done other
638 # than syscall tracing?
639 jz restore_all
640 testb $_TIF_NEED_RESCHED, %cl
641 jnz work_resched
642
643 work_notifysig: # deal with pending signals and
644 # notify-resume requests
645 #ifdef CONFIG_VM86
646 testl $X86_EFLAGS_VM, PT_EFLAGS(%esp)
647 movl %esp, %eax
648 jne work_notifysig_v86 # returning to kernel-space or
649 # vm86-space
650 xorl %edx, %edx
651 call do_notify_resume
652 jmp resume_userspace_sig
653
654 ALIGN
655 work_notifysig_v86:
656 pushl %ecx # save ti_flags for do_notify_resume
657 CFI_ADJUST_CFA_OFFSET 4
658 call save_v86_state # %eax contains pt_regs pointer
659 popl %ecx
660 CFI_ADJUST_CFA_OFFSET -4
661 movl %eax, %esp
662 #else
663 movl %esp, %eax
664 #endif
665 xorl %edx, %edx
666 call do_notify_resume
667 jmp resume_userspace_sig
668 END(work_pending)
1.如果需要放弃CPU占用(_TIF_NEED_RESCHED标识),则去调度其它进程执行
2.如果不需要重新调度,则调用do_notify_resume去处理pending的工作
注意:
do_notify_resume返回时,会jmp resume_userspace_sig,即会再次去检查pending的工作是否做完,如果未做完会重复过程直到pending的工作做完为止。
对于信号来说,处理完一个信号,如果还有信号需要处理,则会继续去处理,直到pending队列中的信号处理完为止;在后面可以看到,在从队列中取出信号时,如果队列中还有信号则会将_TIF_SIGPENDING置位,在resume_userspace中会去检查
v.do_notify_resume
/* arch/x86/kernel/signal.c */
852 /*
853 * notification of userspace execution resumption
854 * - triggered by the TIF_WORK_MASK flags
855 */
856 void
857 do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
858 {
859 #ifdef CONFIG_X86_MCE
860 /* notify userspace of pending MCEs */
861 if (thread_info_flags & _TIF_MCE_NOTIFY)
862 mce_notify_process();
863 #endif /* CONFIG_X86_64 && CONFIG_X86_MCE */
864
865 /* deal with pending signal delivery */
866 if (thread_info_flags & _TIF_SIGPENDING)
867 do_signal(regs);
868
869 if (thread_info_flags & _TIF_NOTIFY_RESUME) {
870 clear_thread_flag(TIF_NOTIFY_RESUME);
871 tracehook_notify_resume(regs);
872 if (current->replacement_session_keyring)
873 key_replace_session_keyring();
874 }
875
876 #ifdef CONFIG_X86_32
877 clear_thread_flag(TIF_IRET);
878 #endif /* CONFIG_X86_32 */
879 }
如果有信号需要传递,_TIF_SIGPENDING置位(在信号发送时置位,见signal_wake_up函数),则调用do_signal去传递信号(调用相应的handler处理信号)
II.信号传递(处理)
/* arch/x86/kernel/signal.c */
773 /*
774 * Note that 'init' is a special process: it doesn't get signals it doesn't
775 * want to handle. Thus you cannot kill init even with a SIGKILL even by
776 * mistake.
777 */
778 static void do_signal(struct pt_regs *regs)
779 {
780 struct k_sigaction ka;
781 siginfo_t info;
782 int signr;
783 sigset_t *oldset;
784
785 /*
786 * We want the common case to go fast, which is why we may in certain
787 * cases get here from kernel mode. Just return without doing anything
788 * if so.
789 * X86_32: vm86 regs switched out by assembly code before reaching
790 * here, so testing against kernel CS suffices.
791 */
792 if (!user_mode(regs))
793 return;
794
795 if (current_thread_info()->status & TS_RESTORE_SIGMASK)
796 oldset = ¤t->saved_sigmask;
797 else
798 oldset = ¤t->blocked;
799
800 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
801 if (signr > 0) {
802 /*
803 * Re-enable any watchpoints before delivering the
804 * signal to user space. The processor register will
805 * have been cleared if the watchpoint triggered
806 * inside the kernel.
807 */
808 if (current->thread.debugreg7)
809 set_debugreg(current->thread.debugreg7, 7);
810
811 /* Whee! Actually deliver the signal. */
812 if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
813 /*
814 * A signal was successfully delivered; the saved
815 * sigmask will have been stored in the signal frame,
816 * and will be restored by sigreturn, so we can simply
817 * clear the TS_RESTORE_SIGMASK flag.
818 */
819 current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
820 }
821 return;
822 }
823
824 /* Did we come from a system call? */
825 if (syscall_get_nr(current, regs) >= 0) {
826 /* Restart the system call - no handlers present */
827 switch (syscall_get_error(current, regs)) {
828 case -ERESTARTNOHAND:
829 case -ERESTARTSYS:
830 case -ERESTARTNOINTR:
831 regs->ax = regs->orig_ax;
832 regs->ip -= 2;
833 break;
834
835 case -ERESTART_RESTARTBLOCK:
836 regs->ax = NR_restart_syscall;
837 regs->ip -= 2;
838 break;
839 }
840 }
841
842 /*
843 * If there's no signal to deliver, we just put the saved sigmask
844 * back.
845 */
846 if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
847 current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
848 sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
849 }
850 }
1.如果不是要返回用户态,直接返回
2.从信号pending队列中取出信号,如果信号可以由内核处理(如SIG_DFL,SIG_IGN),则内核直接处理掉,详细见下面的get_signal_to_deliver;如果信号要由用户态自定义的handler处理信号,则由handle_signal保存当前进程的运行环境,并准备信号处理handler的运行环境,当切回用户态后就去调用信号处理handler,处理完成后恢复进程的正常运行流程。
3.如果信号中断了系统调用,内核可以重启系统调用。信号是由内核处理还是用户进程提供的函数处理,重启系统调用的方式是不同的,因为内核处理不用切换到用户态中再处理信号。
4.内核处理的信号中断了系统调用,直接将原系统调用号regs->orig_ax或restart_syscall系统调用号赋值给ax,并将ip减2即可,因为int 0x80/sysenter均为两字节所以减2后ip指向了int/sysenter指令。此时ax是原系统调用号/restart_syscall(用于重启系统调用的系统调用),再次执行int/sysenter就能重启系统调用了
注:如果要处理多个pending信号,do_signal会进入多次,但是修改ip的值只会在第一次进入do_signal修改;因为系统调用的错误码放在regs->ax中,在修改ip时都会修改regs->ax为系统调用号,而该且是正数,而错误码都是负数,所以只会在第一次进入do_signal修改ip
ii.get_signal_to_deliver
/* kernel/signal.c */
1773 int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka,
1774 struct pt_regs *regs, void *cookie)
1775 {
1776 struct sighand_struct *sighand = current->sighand;
1777 struct signal_struct *signal = current->signal;
1778 int signr;
1779
1780 relock:
1781 /*
1782 * We'll jump back here after any time we were stopped in TASK_STOPPED.
1783 * While in TASK_STOPPED, we were considered "frozen enough".
1784 * Now that we woke up, it's crucial if we're supposed to be
1785 * frozen that we freeze now before running anything substantial.
1786 */
1787 try_to_freeze();
1788
1789 spin_lock_irq(&sighand->siglock);
1790 /*
1791 * Every stopped thread goes here after wakeup. Check to see if
1792 * we should notify the parent, prepare_signal(SIGCONT) encodes
1793 * the CLD_ si_code into SIGNAL_CLD_MASK bits.
1794 */
1795 if (unlikely(signal->flags & SIGNAL_CLD_MASK)) {
1796 int why = (signal->flags & SIGNAL_STOP_CONTINUED)
1797 ? CLD_CONTINUED : CLD_STOPPED;
1798 signal->flags &= ~SIGNAL_CLD_MASK;
1799
1800 why = tracehook_notify_jctl(why, CLD_CONTINUED);
1801 spin_unlock_irq(&sighand->siglock);
1802
1803 if (why) {
1804 read_lock(&tasklist_lock);
1805 do_notify_parent_cldstop(current->group_leader, why);
1806 read_unlock(&tasklist_lock);
1807 }
1808 goto relock;
1809 }
1810
1811 for (;;) {
1812 struct k_sigaction *ka;
1813
1814 if (unlikely(signal->group_stop_count > 0) &&
1815 do_signal_stop(0))
1816 goto relock;
1817
1818 /*
1819 * Tracing can induce an artifical signal and choose sigaction.
1820 * The return value in @signr determines the default action,
1821 * but @info->si_signo is the signal number we will report.
1822 */
1823 signr = tracehook_get_signal(current, regs, info, return_ka);
1824 if (unlikely(signr < 0))
1825 goto relock;
1826 if (unlikely(signr != 0))
1827 ka = return_ka;
1828 else {
1829 signr = dequeue_signal(current, ¤t->blocked,
1830 info);
1831
1832 if (!signr)
1833 break; /* will return 0 */
1834
1835 if (signr != SIGKILL) {
1836 signr = ptrace_signal(signr, info,
1837 regs, cookie);
1838 if (!signr)
1839 continue;
1840 }
1841
1842 ka = &sighand->action[signr-1];
1843 }
1844
1845 if (ka->sa.sa_handler == SIG_IGN) /* Do nothing. */
1846 continue;
1847 if (ka->sa.sa_handler != SIG_DFL) {
1848 /* Run the handler. */
1849 *return_ka = *ka;
1850
1851 if (ka->sa.sa_flags & SA_ONESHOT)
1852 ka->sa.sa_handler = SIG_DFL;
1853
1854 break; /* will return non-zero "signr" value */
1855 }
1856
1857 /*
1858 * Now we are doing the default action for this signal.
1859 */
1860 if (sig_kernel_ignore(signr)) /* Default is nothing. */
1861 continue;
1862
1863 /*
1864 * Global init gets no signals it doesn't want.
1865 * Container-init gets no signals it doesn't want from same
1866 * container.
1867 *
1868 * Note that if global/container-init sees a sig_kernel_only()
1869 * signal here, the signal must have been generated internally
1870 * or must have come from an ancestor namespace. In either
1871 * case, the signal cannot be dropped.
1872 */
1873 if (unlikely(signal->flags & SIGNAL_UNKILLABLE) &&
1874 !sig_kernel_only(signr))
1875 continue;
1876
1877 if (sig_kernel_stop(signr)) {
1878 /*
1879 * The default action is to stop all threads in
1880 * the thread group. The job control signals
1881 * do nothing in an orphaned pgrp, but SIGSTOP
1882 * always works. Note that siglock needs to be
1883 * dropped during the call to is_orphaned_pgrp()
1884 * because of lock ordering with tasklist_lock.
1885 * This allows an intervening SIGCONT to be posted.
1886 * We need to check for that and bail out if necessary.
1887 */
1888 if (signr != SIGSTOP) {
1889 spin_unlock_irq(&sighand->siglock);
1890
1891 /* signals can be posted during this window */
1892
1893 if (is_current_pgrp_orphaned())
1894 goto relock;
1895
1896 spin_lock_irq(&sighand->siglock);
1897 }
1898
1899 if (likely(do_signal_stop(info->si_signo))) {
1900 /* It released the siglock. */
1901 goto relock;
1902 }
1903
1904 /*
1905 * We didn't actually stop, due to a race
1906 * with SIGCONT or something like that.
1907 */
1908 continue;
1909 }
1910
1911 spin_unlock_irq(&sighand->siglock);
1912
1913 /*
1914 * Anything else is fatal, maybe with a core dump.
1915 */
1916 current->flags |= PF_SIGNALED;
1917
1918 if (sig_kernel_coredump(signr)) {
1919 if (print_fatal_signals)
1920 print_fatal_signal(regs, info->si_signo);
1921 /*
1922 * If it was able to dump core, this kills all
1923 * other threads in the group and synchronizes with
1924 * their demise. If we lost the race with another
1925 * thread getting here, it set group_exit_code
1926 * first and our do_group_exit call below will use
1927 * that value and ignore the one we pass it.
1928 */
1929 do_coredump(info->si_signo, info->si_signo, regs);
1930 }
1931
1932 /*
1933 * Death signals, no core dump.
1934 */
1935 do_group_exit(info->si_signo);
1936 /* NOTREACHED */
1937 }
1938 spin_unlock_irq(&sighand->siglock);
1939 return signr;
1940 }
1.获取sighand_struct/signal_struct保护锁
2.从进程私有/共享信号pending队列中取出信号
A.如果信号是可被忽略的SIG_IGN(显示忽略),走步骤2继续取信号
B.如果信号由用户进程处理,则返回信号编号及信号处理sighand,交由handle_signal处理
C.以下就是信号的默认处理
a.如果信号的默认行为是忽略,则走步骤2继续取信号
b.如果是暂停/继续类信号,则由do_signal_stop去暂停/继续进程执行
c.如果信号的默认行为是产生coredump,则去coredump当前进程
d.如果信号的默认行为是结束当前进程,则调用do_group_exit去结束当前进程
3.释放sighand_struct/signal_struct保护锁
III.用户自定义信号处理
i.handle_signal
/* arch/x86/kernel/signal.c */
690 static int
691 handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
692 sigset_t *oldset, struct pt_regs *regs)
693 {
694 int ret;
695
696 /* Are we from a system call? */
697 if (syscall_get_nr(current, regs) >= 0) {
698 /* If so, check system call restarting.. */
699 switch (syscall_get_error(current, regs)) {
700 case -ERESTART_RESTARTBLOCK:
701 case -ERESTARTNOHAND:
702 regs->ax = -EINTR;
703 break;
704
705 case -ERESTARTSYS:
706 if (!(ka->sa.sa_flags & SA_RESTART)) {
707 regs->ax = -EINTR;
708 break;
709 }
710 /* fallthrough */
711 case -ERESTARTNOINTR:
712 regs->ax = regs->orig_ax;
713 regs->ip -= 2;
714 break;
715 }
716 }
717
718 /*
719 * If TF is set due to a debugger (TIF_FORCED_TF), clear the TF
720 * flag so that register information in the sigcontext is correct.
721 */
722 if (unlikely(regs->flags & X86_EFLAGS_TF) &&
723 likely(test_and_clear_thread_flag(TIF_FORCED_TF)))
724 regs->flags &= ~X86_EFLAGS_TF;
725
726 ret = setup_rt_frame(sig, ka, info, oldset, regs);
727
728 if (ret)
729 return ret;
730
731 #ifdef CONFIG_X86_64
732 /*
733 * This has nothing to do with segment registers,
734 * despite the name. This magic affects uaccess.h
735 * macros' behavior. Reset it to the normal setting.
736 */
737 set_fs(USER_DS);
738 #endif
739
740 /*
741 * Clear the direction flag as per the ABI for function entry.
742 */
743 regs->flags &= ~X86_EFLAGS_DF;
744
745 /*
746 * Clear TF when entering the signal handler, but
747 * notify any tracer that was single-stepping it.
748 * The tracer may want to single-step inside the
749 * handler too.
750 */
751 regs->flags &= ~X86_EFLAGS_TF;
752
753 spin_lock_irq(¤t->sighand->siglock);
754 sigorsets(¤t->blocked, ¤t->blocked, &ka->sa.sa_mask);
755 if (!(ka->sa.sa_flags & SA_NODEFER))
756 sigaddset(¤t->blocked, sig);
757 recalc_sigpending();
758 spin_unlock_irq(¤t->sighand->siglock);
759
760 tracehook_signal_handler(sig, info, ka, regs,
761 test_thread_flag(TIF_SINGLESTEP));
762
763 return 0;
764 }
1.设置被中断的系统调用重启环境;ip只会修改一次见II.i
2.设置调用用户信号处理函数环境的堆栈帧
3.获取sighand_struct/signal_struct保护锁
4.recalc_sigpending重新计算是否需要继续处理后续信号,即设置/清空TIF_SIGPENDING标识
5.释放sighand_struct/signal_struct保护锁
ii.信号传递前后内核堆栈及用户堆栈变化情况
IV.信号默认处理
i.do_signal_stop
1661 /*
1662 * This performs the stopping for SIGSTOP and other stop signals.
1663 * We have to stop all threads in the thread group.
1664 * Returns nonzero if we've actually stopped and released the siglock.
1665 * Returns zero if we didn't stop and still hold the siglock.
1666 */
1667 static int do_signal_stop(int signr)
1668 {
1669 struct signal_struct *sig = current->signal;
1670 int notify;
1671
1672 if (!sig->group_stop_count) {
1673 struct task_struct *t;
1674
1675 if (!likely(sig->flags & SIGNAL_STOP_DEQUEUED) ||
1676 unlikely(signal_group_exit(sig)))
1677 return 0;
1678 /*
1679 * There is no group stop already in progress.
1680 * We must initiate one now.
1681 */
1682 sig->group_exit_code = signr;
1683
1684 sig->group_stop_count = 1;
1685 for (t = next_thread(current); t != current; t = next_thread(t))
1686 /*
1687 * Setting state to TASK_STOPPED for a group
1688 * stop is always done with the siglock held,
1689 * so this check has no races.
1690 */
1691 if (!(t->flags & PF_EXITING) &&
1692 !task_is_stopped_or_traced(t)) {
1693 sig->group_stop_count++;
1694 signal_wake_up(t, 0);
1695 }
1696 }
1697 /*
1698 * If there are no other threads in the group, or if there is
1699 * a group stop in progress and we are the last to stop, report
1700 * to the parent. When ptraced, every thread reports itself.
1701 */
1702 notify = sig->group_stop_count == 1 ? CLD_STOPPED : 0;
1703 notify = tracehook_notify_jctl(notify, CLD_STOPPED);
1704 /*
1705 * tracehook_notify_jctl() can drop and reacquire siglock, so
1706 * we keep ->group_stop_count != 0 before the call. If SIGCONT
1707 * or SIGKILL comes in between ->group_stop_count == 0.
1708 */
1709 if (sig->group_stop_count) {
1710 if (!--sig->group_stop_count)
1711 sig->flags = SIGNAL_STOP_STOPPED;
1712 current->exit_code = sig->group_exit_code;
1713 __set_current_state(TASK_STOPPED);
1714 }
1715 spin_unlock_irq(¤t->sighand->siglock);
1716
1717 if (notify) {
1718 read_lock(&tasklist_lock);
1719 do_notify_parent_cldstop(current, notify);
1720 read_unlock(&tasklist_lock);
1721 }
1722
1723 /* Now we don't run again until woken by SIGCONT or SIGKILL */
1724 do {
1725 schedule();
1726 } while (try_to_freeze());
1727
1728 tracehook_finish_jctl();
1729 current->exit_code = 0;
1730
1731 return 1;
1732 }
1.唤醒其它线程
2.如果线程暂停/继续,通过SIGCHLD信号通知主控线程,子线程状态已经改变
3.暂停该(轻量级)进程,直到收到SIGCONT/SIGKILL信号
ii.do_coredump
/* fs/exec.c */
1812 void do_coredump(long signr, int exit_code, struct pt_regs *regs)
1813 {
1985 }
产生coredump文件,coredump过程以后再分析
iii.do_group_exit
/* kernel/exit.c */
1058 /*
1059 * Take down every thread in the group. This is called by fatal signals
1060 * as well as by sys_exit_group (below).
1061 */
1062 NORET_TYPE void
1063 do_group_exit(int exit_code)
1064 {
1087 }
1088
1089 /*
1090 * this kills every thread in the thread group. Note that any externally
1091 * wait4()-ing process will get the correct exit code - even if this
1092 * thread is not the thread group leader.
1093 */
1094 SYSCALL_DEFINE1(exit_group, int, error_code)
1095 {
1096 do_group_exit((error_code & 0xff) << 8);
1097 /* NOTREACHED */
1098 return 0;
1099 }
与linux系统调用group_exit一致,即结束线程组:向其它线程发送SIGKILL信号结束线程组内的其它线程,调用do_exit退出本(轻量级)进程(与系统调用exit一致)。
exit实现以后再分析