Atlas源码剖析(一)
来源:互联网 发布:淘宝限制购买怎么解决 编辑:程序博客网 时间:2024/05/08 23:47
信号设置
在设置各种配置参数之前,如果支持sigaction,则使用sigaction来设置SIGSEGV信号,指定处理函数调用g_on_error_stack_trace获取相关的堆栈信息后,调用abort退出程序。此信号在程序结束前进行清除,修复默认处理方式。
#ifdef HAVE_SIGACTION /* register the sigsegv interceptor */ memset(&sigsegv_sa, 0, sizeof(sigsegv_sa)); sigsegv_sa.sa_handler = sigsegv_handler; sigemptyset(&sigsegv_sa.sa_mask); if (frontend->invoke_dbg_on_crash && !(RUNNING_ON_VALGRIND)) { sigaction(SIGSEGV, &sigsegv_sa, NULL); } #endifstatic void sigsegv_handler(int G_GNUC_UNUSED signum) { g_on_error_stack_trace(g_get_prgname()); abort(); /* trigger a SIGABRT instead of just exiting */}
同时,将SIGPIPE信号的处理方式设置为忽略。这里增加一些对SIGPIPE信号的介绍:TCP是全双工的信道,可以看作两条单工信道,,TCP连接两端的两个端点各负责一条。当对端调用close时, 虽然本意是关闭整个两条信道, 但本端只是收到FIN包. 按照TCP协议的语义, 表示对端只是关闭了其所负责的那一条单工信道, 仍然可以继续接收数据。也就是说, 因为TCP协议的限制, 一个端点无法获知对端的socket是调用了close还是shutdown。
对一个已经收到FIN包的socket调用read方法, 如果接收缓冲已空, 则返回0, 这就是常说的表示连接关闭。但第一次对其调用write方法时, 如果发送缓冲没问题, 会返回正确写入(发送)。但发送的报文会导致对端发送RST报文, 因为对端的socket已经调用了close, 完全关闭, 既不发送, 也不接收数据。所以, 第二次调用write方法(假设在收到RST之后), 会生成SIGPIPE信号, 导致进程退出。
为了避免进程退出, 可以捕获SIGPIPE信号, 或者忽略它, 给它设置SIG_IGN信号处理函数:
signal(SIGPIPE, SIG_IGN);这样, 第二次调用write方法时, 会返回-1, 同时errno置为SIGPIPE。程序便能知道对端已经关闭。Atlas对于此信号的处理正是采用了这种方法。
在进入主流程后,通过libevent事件机制设置SIGTERM、SIGINT和SIGHUP信号,对于SIGTERM信号的处理方式是通过设置signal_shutdown标志,让进程从event_base_loop中退出(每个线程在进入event_base_loop之前,都会通过event_base_loopexit设置一个定时器,每隔1秒钟就退出event_base_loop,检查signal_shutdown是否被设置,如果设置了,就结束线程);SIGINT的处理跟SIGTERM使用同一个处理函数;SIGHUP的处理方式是设置日志中的rotate_logs标志,这导致在下一次写入日志时重新打开日志文件。
signal_set(&ev_sigterm, SIGTERM, sigterm_handler, NULL); event_base_set(chas->event_base, &ev_sigterm); signal_add(&ev_sigterm, NULL); signal_set(&ev_sigint, SIGINT, sigterm_handler, NULL); event_base_set(chas->event_base, &ev_sigint); signal_add(&ev_sigint, NULL);#ifdef SIGHUP signal_set(&ev_sighup, SIGHUP, sighup_handler, chas); event_base_set(chas->event_base, &ev_sighup); if (signal_add(&ev_sighup, NULL)) { g_critical("%s: signal_add(SIGHUP) failed", G_STRLOC); } #endifstatic void sigterm_handler(int G_GNUC_UNUSED fd, short G_GNUC_UNUSED event_type, void G_GNUC_UNUSED *_data) { chassis_set_shutdown_location(NULL);}void chassis_set_shutdown_location(const gchar* location) { if (signal_shutdown == 0) g_message("Initiating shutdown, requested from %s", (location != NULL ? location : "signal handler")); signal_shutdown = 1;}static void sighup_handler(int G_GNUC_UNUSED fd, short G_GNUC_UNUSED event_type, void *_data) { chassis *chas = _data; g_message("received a SIGHUP, closing log file"); /* this should go into the old logfile */ chassis_log_set_logrotate(chas->log); g_message("re-opened log file after SIGHUP"); /* ... and this into the new one */}void chassis_log_set_logrotate(chassis_log *log) { log->rotate_logs = TRUE;}
- Atlas源码剖析(一)
- Atlas源码剖析(二)
- Atlas源码剖析(三)
- Atlas源码剖析(四)
- Atlas源码剖析(五)
- Atlas源码剖析(六)
- Atlas源码剖析(七)
- Atlas源码剖析(八)
- Atlas源码剖析(九)
- Atlas源码剖析(十)
- Atlas源码剖析(十一)
- Atlas源码学习(一)
- Azureus源码剖析(一)
- GDAL源码剖析(一)
- GDAL源码剖析(一)
- GDAL源码剖析(一)
- chromium源码剖析(一)
- Chrome 源码剖析(一)
- 用已有16M文件系统制作32M文件系统,修改 uboot 参数
- java事务大总结(一) 先理解数据库的事务以mysql为例
- 网站重构——轻量化的网站架构设计三,angular restify
- python server android
- Hibernate封装类
- Atlas源码剖析(一)
- SEO优化步骤
- javascript eval和JSON之间的联系
- 使用Android Studio遇到的问题及解决过程
- 新手学习Cadence16.3笔记
- 16进制转化为8进制
- thrift使用示例二
- usaco training 6.1.3 Cow XOR 题解
- MongoDB数据文件备份与恢复