zoukankan      html  css  js  c++  java
  • libevent 源码学习八 —— 集成信号处理

    前言 : 这一节将分析如何将 Signal 集成到事件主循环的框架中 1 集成策略——使用 socket pair a 开始 b 创建监听 socket c 绑定本地回环地址, 开始监听本地连接 d 创建一个连接 socket——sock1 e 调用 connect()连接到监听 socket 监听的窗口 f 调用 accept()取得连接成功后返回的 socket —— sock2 g 将 sock1 作为写 socket:sock2 作为读socket : 返回 h 结束 2 集成到事件主循环——通知 event_base Libevent 会在事件主循环中检查标记,来确定是否有触发的 signal,如果标记被设置就处理这些 signal。 处理框架 1) 初始化阶段: 创建 socket pair 为 socket pair 的读socket 在 libevent 的 event_base 实例上注册一个 persist 的读事件。 2) 信号触发阶段 IN Thread A 将信号发生标记置为1,记录信号 signo; 向写 socket 写入数据,触发读 socket 的读事件,从而通知 event_base 有信号发生 IN libevent thread I/O 事件发生, event_base 的 I/O 机制马上返回; 检查标记发现 signal 事件发生,遍历链表,将 signo 的注册事件添加到激活链表中 3) 注册信号 注册信号 signo 事件,将对应的 event 添加到信号 signo 的 event 链表中 3 evsignal_info 结构体 Libevent 中 Signal 事件的管理时通过结构体 evsignal_info 完成的,结构体位于 evsignal.h 文件中。 struct evsignal_info(){ struct event ev_signal; int ev_signal_pair[2]; int ev_signal_added; volatile sig_atomic_t evsignal_caught; struct event_list evsigevents[NSIG]; sig_atomic_t evsigcaught[NSIG]; #ifdef HAVE_SIGNAL struct sigaction **sh_old; #else ev_sighandler_t **sh_old; #endif int sh_old_max; }; ev_signal 为 socket pair 的读 socket 向 event_base 注册读事件时使用的 event 结构体 ev_signal_pair : socket pair 对 ev_signal_added : 记录ev_signal 事件是否已经注册了 evsignal_caught : 是否有信号发生标记:是 volatile 类型,直接从内存读取 evsigevents[NSIG] : 数组,evsigevents[signo] 表示注册到信号 signo 的事件链表 evsigcaught[NSIG] : 具体记录每个信号触发的次数 sh_old 记录了原来的 signal 处理函数指针, 当信号 signo 注册的 event 被清空时,需要重新设置器处理函数 evsignal_info 的初始化包括, 创建 socket pair, 设置 ev_signal 事件,将所有标记置0, 初始化信号的注册事件链表指针。 4 注册、注销 signal 事件 注册 signal 事件是通过 evsignal_add(struct event* ev)函数完成的, Libevent 对所有的信号注册使用同一个处理函数 evsignal_handler(),注册过程如下 取得 ev 要注册到的信号 signo 如果信号 signo 未被注册,那么就为 signo 注册信号处理函数 evsignal_handler() 如果事件 ev_signal 还没有被注册,就注册 ev_signal 事件 将事件 ev 添加到 signo 的 event 链表中 从 signo 上注销一个已注册的 signal 事件: 直接从其已注册事件的链表中移除。如果事件链表已空,那么就恢复旧的处理函数。 处理函数 evsignal_handler() 函数就是记录信号的发生次数,并通知 event_base 有信号触发, 需要处理。 static void evsignal_handler(int sig){ int save_errno = errno; if(evsignal_base == NULL) { event_warn("%s : reveived signal %d, but have no base configured", __func__, sig); return; } // 记录信号 sig 的触发次数,并设置 event 触发标记 evsignal_base -> sig.evsigcaught[sig]++; evsignal_base -> sig.evsignal_caught = 1; #ifndef HAVE_SIGACTION signal(sig, evsignal_handler); // 重新注册信号 #endif // 向写 socket 写一个字节数据,触发 event_base 的 I/O 事件,从而通知有信号触发,需要处理 send(evsignal_base -> sig.ev_signal_pair[0], "a", 1, 0); errno = save_errno // 错误码 }
  • 相关阅读:
    PCA算法的最小平方误差解释
    windows下面安装Python和pip终极教程
    理解C/C++的复杂声明
    C++的特殊预处理定义#、##和#@
    虚拟机中linux系统无法打开原保存的显示器配置解决方法
    Visual C++内存泄露检测—VLD工具使用说明
    C++重载、覆盖与隐藏——转载
    python爬虫实战(二)--------千图网高清图
    Linux常用命令12
    Linux常用命令11
  • 原文地址:https://www.cnblogs.com/sanerer/p/10787226.html
Copyright © 2011-2022 走看看