用户空间编程实例如下,在处理这个signal的时候会执行应用程序的转存

软件调节和测量检验本事(2)– coredump怎样贯彻

前段时间在工作中掌握到利用软件在崩溃的时候能够安装生成转存文件,这么些效应便是coredump。不论是应用程序崩溃如故kernel崩溃转存功用都是很实用技能。本文是想从落实原理角度来明白这两项技能达成方式。首先分析一下应用程序coredump的完毕格局。

什么标准触发转存
这一个转存发生在应用程序收到致命的signal,在管理这一个signal的时候会实践应用程序的转存,并在以往退出执行。有点要求小心,要是用户给那几个致命signal安装了自定义的handler,转存是不会生出的。OK,那么这里总括出两点:
1,致命signal会出发转存爆发,这几个signal富含如下内容。

  1. 398 #define SIG_KERNEL_COREDUMP_MASK(\
  2. 399 rt_sigmask(SIGQUIT)|rt_sigmask(SIGILL)|\
  3. 400 rt_sigmask(SIGTRAP)|rt_sigmask(SIGABRT)|\
  4. 401 rt_sigmask(SIGFPE)|rt_sigmask(SIGSEGV)|\
  5. 402 rt_sigmask(SIGBUS)|rt_sigmask(SIGSYS)|\
  6. 403 rt_sigmask(SIGXCPU)|rt_sigmask(SIGXFSZ)|\
  7. 404 SIGEMT_MASK

2,要是上边的沉重signal被用户设置了自定义的管理函数,coredump也不会生出。

  1. 2264if(ka->sa.sa_handler!=SIG_DFL){
  2. 2265/*Run the handler.*/
  3. 2266 ksig->ka=*ka;
  4. 2267
  5. 2268if(ka->sa.sa_flags&SA_ONESHOT)
  6. 2269 ka->sa.sa_handler=SIG_DFL;
  7. 2270
  8. 2271 break;/*will return non-zero”signr”value*/
  9. 2272}

在kernel查找须要处理的signal的时候,首先会推断这几个signal是还是不是暗中同意管理格局,若是是私下认可管理才会继续推行到coredump分支,不然跳出查找环节,实践用户自定义处理方式。

触发coredump执行的支行

  1. 2335if(sig_kernel_coredump(signr)){
  2. 2336if(print_fatal_signals)
  3. 2337 print_fatal_signal(ksig->info.si_signo);
  4. 2338 proc_coredump_connector(current);
  5. 2339/*
  6. 2340*Ifit was abletodump core,this kills all
  7. 2341*other threadsinthe groupandsynchronizes with
  8. 2342*their demise.Ifwe lost the race with another
  9. 2343*thread getting here,itsetgroup_exit_code
  10. 2344*firstandour do_group_exitcallbelow will use
  11. 2345*that valueandignore the one we pass it.
  12. 2346*/
  13. 2347 do_coredump(&ksig->info);
  14. 2348}

将沉重signal打字与印刷到调整台的Tips
假设你敞开如下proc目录下的option,将拉开打字与印刷致命signal到调节台的功用。
/proc/sys/kernel/print-fatal-signals

coredump首要步骤
实际少将这一个应用程序都写入到磁盘的进度确定是非常担任的。这里本身不会扣没二个细节,有一部分原理性的底细恐怕推到前边的一些再详尽学习和深入分析。不过,这里大家需求掌握如下多少个有关coredump的严重性管理流程。
1,
coredump之间,首先要检查线程组中持有线程是否现已都跻身到了休眠状态。大家要coredump必须有限支撑我们在拷贝那几个进度的内部存款和储蓄器空间的时候经过中的有个别线程还在运作并改写内部存款和储蓄器空间。
2,
对于直接将经过内部存款和储蓄器转存到文件的情状,未有啥特别之处,正是展开二个文本,并初始写入。
3,对于制订了用户空间脚本,实行局地滑坡操作的意况,这里会运营二个用户态进程,并在kernel和用户态进度之间创立一个管道,
kernel=========读出===========用户态进度(压缩)———–写入——–>文件

