nginx源码分析—信号初始化

本文深入探讨了nginx启动过程中的信号初始化机制,包括信号数组、信号处理函数以及信号处理方式,详细解释了如何设置信号处理程序以响应特定信号。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作者:阿波
链接:http://blog.youkuaiyun.com/livelylittlefish/article/details/7308100

Content

0.

1. ngx_init_signals()函数

1.1 ngx_signal_t结构

1.2 signals数组

1.3 sigaction结构

2.几个问题

2.1ngx_signal_value宏是如何得到整数的信号值signo的?

2.2 handler=SIG_IGN=0x1是如何忽略信号的?

3.ngx_signal_handler()函数

4.小结

 

0.

本文主要分析nginx信号初始化及其处理。文中如无特别说明,.表示nginx-1.0.4代码目录,本文为/usr/src/nginx-1.0.4

1. ngx_init_signals()函数

该函数主要任务是设置signals[]数组中每个信号的action(即常说的注册、安装等)。如下。

./src/os/unix/ngx_process.c

[cpp]  view plain copy
  1. ngx_int_t  
  2. ngx_init_signals(ngx_log_t *log)  
  3. {  
  4.     ngx_signal_t      *sig;  
  5.     struct sigaction   sa;  
  6.   
  7.     for (sig = signals; sig->signo != 0; sig++) {   /* signals数组 */  
  8.         ngx_memzero(&sa, sizeof(struct sigaction)); /* 此处sigaction是一个结构类型 */  
  9.         sa.sa_handler = sig->handler;  
  10.         sigemptyset(&sa.sa_mask);    /* 清空sa_mask */  
  11.         if (sigaction(sig->signo, &sa, NULL) == -1) { /* 设置sig->signo信号的action,此处sigaction为系统API */  
  12.             ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,  
  13.                           "sigaction(%s) failed", sig->signame);  
  14.             return NGX_ERROR;  
  15.         }  
  16.     }  
  17.   
  18.     return NGX_OK;  
  19. }  

1.1 ngx_signal_t结构

nginx的信号结构如下。

[html]  view plain copy
  1. typedef struct {  
  2.     int     signo;                /* 信号值 */  
  3.     char   *signame;              /* 信号名 */  
  4.     char   *name;                 /* 信号可读名 */  
  5.     void  (*handler)(int signo);  /* 信号处理程序 */  
  6. } ngx_signal_t;  

nginx进程收到相关信号时就会执行注册的handler

1.2 signals数组

对于该函数中的signals数组,其信号的handlerngx_signal_handler(),如下所示。

./src/os/unix/ngx_process.c

[cpp]  view plain copy
  1. ngx_signal_t  signals[] = {  
  2.     { ngx_signal_value(NGX_RECONFIGURE_SIGNAL),  
  3.       "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL),  
  4.       "reload",  
  5.       ngx_signal_handler },  
  6.   
  7.     { ngx_signal_value(NGX_REOPEN_SIGNAL),  
  8.       "SIG" ngx_value(NGX_REOPEN_SIGNAL),  
  9.       "reopen",  
  10.       ngx_signal_handler },  
  11.   
  12.     { ngx_signal_value(NGX_NOACCEPT_SIGNAL),  
  13.       "SIG" ngx_value(NGX_NOACCEPT_SIGNAL),  
  14.       "",  
  15.       ngx_signal_handler },  
  16.   
  17.     { ngx_signal_value(NGX_TERMINATE_SIGNAL),  
  18.       "SIG" ngx_value(NGX_TERMINATE_SIGNAL),  
  19.       "stop",  
  20.       ngx_signal_handler },  
  21.   
  22.     { ngx_signal_value(NGX_SHUTDOWN_SIGNAL),  
  23.       "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL),  
  24.       "quit",  
  25.       ngx_signal_handler },  
  26.   
  27.     { ngx_signal_value(NGX_CHANGEBIN_SIGNAL),  
  28.       "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL),  
  29.       "",  
  30.       ngx_signal_handler },  
  31.   
  32.     { SIGALRM, "SIGALRM""", ngx_signal_handler },  
  33.   
  34.     { SIGINT, "SIGINT""", ngx_signal_handler },  
  35.   
  36.     { SIGIO, "SIGIO""", ngx_signal_handler },  
  37.   
  38.     { SIGCHLD, "SIGCHLD""", ngx_signal_handler },  
  39.   
  40.     { SIGSYS, "SIGSYS, SIG_IGN""", SIG_IGN },    /* SIGSYS=31,该信号handler=SIG_IGN,表示忽略该信号 */  
  41.   
  42.     { SIGPIPE, "SIGPIPE, SIG_IGN""", SIG_IGN },  /* SIGPIPE=13,该信号handler=SIG_IGN,表示忽略该信号 */   
  43.   
  44.     { 0, NULL, "", NULL }  
  45. };  

