linux signal传递(处理)

来源:互联网 发布:telnet无法连接端口 编辑:程序博客网 时间:2024/05/22 04:53

内核版本: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 resumption854  * - triggered by the TIF_WORK_MASK flags855  */856 void857 do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)858 {859 #ifdef CONFIG_X86_MCE860         /* 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_32877         clear_thread_flag(TIF_IRET);878 #endif /* CONFIG_X86_32 */879 }

如果有信号需要传递,_TIF_SIGPENDING置位(在信号发送时置位,见signal_wake_up函数),则调用do_signal去传递信号(调用相应的handler处理信号)

 


II.信号传递(处理)

i.do_signal
/* arch/x86/kernel/signal.c */773 /*774  * Note that 'init' is a special process: it doesn't get signals it doesn't775  * want to handle. Thus you cannot kill init even with a SIGKILL even by776  * 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 certain787          * cases get here from kernel mode. Just return without doing anything788          * if so.789          * X86_32: vm86 regs switched out by assembly code before reaching790          * 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         else798                 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 the804                  * signal to user space. The processor register will805                  * have been cleared if the watchpoint triggered806                  * 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 saved815                          * sigmask will have been stored in the signal frame,816                          * and will be restored by sigreturn, so we can simply817                          * 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 sigmask844          * 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 be1785          * 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 if1792          * we should notify the parent, prepare_signal(SIGCONT) encodes1793          * 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 same1866                  * container.1867                  *1868                  * Note that if global/container-init sees a sig_kernel_only()1869                  * signal here, the signal must have been generated internally1870                  * or must have come from an ancestor namespace. In either1871                  * 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 in1880                          * the thread group.  The job control signals1881                          * do nothing in an orphaned pgrp, but SIGSTOP1882                          * always works.  Note that siglock needs to be1883                          * 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 race1906                          * 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 all1923                          * other threads in the group and synchronizes with1924                          * their demise.  If we lost the race with another1925                          * thread getting here, it set group_exit_code1926                          * first and our do_group_exit call below will use1927                          * 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 int691 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 TF720          * 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_64732         /*733          * This has nothing to do with segment registers,734          * despite the name.  This magic affects uaccess.h735          * macros' behavior.  Reset it to the normal setting.736          */737         set_fs(USER_DS);738 #endif739 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, but747          * notify any tracer that was single-stepping it.748          * The tracer may want to single-step inside the749          * 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 group1688                          * 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 is1699          * a group stop in progress and we are the last to stop, report1700          * 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, so1706          * we keep ->group_stop_count != 0 before the call. If SIGCONT1707          * 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 signals1060  * as well as by sys_exit_group (below).1061  */1062 NORET_TYPE void1063 do_group_exit(int exit_code)1064 {1087 }1088 1089 /*1090  * this kills every thread in the thread group. Note that any externally1091  * wait4()-ing process will get the correct exit code - even if this1092  * 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实现以后再分析





原创粉丝点击