对于第一步管理,kernel想经过组中全数的线程发送kill
signal复信号,然后等待全部进程都不处于运增势况。
对于第二步,管理相对简便易行,只是自此假如风乐趣还可深入钻研一下coredump文件的格式到底是哪些体统的。
其三步,相对比较复杂,相比玄妙的地点正是在kernel中国建工业总会公司立了一条管道,kernel处理signal部分将coredump写入管道,而新建的进程中管道的另外一端被安装到了正规化输入上边。

对于减弱进度转存的艺术
我们得以兴建二个shell实行文书
#!/bin/sh
execgzip->/root/$1.core.$2.gz
然后在/proc/sys/kernel/core_pattern 中写入
|/usr/sbin/core_helper%e%p

coredump怎么样完结前段时间在职业中通晓到应用程式在崩溃的时候能够安装生成转存文件,那一个职能便是coredump。不论是应用…

转自:

Linux模拟信号机制概述

Linux编程,非能量信号是一个令人爱恨交加又不得不提的三个领域。方今自己凑集学习了Linux的signal相关的剧情,分享出来,也为防止投机忘记。
   
复信号的本质是异步。异步一以此词,听着高级大气上等级次序,又令人云山雾绕,其则不然。其实大家考虑,我们以此世界是异步的,每种人干事儿,并不三回九转A->B->C->D这种。比方笔者在英特网买了东西,作者其实并不知道快递何时能到。小编只怕在集团内部,在喝水,在回寄邮资件,在查bug,在写代码,遽然收到了快递小哥的电话,注意那正是能量信号的delivery。由于快递的过来,笔者只得停下笔者手下的体力劳动,去签收快递。那正是风传中的标准的异步。笔者不知晓快递小哥何时给自身电话,不过笔者接受电话就去签收,那是本身的时域信号管理函数。越来越高端一点,即使自己在列席第一的集会,小编只怕须要掩饰快递小哥的对讲机(倘使作者精通其电话),这一度是linux下实信号的高端应用(sigprocmask)了。
   
实信号是一种机制,是在软件等级次序对中断机制的一种模拟,内核让某经过意识到某非常专门的学业产生了。强迫进度去推行相应的能量信号管理函数。至于频限信号的来源于也许出自硬件如按下键盘只怕硬件故障(如ctrl+c发送SIGINT),可财富于别的进度(kill,sigqueue),可资源于自身进度(raise)。 
   
实信号的精神是一种进程间的通讯,二个经过能够向另三个经过发送非复信号,至少传递了signo这一个int值。实际上,通信的内容,能够远不只有是signo,能够通过SA_SIGINFO标识位公告进程去取额外的消息。
   
笔者痛恨片汤话儿,但是上边一大坨片汤话儿,却真真的道出了实信号的本质。
   
后边也波及了,signal是个令人爱恨交加的feature,原因在于沉重的历史包袱。下边笔者将一一道来。
   
在上古时期,UNIX就已经有了signal那一个feature,但是及时的signal存在多少个难题:
   1
守旧的连续信号管理函数是一回性的,而非永远性的。

   
linux为了向下包容,依旧达成了那些有弱点的signal系统调用。你可看到signal系统调用的基础代码中有SA_ONESHOT这几个标识位。

 

  1. #ifdef __ARCH_WANT_SYS_SIGNAL

  2. /*

  3.  * For
    backwards compatibility. Functionality
    superseded by sigaction.

  4.  */

  5. SYSCALL_DEFINE2(signal, int, sig,
    __sighandler_t, handler)

  6. {

  7.     struct k_sigaction new_sa, old_sa;

  8.     int ret;

  9.     new_sa.sa.sa_handler =
    handler;

  10.     new_sa.sa.sa_flags =
    SA_ONESHOT | SA_NOMASK;

  11.     sigemptyset(&new_sa.sa.sa_mask);

  12.     ret = do_sigaction(sig,
    &new_sa, &old_sa);

  13.     return ret ? ret : (unsigned
    long)old_sa.sa.sa_handler;

  14. }

  15. #endif /* __ARCH_WANT_SYS_SIGNAL */

还是先看看Linux中用户空间怎么选用的,用户空间编制程序实举个例子下:

   
这个SA_ONESHOT标志位,等同于SA_RESETHAND标志:在arch/x86/include/uapi/asm/signal.h中有:

#include<signal.h>

  1. #define SA_ONESHOT    SA_RESETHAND

