概述
不论是内核发送信号(硬件异常-SIGSEGV等、软件通知-SIGPIPE等、终端键-SIGINT等),还是用户进程发送信号(kill系统调用),都要由内核将信号记录到相应(轻量级)进程描述符中的信号相关结构中、唤醒被阻塞的目标进程等。
在信号发送阶段,内核将信号添加到信号pending队列中;在信号传递阶段,内核将信号从pending队列中取出,并处理(包括调用用户自定义处理、SIG_DFL默认处理、SIG_IGN忽略处理)。
注:linux内核无线程概念,线程的功能是由轻量级进程实现,以下线程均代表轻量级进程;线程组代表进程,包括只有主控线程的进程
I.signal发送函数
信号可以发送到线程、线程组、进程组
内核主要通过以下函数发送信号:
线程
sys_tkill/sys_tgkill:tkill/tgkill系统调用对应的内核服务
send_sig:发送信号到线程
force_sig:强制发送信号到线程;当目标进程忽略该信号时,将信号处理重置为SIG_DFL;当目标进程阻塞该信号时,将信号处理重置为SIG_DFL并清空阻塞mask中对应的信号位
线程组(进程)
sys_kill:kill系统调用对应的内核服务;当参数pid大于0时,会发送信号给线程组
group_send_sig_info:发送信号给某线程组
进程组
__kill_pgrp_info:发送信号给进程组内的所有线程组
以上函数的调用关系图如下:
信号发送到线程和线程组的区别主要是,将信号pending到私有信号pending队列还是共享信号pending队列;发送信号到进程组其实就是发送信号到进程组内的所有线程组
II.发送函数实现
由上图可知,所有的函数都会最终调用send_signal实现信号的发送
i.send_signal
/* kernel/signal.c */
916 static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
917 int group)
918 {
919 int from_ancestor_ns = 0;
920
921 #ifdef CONFIG_PID_NS
922 if (!is_si_special(info) && SI_FROMUSER(info) &&
923 task_pid_nr_ns(current, task_active_pid_ns(t)) <= 0)
924 from_ancestor_ns = 1;
925 #endif
926
927 return __send_signal(sig, info, t, group, from_ancestor_ns);
928 }
from_ancestor_ns置位必须满足以下所有条件:
1.siginfo不是特殊的信号信息,SEND_SIG_NOINFO,SEND_SIG_PRIV,SEND_SIG_FORCED
2.信号是从用户进程通过kill发出的
3.发送信号的进程current是上级pid命名空间的进程(即current不在下级pid命名空间中),接收方为下级pid命名空间的进程;由alloc_pid可以看出,下级pid命名空间分配进程id时,也会在所有上级分配一个id;比如有两级pid命名空间,上级的id有1、2...1023,下级id有1、2,当下级创建进程则会在下级分配3上级分配1024,即上级的1024与下级的3是同一进程,此时上级空间的2进程向下级空间2发送信号就叫from_ancestor_ns
注:由struct pid中numbers数组大小为1及alloc_pid处理可知目前内核版本(2.6.32.60)只支持一级pid命名空间,所以from_ancestor_ns恒等于0
send_signal会以from_ancestor_ns=0调用__send_signal
832 static int __send_signal(int sig, struct siginfo *info, struct task_struct *t,
833 int group, int from_ancestor_ns)
834 {
835 struct sigpending *pending;
836 struct sigqueue *q;
837 int override_rlimit;
838
839 trace_sched_signal_send(sig, t);
840
841 assert_spin_locked(&t->sighand->siglock);
842
843 if (!prepare_signal(sig, t, from_ancestor_ns))
844 return 0;
845
846 pending = group ? &t->signal->shared_pending : &t->pending;
847 /*
848 * Short-circuit ignored signals and support queuing
849 * exactly one non-rt signal, so that we can get more
850 * detailed information about the cause of the signal.
851 */
852 if (legacy_queue(pending, sig))
853 return 0;
854 /*
855 * fast-pathed signals for kernel-internal things like SIGSTOP
856 * or SIGKILL.
857 */
858 if (info == SEND_SIG_FORCED)
859 goto out_set;
860
861 /* Real-time signals must be queued if sent by sigqueue, or
862 some other real-time mechanism. It is implementation
863 defined whether kill() does so. We attempt to do so, on
864 the principle of least surprise, but since kill is not
865 allowed to fail with EAGAIN when low on memory we just
866 make sure at least one signal gets delivered and don't
867 pass on the info struct. */
868
869 if (sig < SIGRTMIN)
870 override_rlimit = (is_si_special(info) || info->si_code >= 0);
871 else
872 override_rlimit = 0;
873
874 q = __sigqueue_alloc(t, GFP_ATOMIC | __GFP_NOTRACK_FALSE_POSITIVE,
875 override_rlimit);
876 if (q) {
877 list_add_tail(&q->list, &pending->list);
878 switch ((unsigned long) info) {
879 case (unsigned long) SEND_SIG_NOINFO:
880 q->info.si_signo = sig;
881 q->info.si_errno = 0;
882 q->info.si_code = SI_USER;
883 q->info.si_pid = task_tgid_nr_ns(current,
884 task_active_pid_ns(t));
885 q->info.si_uid = current_uid();
886 break;
887 case (unsigned long) SEND_SIG_PRIV:
888 q->info.si_signo = sig;
889 q->info.si_errno = 0;
890 q->info.si_code = SI_KERNEL;
891 q->info.si_pid = 0;
892 q->info.si_uid = 0;
893 break;
894 default:
895 copy_siginfo(&q->info, info);
896 if (from_ancestor_ns)
897 q->info.si_pid = 0;
898 break;
899 }
900 } else if (!is_si_special(info)) {
901 if (sig >= SIGRTMIN && info->si_code != SI_USER)
902 /*
903 * Queue overflow, abort. We may abort if the signal was rt
904 * and sent by user using something other than kill().
905 */
906 return -EAGAIN;
907 }
908
909 out_set:
910 signalfd_notify(t, sig);
911 sigaddset(&pending->signal, sig);
912 complete_signal(sig, t, group);
913 return 0;
914 }
1.信号预处理;处理stop(SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOUT)和continue(SIGCONT)信号;并判断信号是否需要发送,不需要发送直接返回
2.根据信号目标是线程还是线程组,取线程私有信号pending队列或线程组共享信号pending队列
3.如果是非实时信号,且pending队列中已经有该信号,则不需再将该信号添加到信号pending队列,直接返回成功
4.如果是特殊原因产生的信号,或内核/kill发出的信号,则分配sigqueue时可以超过用户pending信号资源限制;否则,pending信号超限,则sigqueue分配失败
5.初始化sigqueue的siginfo信息,并将sigqueue排入信号pending队列
6.signalfd_notify唤醒信号的等待队列;linux可以使用signalfd系统调用来创建用于接收信号的文件描述符,当没有信号而去read该描述符时进程就会被阻塞,并将阻塞进程添加到信号的等待列队中,所以出现信号时就唤醒该队列的阻塞进程;详细代码见fs/signalfd.c
7.将信号添加到信号pending位图中
8.查找处理该信号的(轻量级)进程,并唤醒
ii.prepare_signal
信号预处理
633 /*
634 * Handle magic process-wide effects of stop/continue signals. Unlike
635 * the signal actions, these happen immediately at signal-generation
636 * time regardless of blocking, ignoring, or handling. This does the
637 * actual continuing for SIGCONT, but not the actual stopping for stop
638 * signals. The process stop is done as a signal action for SIG_DFL.
639 *
640 * Returns true if the signal should be actually delivered, otherwise
641 * it should be dropped.
642 */
643 static int prepare_signal(int sig, struct task_struct *p, int from_ancestor_ns)
644 {
645 struct signal_struct *signal = p->signal;
646 struct task_struct *t;
647
648 if (unlikely(signal->flags & SIGNAL_GROUP_EXIT)) {
649 /*
650 * The process is in the middle of dying, nothing to do.
651 */
652 } else if (sig_kernel_stop(sig)) {
653 /*
654 * This is a stop signal. Remove SIGCONT from all queues.
655 */
656 rm_from_queue(sigmask(SIGCONT), &signal->shared_pending);
657 t = p;
658 do {
659 rm_from_queue(sigmask(SIGCONT), &t->pending);
660 } while_each_thread(p, t);
661 } else if (sig == SIGCONT) {
662 unsigned int why;
663 /*
664 * Remove all stop signals from all queues,
665 * and wake all threads.
666 */
667 rm_from_queue(SIG_KERNEL_STOP_MASK, &signal->shared_pending);
668 t = p;
669 do {
670 unsigned int state;
671 rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending);
672 /*
673 * If there is a handler for SIGCONT, we must make
674 * sure that no thread returns to user mode before
675 * we post the signal, in case it was the only
676 * thread eligible to run the signal handler--then
677 * it must not do anything between resuming and
678 * running the handler. With the TIF_SIGPENDING
679 * flag set, the thread will pause and acquire the
680 * siglock that we hold now and until we've queued
681 * the pending signal.
682 *
683 * Wake up the stopped thread _after_ setting
684 * TIF_SIGPENDING
685 */
686 state = __TASK_STOPPED;
687 if (sig_user_defined(t, SIGCONT) && !sigismember(&t->blocked, SIGCONT)) {
688 set_tsk_thread_flag(t, TIF_SIGPENDING);
689 state |= TASK_INTERRUPTIBLE;
690 }
691 wake_up_state(t, state);
692 } while_each_thread(p, t);
693
694 /*
695 * Notify the parent with CLD_CONTINUED if we were stopped.
696 *
697 * If we were in the middle of a group stop, we pretend it
698 * was already finished, and then continued. Since SIGCHLD
699 * doesn't queue we report only CLD_STOPPED, as if the next
700 * CLD_CONTINUED was dropped.
701 */
702 why = 0;
703 if (signal->flags & SIGNAL_STOP_STOPPED)
704 why |= SIGNAL_CLD_CONTINUED;
705 else if (signal->group_stop_count)
706 why |= SIGNAL_CLD_STOPPED;
707
708 if (why) {
709 /*
710 * The first thread which returns from do_signal_stop()
711 * will take ->siglock, notice SIGNAL_CLD_MASK, and
712 * notify its parent. See get_signal_to_deliver().
713 */
714 signal->flags = why | SIGNAL_STOP_CONTINUED;
715 signal->group_stop_count = 0;
716 signal->group_exit_code = 0;
717 } else {
718 /*
719 * We are not stopped, but there could be a stop
720 * signal in the middle of being processed after
721 * being removed from the queue. Clear that too.
722 */
723 signal->flags &= ~SIGNAL_STOP_DEQUEUED;
724 }
725 }
726
727 return !sig_ignored(p, sig, from_ancestor_ns);
728 }
1.预处理信号,主要处理暂停信号和继续信号
A.进程正在退出,不处理暂停信号和继续信号
B.如果是暂停信号(SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOUT),则删除共享和私有信号pending队列中的SIGCONT信号
C.如果是继续信号(SIGCONT)
a.删除共享和私有信号pending队列中的暂停信号
b.如果用户处理SIGCONT(即SIGCONT的处理不是SIG_IGN,SIG_DFL)且未阻塞SIGCONT,则唤醒线程
c.唤醒暂停的线程
2.判断该信号是否需要发送,需要发送返回1,不需要发送返回0
70 static int sig_ignored(struct task_struct *t, int sig, int from_ancestor_ns)
71 {
72 /*
73 * Blocked signals are never ignored, since the
74 * signal handler may change by the time it is
75 * unblocked.
76 */
77 if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig))
78 return 0;
79
80 if (!sig_task_ignored(t, sig, from_ancestor_ns))
81 return 0;
82
83 /*
84 * Tracers may want to know about even ignored signals.
85 */
86 return !tracehook_consider_ignored_signal(t, sig);
87 }
1.如果信号是阻塞的,则不能忽略,需要发送
2.如果信号不可忽略(显示的忽略SIG_IGN,或默认行为SIG_DFL是忽略),需要发送
3.如果进程被跟踪,则信号不能忽略,需要发送
iii.complete_signal
查找处理信号的线程
751 static void complete_signal(int sig, struct task_struct *p, int group)
752 {
753 struct signal_struct *signal = p->signal;
754 struct task_struct *t;
755
756 /*
757 * Now find a thread we can wake up to take the signal off the queue.
758 *
759 * If the main thread wants the signal, it gets first crack.
760 * Probably the least surprising to the average bear.
761 */
762 if (wants_signal(sig, p))
763 t = p;
764 else if (!group || thread_group_empty(p))
765 /*
766 * There is just one thread and it does not need to be woken.
767 * It will dequeue unblocked signals before it runs again.
768 */
769 return;
770 else {
771 /*
772 * Otherwise try to find a suitable thread.
773 */
774 t = signal->curr_target;
775 while (!wants_signal(sig, t)) {
776 t = next_thread(t);
777 if (t == signal->curr_target)
778 /*
779 * No thread needs to be woken.
780 * Any eligible threads will see
781 * the signal in the queue soon.
782 */
783 return;
784 }
785 signal->curr_target = t;
786 }
787
788 /*
789 * Found a killable thread. If the signal will be fatal,
790 * then start taking the whole group down immediately.
791 */
792 if (sig_fatal(p, sig) &&
793 !(signal->flags & (SIGNAL_UNKILLABLE | SIGNAL_GROUP_EXIT)) &&
794 !sigismember(&t->real_blocked, sig) &&
795 (sig == SIGKILL ||
796 !tracehook_consider_fatal_signal(t, sig))) {
797 /*
798 * This signal will be fatal to the whole group.
799 */
800 if (!sig_kernel_coredump(sig)) {
801 /*
802 * Start a group exit and wake everybody up.
803 * This way we don't have other threads
804 * running and doing things after a slower
805 * thread has the fatal signal pending.
806 */
807 signal->flags = SIGNAL_GROUP_EXIT;
808 signal->group_exit_code = sig;
809 signal->group_stop_count = 0;
810 t = p;
811 do {
812 sigaddset(&t->pending.signal, SIGKILL);
813 signal_wake_up(t, 1);
814 } while_each_thread(p, t);
815 return;
816 }
817 }
818
819 /*
820 * The signal is already in the shared-pending queue.
821 * Tell the chosen thread to wake up and dequeue it.
822 */
823 signal_wake_up(t, sig == SIGKILL);
824 return;
825 }
1.查找接收信号的线程:
A.如果目标线程接收信号,则由其接收信号。
B.如果目标线程不接收信号
a.信号不是发往线程组的,或者是发往线程组但是线程组只有主线程,则暂不决定由哪个线程接收信号
b.否则,表示信号是发往线程组的,且线程组不只有主线程;查找出接收信号的线程
2.如果信号处理是SIG_DFL且默认行为是结束,并且信号未被阻塞,则结束线程组内所有的线程
3.唤醒接收信号的线程,并设置TIF_SIGPENDING标识,以便在返回用户态时内核将信号传递给该线程
(轻量级)进程可接收信号
730 /*
731 * Test if P wants to take SIG. After we've checked all threads with this,
732 * it's equivalent to finding no threads not blocking SIG. Any threads not
733 * blocking SIG were ruled out because they are not running and already
734 * have pending signals. Such threads will dequeue from the shared queue
735 * as soon as they're available, so putting the signal on the shared queue
736 * will be equivalent to sending it to one such thread.
737 */
738 static inline int wants_signal(int sig, struct task_struct *p)
739 {
740 if (sigismember(&p->blocked, sig))
741 return 0;
742 if (p->flags & PF_EXITING)
743 return 0;
744 if (sig == SIGKILL)
745 return 1;
746 if (task_is_stopped_or_traced(p))
747 return 0;
748 return task_curr(p) || !signal_pending(p);
749 }
(轻量级)进程是否接收信号
1.信号被阻塞,不会接收信号
2.正在退出,不会接收信号
3.信号是SIGKILL,接收信号
4.(轻量级)进程停止或被跟踪,不会接收信号
5.(轻量级)进程未占用CPU且已有信号pending,不会接收信号
最后
以上就是纯情老师为你收集整理的linux signal产生(发送)的全部内容,希望文章能够帮你解决linux signal产生(发送)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复