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.信号传递(处理)
/* 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实现以后再分析
- linux signal传递(处理)
- Linux信号(Signal)处理
- linux signal 内核处理
- linux signal 处理机制
- linux signal 处理
- linux signal 处理
- linux signal 处理
- Linux下面signal处理
- Linux 信号处理signal
- linux signal 处理
- linux signal 处理
- Linux Signal 处理
- Linux信号signal处理机制
- Linux信号signal处理机制
- Linux 信号signal处理机制
- Linux信号signal处理机制
- Linux 信号signal处理机制
- Linux 信号signal处理机制
- spring配置连接数据库
- c语言实现封装,继承和多态
- 数据库知识总结
- 从关系型数据库到非关系型数据库
- R语言与回归分析学习笔记(bootstrap method)
- linux signal传递(处理)
- 决定
- JS拼图游戏
- 为什么项目开放源代码之后就变成死项目 很少或几乎不再更新
- 机器学习理论与实战(二)决策树
- UpdateWindow
- ext tree 异步加载取消自动加载功能。
- Java线程同步之一
- 快速读取进程内存