#include<stdio.h>

   
数字信号发生,到非确定性信号管理函数初步执行,中间断定是一时间差的。内核起始初叶迫使过程对时限信号作出响应,那叫作功率信号的传递。也便是说时域信号发生,内核只是在进度描述符记录了一笔,该进度收到信号X一枚,并未马上强迫进程对时域信号作出响应。已经发生但未曾传递的数字信号叫挂起能量信号。对于非实时来说,时限信号不排队,位图占个位就可以。对于实时随机信号,则排队,同一实信号也有多个挂起时域信号。那几个十分少说,后边自然关系。

#include<unistd.h>

    图片 1
   
上海教室反映了基石怎么样传递确定性信号。基本正是采取三个挂起复信号,然后管理二个时限信号。get_signal_to_deliver
是在进度中甄选三个复信号来handle。代码在kernel/signal.c,个中有如下code:

/*上边为八个新的确定性信号操作函数*/

  1.         if (ka->sa.sa_handler ==
    SIG_IGN) /* Do nothing. */

  2.             continue;

  3.         if (ka->sa.sa_handler !=
    SIG_DFL) {

  4.             /* Run the handler. */

  5.             *return_ka = *ka;

  6.             if (ka->sa.sa_flags &
    SA_ONESHOT)

  7.                 ka->sa.sa_handler =
    SIG_DFL;

  8.             break; /* will
    return non-zero “signr” value */

  9.         }

       
    大家看来了linux也落到实处了signal那个有恶疾的连串调用。古板的signal系统调用,他的实信号管理函数是叁回性的,执行过后,该实信号的非实信号管理函数就成为了SIG_DFL。
       
    值得提的是,glibc的signal函数,调用的已经不是古板的signal系统调用,而是rt_sigaction系统调用,这种三遍性的欠缺早就经缓和了。怎么注解: 

void handler(int sig)

  1. manu@manu-hacks:~/code/c/self/signal$ cat signal_fault_1.c

  2. #include <stdio.h>

  3. #include <stdlib.h>

  4. #include <signal.h>

  5. #include <string.h>

  6. #include <errno.h>

  7. #define MSG “OMG , I catch the signal
    SIGINT\n”

  8. #define MSG_END “OK,finished process
    signal SIGINT\n”

  9. int do_heavy_work()

  10. {

  11.     int i ;

  12.     int k;

  13.     srand(time(NULL));

  14.     for(i = 0 ; i <
    100000000;i++)

  15.     {

  16.         k = rand()%1234589;

  17.     }

  18. }

  19. void signal_handler(int signo)

  20. {

  21.     write(2,MSG,strlen(MSG));

  22.     do_heavy_work();

  23.     write(2,MSG_END,strlen(MSG_END));

  24. }

  25. int main()

  26. {

  27.     char input[1024] = {0};

  28. #if defined TRADITIONAL_SIGNAL_API
        if(syscall(SYS_signal ,SIGINT,signal_handler) == -1)
    #elif defined SYSTEMV_SIGNAL_API
        if(sysv_signal(SIGINT,signal_handler) == -1)
    #else
        if(signal(SIGINT,signal_handler) == SIG_ERR)
    #endif

  29.     {

  30.         fprintf(stderr,”signal
    failed\n”);

  31.         return -1;

  32.     }

  33.     printf(“input a string:\n”);

  34.     if(fgets(input,sizeof(input),stdin)== NULL)

  35.     {

  36.         fprintf(stderr,”fgets
    failed(%s)\n”,strerror(errno));

  37.         return -2;

  38.     }

  39.     else

  40.     {

  41.         printf(“you entered:%s”,input);

  42.     }

  43.     return 0;

  44.     

  45. }

       
    编写翻译的时候,笔者未有定义SYSTEMV_SIGNAL_API,正是行业内部的glibc的signal函数,作者用strace追踪glibc的signal函数调用的系统调用是: 

{

  1. rt_sigaction(SIGINT,
    {0x8048736, [INT],
    SA_RESTART}, {SIG_DFL, [], 0}, 8) = 0

         printf(“Receive signal :%u\n”,sig);

    测量试验结果如下:

}

  1. manu@manu-hacks:~/code/c/self/signal$ gcc -o signal_glibc signal_fault_1.c

  2. manu@manu-hacks:~/code/c/self/signal$ ./signal_glibc

  3. input a string:

  4. input^COMG , I catch the signal
    SIGINT

  5. ^COK,finished process signal SIGINT

  6. OMG , I catch the signal SIGINT

  7. OK,finished process signal SIGINT

  8. ^COMG , I catch the signal SIGINT

  9. OK,finished process signal SIGINT

  10. ^COMG , I catch the signal SIGINT

  11. OK,finished process signal SIGINT

  12. ^Z

  13. [1]+ Stopped
    ./signal_glibc

