WPA_SUPPLICANT源码分析(1):EVENT LOOP的实现
2012-09-11 17:56
1641 查看
转:http://blog.chinaunix.net/uid-20273473-id-3128151.html
WPA_SUPPLICANT的程序的生命就是在运行一个EVENT LOOP, 等待各种Event的到来,然后做相应的处理。因此分析EVENT LOOP的实现能起到提纲挈领的作用。
1. 数据结构: 见下图
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/05/0e5103b8efe2237bb095c7a0df78e5ea.png)
struct eloop_data结构体是一个统领全局的数据结构,只有一个实例,即Line 75:
点击(此处)折叠或打开
static struct eloop_data eloop;
要处理的Event有三大种类型:Socket事件,Timeout事件,Signal事件. 其中Socket事件又分为三种类型:
* @EVENT_TYPE_READ: Socket has data available for reading
* @EVENT_TYPE_WRITE: Socket has room for new data to be written
* @EVENT_TYPE_EXCEPTION: An exception has been reported
Socket事件:有readers, writers, exceptions三个eloop_sock_table结构体, 每个里面都有动态数组,数组的每一项都是一个具体的eloop_sock. 可以向各个Table里面添加、删除eloop_sock. 事件分发就是遍历sock_table, 依次运行里面的每个Handler.
Timeout事件: 每个struct eloop_timeout都被放在一个双向链表中, 链表头就是eloop_data中的”timeout”项。这些struct eloop_timeout按超时先后排序。
Signal事件:每个struct eloop_signal放在动态数组中
疑问: 为什么Socket和signal事件不使用链表,而是动态的扩大和缩小数组?
2. 基于Select的多Event处理
void eloop_run(void) 是个总函数,我们看它是怎么用select系统调用实现多路复用监听多个事件的。
while (!eloop.terminate &&
(!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
如果eloop.terminate变为非零值,就会退出循环。这是为了提供一种从外部结束循环的方法。
如果eloop.terminate为零,只要timeout链表或者任一个Socket不为空,都会继续循环。
Select系统调用的原型是:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
在循环体里面:
(1)找到timeout链表的第一项(因为是按超时先后排序的,所以第一项肯定是最先超时的),计算超时时间距现在还有多久, 并据此设置select的timeout参数。
(2)设置readfd, writefds和exceptfds三个fd_set: 方法是遍历各个eloop_sock_table,把每个sock描述符加入相应的fd_set里面。
(3)调用select。 可能阻塞在此处。
(4)eloop_process_pending_signals(); 处理Signal事件。后面会分析。
(5)判断是否有超时发生,如果是则调用其Handler, 并从timeout链表移除。然后继续下次循环。
(6)如果不是超时事件,则应该是readfds, writefds或者exceptfds事件, fd_set里面会被改变,存放发生事件的描述符。因此分别遍历三个sock_table, 如果其描述符在fd_set里面则调用其Handler.
(7)继续下次循环.
值得一提的是,这里对Signal的处理有点特别。在eloop_register_signal() 函数注册的signal的Handler并不是当Signal发生时就会自动执行的。当Signal发生时只会对该struct eloop_signal的 signaled变量加1,以表明Signal已收到并处于Pendning状态。在select()超时或者有Socket事件方式时才会顺便调用eloop_process_pending_signals(), 对每个处于Pending状态的struct
eloop_signal调用其Handler.
疑问:这样做有什么好处?如果select阻塞很久,岂不是Signal也要Pending很久才得到处理?
WPA_SUPPLICANT的程序的生命就是在运行一个EVENT LOOP, 等待各种Event的到来,然后做相应的处理。因此分析EVENT LOOP的实现能起到提纲挈领的作用。
1. 数据结构: 见下图
![](https://oscdn.geek-share.com/Uploads/Images/Content/202006/05/0e5103b8efe2237bb095c7a0df78e5ea.png)
struct eloop_data结构体是一个统领全局的数据结构,只有一个实例,即Line 75:
点击(此处)折叠或打开
static struct eloop_data eloop;
要处理的Event有三大种类型:Socket事件,Timeout事件,Signal事件. 其中Socket事件又分为三种类型:
* @EVENT_TYPE_READ: Socket has data available for reading
* @EVENT_TYPE_WRITE: Socket has room for new data to be written
* @EVENT_TYPE_EXCEPTION: An exception has been reported
Socket事件:有readers, writers, exceptions三个eloop_sock_table结构体, 每个里面都有动态数组,数组的每一项都是一个具体的eloop_sock. 可以向各个Table里面添加、删除eloop_sock. 事件分发就是遍历sock_table, 依次运行里面的每个Handler.
Timeout事件: 每个struct eloop_timeout都被放在一个双向链表中, 链表头就是eloop_data中的”timeout”项。这些struct eloop_timeout按超时先后排序。
Signal事件:每个struct eloop_signal放在动态数组中
疑问: 为什么Socket和signal事件不使用链表,而是动态的扩大和缩小数组?
2. 基于Select的多Event处理
void eloop_run(void) 是个总函数,我们看它是怎么用select系统调用实现多路复用监听多个事件的。
while (!eloop.terminate &&
(!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
如果eloop.terminate变为非零值,就会退出循环。这是为了提供一种从外部结束循环的方法。
如果eloop.terminate为零,只要timeout链表或者任一个Socket不为空,都会继续循环。
Select系统调用的原型是:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
在循环体里面:
(1)找到timeout链表的第一项(因为是按超时先后排序的,所以第一项肯定是最先超时的),计算超时时间距现在还有多久, 并据此设置select的timeout参数。
(2)设置readfd, writefds和exceptfds三个fd_set: 方法是遍历各个eloop_sock_table,把每个sock描述符加入相应的fd_set里面。
(3)调用select。 可能阻塞在此处。
(4)eloop_process_pending_signals(); 处理Signal事件。后面会分析。
(5)判断是否有超时发生,如果是则调用其Handler, 并从timeout链表移除。然后继续下次循环。
(6)如果不是超时事件,则应该是readfds, writefds或者exceptfds事件, fd_set里面会被改变,存放发生事件的描述符。因此分别遍历三个sock_table, 如果其描述符在fd_set里面则调用其Handler.
(7)继续下次循环.
值得一提的是,这里对Signal的处理有点特别。在eloop_register_signal() 函数注册的signal的Handler并不是当Signal发生时就会自动执行的。当Signal发生时只会对该struct eloop_signal的 signaled变量加1,以表明Signal已收到并处于Pendning状态。在select()超时或者有Socket事件方式时才会顺便调用eloop_process_pending_signals(), 对每个处于Pending状态的struct
eloop_signal调用其Handler.
疑问:这样做有什么好处?如果select阻塞很久,岂不是Signal也要Pending很久才得到处理?
相关文章推荐
- WPA_SUPPLICANT源码分析(1):EVENT LOOP的实现 (转)
- WPA_SUPPLICANT源码分析(1):EVENT LOOP的实现
- muduo源码分析之EventLoop、Channel、Poller的实现
- Netty 4.0源码分析1:服务端启动过程中的Channel与EventLoopGroup的注册
- 4000 Netty5.0的NioEventLoop源码详细分析
- Netty线程模型源码分析之NioEventLoopGroup的初始化
- Netty源码学习——EventLoopGroup原理:NioEventLoopGroup分析
- 【Netty4.X】Netty源码分析之NioEventLoopGroup(五)
- Android Wi-Fi源码分析之wpa_supplicant初始化(一)
- Muduo网络库源码分析(四)EventLoopThread和EventLoopThreadPool的封装
- Android Wi-Fi源码分析之wpa_supplicant初始化(四):wpa_supplicant_init_iface函数分析
- Android View系统源码分析(四)—— 各种消息监测的基本实现方法&View.dispatchTouchEvent()
- hostapd wpa_supplicant madwifi详细分析(九)——wps原理及实现 一
- Netty源码分析:NioEventLoopGroup
- Netty源码分析:NioEventLoop启动以及其IO操作和Task任务的处理
- Android wpa_supplicant源码分析--conf配置文件
- Android Wi-Fi源码分析之wpa_supplicant初始化(三):wpa_supplicant_add_iface函数分析
- netty4源码分析——NioEventLoop
- 【Netty4.X】Netty源码分析之NioEventLoop(六)