通过调试nginx,可以查看在运行环境中该数组的真实内容,也可看出ngx_signal_t结构,及nginx支持的信号种类。如下。

[plain]  view plain copy
  1. (gdb) p signals  
  2. $5 = {{  
  3.     signo = 1,   
  4.     signame = 0x476235 "SIGHUP",   
  5.     name = 0x4726ab "reload",   
  6.     handler = 0x41df10 <ngx_signal_handler>  
  7.   }, {  
  8.     signo = 10,   
  9.     signame = 0x47623c "SIGUSR1",   
  10.     name = 0x4726a4 "reopen",   
  11.     handler = 0x41df10 <ngx_signal_handler>  
  12.   }, {  
  13.     signo = 28,   
  14.     signame = 0x476244 "SIGWINCH",   
  15.     name = 0x47b68f "",   
  16.     handler = 0x41df10 <ngx_signal_handler>  
  17.   }, {  
  18.     signo = 15,   
  19.     signame = 0x47624d "SIGTERM",   
  20.     name = 0x47269a "stop",   
  21.     handler = 0x41df10 <ngx_signal_handler>  
  22.   }, {  
  23.     signo = 3,   
  24.     signame = 0x476255 "SIGQUIT",   
  25.     name = 0x47269f "quit",   
  26.     handler = 0x41df10 <ngx_signal_handler>  
  27.   }, {  
  28.     signo = 12,   
  29.     signame = 0x47625d "SIGUSR2",   
  30.     name = 0x47b68f "",   
  31.     handler = 0x41df10 <ngx_signal_handler>  
  32.   }, {  
  33.     signo = 14,   
  34.     signame = 0x476265 "SIGALRM",   
  35.     name = 0x47b68f "",   
  36.     handler = 0x41df10 <ngx_signal_handler>  
  37.   }, {  
  38.     signo = 2,   
  39.     signame = 0x47626d "SIGINT",   
  40.     name = 0x47b68f "",   
  41.     handler = 0x41df10 <ngx_signal_handler>  
  42.   }, {  
  43.     signo = 29,   
  44.     signame = 0x476274 "SIGIO",   
  45.     name = 0x47b68f "",   
  46.     handler = 0x41df10 <ngx_signal_handler>  
  47.   }, {  
  48.     signo = 17,   
  49.     signame = 0x47627a "SIGCHLD",   
  50.     name = 0x47b68f "",   
  51.     handler = 0x41df10 <ngx_signal_handler>  
  52.   }, {  
  53.     signo = 31,   
  54.     signame = 0x476282 "SIGSYS, SIG_IGN",   
  55.     name = 0x47b68f "",   
  56.     handler = 0x1      /* 该信号handler=SIG_IGN=0x1,表示忽略该信号 */  
  57.   }, {  
  58.     signo = 13,   
  59.     signame = 0x476292 "SIGPIPE, SIG_IGN",   
  60.     name = 0x47b68f "",   
  61.     handler = 0x1      /* 该信号handler=SIG_IGN=0x1,表示忽略该信号 */  
  62.   }, {  
  63.     signo = 0,   
  64.     signame = 0x0,   
  65.     name = 0x47b68f "",   
  66.     handler = 0  
  67.   }}  

通过调试打印出signals数组的内容,可以很清晰地看到其定义。几个用到的宏如下。

./src/core/ngx_config.h

[cpp]  view plain copy
  1. #define ngx_signal_helper(n)     SIG##n  
  2. #define ngx_signal_value(n)      ngx_signal_helper(n)  
  3.   
  4. #define NGX_SHUTDOWN_SIGNAL      QUIT  
  5. #define NGX_TERMINATE_SIGNAL     TERM  
  6. #define NGX_NOACCEPT_SIGNAL      WINCH  
  7. #define NGX_RECONFIGURE_SIGNAL   HUP  
  8.   
  9. #if (NGX_LINUXTHREADS)  
  10. #define NGX_REOPEN_SIGNAL        INFO  
  11. #define NGX_CHANGEBIN_SIGNAL     XCPU  
  12. #else  
  13. #define NGX_REOPEN_SIGNAL        USR1  
  14. #define NGX_CHANGEBIN_SIGNAL     USR2  
  15. #endif  

1.3 sigaction结构

sigaction结构定义如下。

[cpp]  view plain copy
  1. struct sigaction {  
  2.     void     (*sa_handler)(int);  
  3.     void     (*sa_sigaction)(int, siginfo_t *, void *);  
  4.     sigset_t   sa_mask;  
  5.     int        sa_flags;  
  6.     void     (*sa_restorer)(void);  
  7. };  

该定义从sigactionmanual页而来,如果查看kernel源代码,可能因版本不同有所调整。

 

2.几个问题