void sigroutine(int num)

   
大家设置的时域信号管理函数并不是二次性的,原因便是glibc的signal函数调用的函数并不是是signal系统调用,并从未SA_ONESHOT标志位。
   
大家怎么着体验下老古董的signal,glibc提供了贰个sysv_signal接口,manual中如此描述:

{

  1.    However sysv_signal() provides
    the System V unreliable signal semantics, that is:
    a) the disposition of the sig‐

  2.    nal is reset to the default when the handler is invoked; b) delivery
    of further instances of the signal is not

  3.    blocked while the signal handler is
    executing; and c) if the handler interrupts (certain)
    blocking system calls,

  4.    then the system call is not automatically restarted.

       
    对于我们的例证只需求:

         switch(num)

  1. gcc -DSYSTEMV_SIGNAL_API -o signal_sysv signal_fault_1.c

        大家看下:

         {

  1. manu@manu-hacks:~/code/c/self/signal$ ./signal_sysv

  2. input a string:

  3. ^COMG , I catch the signal SIGINT

  4. ^C

  5. manu@manu-hacks:~/code/c/self/signal$ man sysv_signal

         case 1:

   
第1个ctrl+C导致了经过的生产,原因是sysv_signal这种观念的signal的装置函数是贰回性的。strace也表达了那或多或少:

                   printf(“SIGUP signal\n”);

  1. rt_sigaction(SIGINT,
    {0x8048756, [], SA_INTERRUPT|SA_NODEFER|SA_RESETHAND}, {SIG_DFL,
    [], 0}, 8) = 0

                   break;

    还记得么:

         case 2:

  1. #define SA_ONESHOT SA_RESETHAND

                   printf(“SIGINT signal\n”);

   
大家开掘sysv调用的不是signal系统调用,而是rt_sigaction系统调用。倘让你非要品尝守旧的signal系统调用,那也易于。

                   break;

  1. gcc -DTRADITIONAL_SIGNAL_API  -o signal_traditional
    signal_fault_1.c 

       
    大家开掘第二个SIGINT实信号的频限信号管理函数已经SIG_DFL,使进度退出了。

         case 3:

  1. manu@manu-hacks:~/code/c/self/signal$ ./signal_traditional

  2. input a string:

  3. ^COMG , I catch the signal SIGINT

  4. ^C

       
    大家经过strace能够作证,的确调用了signal系统调用: 

                   printf(“SIGQUIT signal\n”);

  1. signal(SIGINT,
    0x8048736) = 0 (SIG_DFL) 

                   break;

    2开始时期的复信号,未有遮挡正在管理的功率信号。
   
如何表明那或多或少呢?笔者上边的例证中有目的在于实信号管理函数中做了很heavy很耗费时间的操作,进而轻便造出管理随机信号A的时候,另一时域信号A又被deliver的场景。
   
因为do_heavy_work是个很耗时的操作,实信号管理完了大家会在标准错误上输出管理到位的讲话,那就表征了实信号管理实现了从未。
   
大家看下传统signal的,收到三个SIGINT的功率信号的情形:

         default:

  1. manu@manu-hacks:~/code/c/self/signal$ ./signal_traditional

  2. input a string:

  3. ^COMG , I catch the signal SIGINT

  4. OK,finished process signal SIGINT

  5. fgets failed(Interrupted system call)

  6. manu@manu-hacks:~/code/c/self/signal$

                   break;

   
借使本人在进程管理复信号管理函数的时候,再度发送二个SIGINT,这么些SIGINT也说不定被内核deliver。那么时域信号管理函数就被中断掉,

         }  www.2cto.com  

  1. manu@manu-hacks:~/code/c/self/signal$ ./signal_traditional

  2. input a string:

  3. ^COMG , I catch the signal SIGINT

  4. ^C

  5. manu@manu-hacks:~/code/c/self/signal$

         return;

   
