linux signal产生(发送)

不论是内核发送信号(硬件异常-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:发送信号给进程组内的所有线程组

以上函数的调用关系图如下:
linux signal产生(发送)_第1张图片


信号发送到线程和线程组的区别主要是,将信号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产生(发送))