2.1ngx_signal_value宏是如何得到整数的信号值signo的?

 

举个例子,NGX_RECONFIGURE_SIGNAL=HUP,因此ngx_signal_value(NGX_RECONFIGURE_SIGNAL)=SIGHUP

从上述signals数组可以看出,SIGHUPsigno=1name"reload"。那么,这个1是在哪里定义的?

——这很容易能想到kernel源代码。果期不然,在#include <signal.h>

 

file:/usr/include/asm/signal.h/usr/include/asm-generic/signal.h均有定义。

[cpp]  view plain copy
  1. #define SIGHUP       1  
  2. #define SIGINT       2  
  3. #define SIGQUIT      3  
  4. #define SIGILL       4  
  5. #define SIGTRAP      5  
  6. #define SIGABRT      6  
  7. #define SIGIOT       6  
  8. #define SIGBUS       7  
  9. #define SIGFPE       8  
  10. #define SIGKILL      9  
  11. #define SIGUSR1     10  
  12. #define SIGSEGV     11  
  13. #define SIGUSR2     12  
  14. #define SIGPIPE     13  
  15. #define SIGALRM     14  
  16. #define SIGTERM     15  
  17. #define SIGSTKFLT       16  
  18. #define SIGCHLD     17  
  19. #define SIGCONT     18  
  20. #define SIGSTOP     19  
  21. #define SIGTSTP     20  
  22. #define SIGTTIN     21  
  23. #define SIGTTOU     22  
  24. #define SIGURG      23  
  25. #define SIGXCPU     24  
  26. #define SIGXFSZ     25  
  27. #define SIGVTALRM       26  
  28. #define SIGPROF     27  
  29. #define SIGWINCH        28  
  30. #define SIGIO           29  
  31. #define SIGPOLL     SIGIO  
  32. /* 
  33. #define SIGLOST     29 
  34. */  
  35. #define SIGPWR      30  
  36. #define SIGSYS      31  
  37. #define SIGUNUSED   31  
  38.   
  39. /* These should not be considered constants from userland.  */  
  40. #define SIGRTMIN        32  
  41. #define SIGRTMAX        _NSIG  

2.2 handler=SIG_IGN=0x1是如何忽略信号的?

从上述signals数组中可以看出,SIGSYS=31SISPIPE=13信号,其handler=SIG_IGN=0x1,表明忽略该信号。是如何做到的?SIG_IGN又是在何处定义的?

 

file: /usr/include/asm-generic/signal-defs.h

[cpp]  view plain copy
  1. #ifndef SIG_BLOCK  
  2. #define SIG_BLOCK          0    /* for blocking signals */  
  3. #endif  
  4. #ifndef SIG_UNBLOCK  
  5. #define SIG_UNBLOCK        1    /* for unblocking signals */  
  6. #endif  
  7. #ifndef SIG_SETMASK  
  8. #define SIG_SETMASK        2    /* for setting the signal mask */  
  9. #endif  
  10.   
  11. #ifndef __ASSEMBLY__  
  12. typedef void __signalfn_t(int);  
  13. typedef __signalfn_t __user *__sighandler_t;  
  14.   
  15. typedef void __restorefn_t(void);  
  16. typedef __restorefn_t __user *__sigrestore_t;  
  17.   
  18. #define SIG_DFL ((__force __sighandler_t)0) /* default signal handling */  
  19. #define SIG_IGN ((__force __sighandler_t)1) /* ignore signal */  
  20. #define SIG_ERR ((__force __sighandler_t)-1)    /* error return from signal */  
  21. #endif  

即,

#defineSIG_IGN((void (*)(int))1)

handler函数类型为void(*)(int),符合sigaction结构中sa_handler定义。表明信号忽略函数地址为1,而在实际中是不可能出现函数地址为1的情况,因此可用来区别于别的指针。

实际上,对nginx31号和13号信号,sigactionSIG_IGN=0x1注册(登记)为其signalhandler。即将这两个信号交给系统(init进程)处理。

另:忽略SIGCHLD信号,常作为提高并发服务器性能的一个技巧。因为并发服务器可能fork很多子进程,子进程终结后需要服务器进程wait子进程并清理资源。如果将该信号忽略,可使内核把僵尸子进程交给init进程处理,节省大量僵尸子进程占用的系统资源。

 

3.ngx_signal_handler()函数

该函数仅根据其收到的信号对相应的全局变量,如ngx_quit, ngx_terminate, ngx_noaccept等进行赋值(均赋值为1),当该进程发现相应变量为1时,即会采取相应的操作。

具体的处理,可参考源代码。

 

4.小结

本文主要分析nginx启动过程中信号如何初始化。

 

Reference

# man sigaction

# man -S 7 signal

# man -S 2 kill

<Unix网络编程>

http://www.cplusplus.com/reference/clibrary/csignal/signal

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值