我们看来大家摄取了I catch the signal SIGINT的打字与印刷,可是,并从未收到OK,I
finished process signal
SIGINT,那注明古板的signal并未遮挡正在管理的实信号。
   
那么我们前天的glibc的signal函数怎样?
    strace又来帮忙了?

}

  1. rt_sigaction(SIGINT,
    {0x8048736, [INT],
    SA_RESTART}, {SIG_DFL, [], 0}, 8) = 0

int main(void)

    glibc的signal函数,调用的是rt_sigaction
系统调用:
    

{

  1. SYSCALL_DEFINE4(rt_sigaction, int, sig,

  2.         const struct sigaction
    __user *, act,

  3.         struct sigaction __user
    *,
    oact,

  4.         size_t, sigsetsize)

  5. struct sigaction {

  6.     union {

  7.      __sighandler_t _sa_handler;

  8.      void (*_sa_sigaction)(int, struct siginfo *, void *);

  9.     } _u;

  10.     sigset_t sa_mask;

  11.     unsigned long sa_flags;

  12.     void (*sa_restorer)(void);

  13. }

       
    大家把strace中的音信,和sigaction数据相比较,开掘,[INT],就是风传中的sa_mask,当管理SIGINT的时候,看起来是在管理SIGINT时限信号管理函数的时候,SIGINT会被被挡住,幸免重入。实际怎样呢? 

         struct sigaction sa;

  1. manu@manu-hacks:~/code/c/self/signal$ ./signal_glibc

  2. input a string:

  3. ^COMG , I catch the signal SIGINT

  4. ^C^C^C^COK,finished process signal
    SIGINT

  5. OMG , I catch the signal SIGINT

  6. ^C^COK,finished process signal
    SIGINT

  7. OMG , I catch the signal SIGINT

  8. OK,finished process signal SIGINT

  9. ^COMG , I catch the signal SIGINT

  10. OK,finished process signal SIGINT

  11. ^COMG , I catch the signal SIGINT

  12. ^Z

  13. [2]+ Stopped
    ./signal_glibc

         int count;

   
从未出现OMG,I catch the
SIGINT接二连三出现。那是偶然仍旧自然呢?答案是必定,内核是怎样完毕的吗?
   
在上海体育地方的handle_signal函数的最终,调用了signal_delivered函数: 

         sa.sa_handler=handler;

  1. /**

  2.  * signal_delivered –

  3.  * @sig:        number of signal being delivered

  4.  * @info:        siginfo_t of signal being
    delivered

  5.  * @ka:            sigaction setting that chose
    the handler

  6.  * @regs:        user register state

  7.  * @stepping:        nonzero if debugger single-step or block-step in use

  8.  *

  9.  * This function should be called when a signal has
    succesfully been

  10.  * delivered. It updates the blocked signals accordingly
    (@ka->sa.sa_mask

  11.  * is
    always blocked, and the signal itself is blocked unless %SA_NODEFER

  12.  * is
    set in
    @ka->sa.sa_flags.
    Tracing is notified.

  13.  */

  14. void signal_delivered(int sig,
    siginfo_t *info, struct k_sigaction *ka,

  15.             struct pt_regs *regs, int stepping)

  16. {

  17.     sigset_t blocked;

  18.     /*
    A signal was successfully delivered,
    and the

  19.      saved sigmask was stored on the
    signal frame,

  20.      and will be restored by
    sigreturn. So we can

  21.      simply clear the restore sigmask flag. */

  22.     clear_restore_sigmask();

  23.     sigorsets(&blocked,
    &current->blocked,
    &ka->sa.sa_mask);

  24.     if (!(ka->sa.sa_flags &
    SA_NODEFER))

  25.         sigaddset(&blocked,
    sig);

  26.     set_current_blocked(&blocked);

  27.     tracehook_signal_handler(sig,
    info, ka, regs,
    stepping);

  28. }

       
    那么些函数很风趣,只要用户未有一些名SA_NODEFE奇骏标记位,当前管理的复信号总是步向到屏蔽实信号之中。浓厚领悟Linux内核在也涉嫌了那或多或少。杰出教材是这么说的:

         sigemptyset(&sa.sa_mask);

  1. 当进度实践三个信号管理程序的函数时,经常屏蔽相应的复信号,即自动阻塞这些功率信号,直各管理程序截止。由此,所拍卖的复信号的另三次面世,并不能够暂停复信号处理程序,所以功率信号管理函数不必是可以重入的。

         sa.sa_flags=0;

   
这一个结论很吃惊吗。是的您用glibc的signal函数,不必忧虑复信号管理函数的嵌套难题。至于重入难点我们后文研讨。
   
那么守旧的signal系统调用和sysv_signal又如何?为什么他们存在随机信号的可重入难题? 
 

         printf(“task id is:%d\n”,getpid());

  1. SYSCALL_DEFINE2(signal, int, sig, __sighandler_t, handler)

  2. {

  3.     struct k_sigaction new_sa, old_sa;

  4.     int ret;

  5.     new_sa.sa.sa_handler =
    handler;

  6.     new_sa.sa.sa_flags =
    SA_ONESHOT | SA_NOMASK;

  7.     sigemptyset(&new_sa.sa.sa_mask);

  8.     ret = do_sigaction(sig,
    &new_sa, &old_sa);

  9.     return ret ? ret : (unsigned
    long)old_sa.sa.sa_handler;

  10. }

/*下边四条语句为对应的频限信号设置新的拍卖措施*/

#define SA_NOMASK SA_NODEFER

         sigaction(SIGTERM,&sa,NULL);

   
至于sysv_signal

         signal(SIGHUP,sigroutine);

  1. rt_sigaction(SIGINT,
    {0x8048756, [], SA_INTERRUPT|SA_NODEFER|SA_RESETHAND}, {SIG_DFL,
    [], 0}, 8) = 0

         signal(SIGINT,sigroutine);

   
相当的少说了,不作死就不会死,signal系统调用和sysv_signal都作死:sa_mask是空,更要命的是都有SA_NODEFELacrosse。自作孽,不可活。之所以这么自作孽,正是为了向下兼容,向守旧的signal致敬。
    
    3
刚开始阶段的signal,会暂停系统调用。  

         signal(SIGQUIT,sigroutine);

    何意?  

 

    有个别系统调用大概会被数字信号中断,此时系统调用重返错误EINTGL450,表示被确定性信号中断了。相当多的系统调用都会被中止,笔者前面有篇博文重启系统调用商量,就详细介绍了系统被信号中断的主题材料,古板的signal汇合世这一个标题。那么glibc的signal函数有未有那个难题?答案是不曾那一个难点,glibc的signal函数很不利。

         while(1)

  1. rt_sigaction(SIGINT,
    {0x8048736, [INT],
    SA_RESTART}, {SIG_DFL, [], 0}, 8) = 0

         {

    signal系统调用和sysv_signal都有其一缺欠:请看: 

                   sigsuspend(&sa.sa_mask);/*堵塞,平昔等候时域信号达到*/

  1. manu@manu-hacks:~/code/c/self/signal$ ./signal_traditional

  2. input a string:

  3. ^COMG , I catch the signal SIGINT

  4. OK,finished process signal SIGINT

  5. fgets failed(Interrupted system call)

  6. manu@manu-hacks:~/code/c/self/signal$ ./signal_sysv

  7. input a string:

  8. ^COMG , I catch the signal SIGINT

  9. OK,finished process signal SIGINT

  10. fgets failed(Interrupted system call)

  11. manu@manu-hacks:~/code/c/self/signal$

                   printf(“loop\n”);

    原因正是未有SA_RESTART标记位。内核代码如何突显:

         }  www.2cto.com  

  1. static void

  2. handle_signal(unsigned long sig, siginfo_t *info, struct
    k_sigaction *ka,

  3.         struct pt_regs *regs)

  4. {

  5.     /* Are we
    from a system call? */

  6.     if
    (syscall_get_nr(current,
    regs) >= 0) {

  7.         /* If so, check
    system call restarting.. */

  8.         switch (syscall_get_error(current,
    regs))
    {

  9.         case -ERESTART_RESTARTBLOCK:

  10.         case -ERESTARTNOHAND:

  11.             regs->ax = -EINTR;

  12.             break;

  13.         case -ERESTARTSYS:

  14.             if (!(ka->sa.sa_flags &
    SA_RESTART)) {

  15.                 regs->ax = -EINTR;

  16.                 break;

  17.             }

  18.         /*
    fallthrough */

  19.         case -ERESTARTNOINTR:

  20.             regs->ax = regs->orig_ax;

  21.             regs->ip -= 2;

  22.             break;

  23.         }

  24.     }

  25.     。。。

  26. }

         return 0;

   
比很多篇章都都将signal函数描述的多多不堪,其实glibc的signal函数非常可信赖,守旧的signal的多少个缺陷都不设有,在经常的办事中,signal完全能够满足急需。

}

只是存在七个难题,就能够可移植性。由于分歧的阳台大概两样。单就linux平台来讲,glibc的signal函数尚可。

     
 可知,用户空间调用了好多体系调用来贯彻时限信号的编制程序,为了弄驾驭她的内在规律,决定将根本中的完毕做一个光景的梳理。为了理清思路,大家由基本中落复复信号操作涉及的主要性数据结构关系画出下图,大家看到,内核中的数据结构完结较轻便,首要分两局部,一部分用以时限信号操作(即handler),由进度的sighand字段早先;另一片段用来非确定性信号的挂起,由进程的signal和pending字段索引。

    那么signal还应该有如何难题吗?为什么有引进了实时功率信号?那是下一篇内容。

图片 2
 

参照他事他说加以考察文献

由关系图,我们大约观其实现原理如下:

1
深远领会linunx内核

1,  
进程的兼具时域信号(现为叁十个)由贰个数组task->sighand->action[]保存,数组的下标即为非复信号的ID,譬喻SIGQUIT等,每一个操作由多少个数据结构sigaction完成,该字段的sa_handler即为促成的操作;

2  linux内核源代码情景解析
3 signal ppt  蘇維農
4 linux系统一编写程

2,  
进程对挂起的确定性信号有二种队列,一种为具备进度分享的。该队列的各个为三个sigqueue结构,通过该组织info字段的si_signo等属性能够一定到对应的时域信号ID。当中sigset_t结构为三个叁15个人整型,用于固定到ID,即类似位图的意味。

作者们看多少个最中央的操作于内核中的达成。

1,   设置新的action;

系统调用signal用于落到实处那些效应,当然也能够用sigaction系统调用,

SYSCALL_DEFINE2(signal, int, sig, __sighandler_t, handler)

{

         struct k_sigaction new_sa, old_sa;

         int ret;

 

         new_sa.sa.sa_handler = handler;

         new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK;

         sigemptyset(&new_sa.sa.sa_mask);

 

         ret = do_sigaction(sig, &new_sa, &old_sa);

 

         return ret ? ret : (unsignedlong)old_sa.sa.sa_handler;

}

该种类调用分配二个新的action后,调用do_sigaction实现实际工作,最终回到旧的action的handler。
 www.2cto.com  

int do_sigaction(int sig,struct k_sigaction *act, struct k_sigaction
*oact)

{

         struct task_struct *t = current;

         struct k_sigaction *k;

         sigset_t mask;

……

         k = &t->sighand->action[sig-1];

         spin_lock_irq(&current->sighand->siglock);

         if (oact)

                   *oact = *k;/*保存旧的action*/

         if (act) {

                   sigdelsetmask(&act->sa.sa_mask,

                                  sigmask(SIGKILL) | sigmask(SIGSTOP));

                   *k = *act;/*设置新的action*/

 

                  /*对二种handler的独特管理*/

                   if (sig_handler_ignored(sig_handler(t, sig), sig))
{

                            ……

                   }

         }

         spin_unlock_irq(&current->sighand->siglock);

         return 0;

}

完成很轻巧,先保存旧的action,用于系统调用重返,然后设置新的action。

2,   发送确定性信号

出殡时域信号的系统调用有好些个,最后都会调用__send_signal()函数。

staticint __send_signal(int sig,struct siginfo *info, struct
task_struct *t,

                            int group, int from_ancestor_ns)

{

         struct sigpending *pending;

         struct sigqueue *q;

         int override_rlimit;

         ……

         /*找到必要挂起的行列*/

         pending = group ? &t->signal->shared_pending :
&t->pending;

         ……

         /*分配队列项结构*/

q = __sigqueue_alloc(t, GFP_ATOMIC |
__GFP_NOTRACK_FALSE_POSITIVE,

发表评论

电子邮件地址不会被公开。 必填项已用*标注

相关文章