1# 事件处理系统
2## 概述
3事件处理系统。c_utils提供基于Reactor模式,以epoll为后台多路复用机制,通过文件描述符fd实现对各I/O设备的基于事件的异步处理机制。
4
5开发者通过构造事件描述对象(`IOEventHandler`),指定由Fd指定的被监听I/O设备(不支持普通文件)、具体监听的事件类型以及捕获目标事件后的响应行为(回调函数)。
6
7随后开发者需要构造事件处理系统的中心响应器对象(`IOEventReactor`),该中心响应器对象将根据对监听事件以及响应行为的描述,捕获目标事件并对事件进行响应。
8
9## 相关原理
10
11### UML类图
12```mermaid
13classDiagram
14direction LR
15
16class EventHandler{
17    <<Abstact>>
18    + Start()
19    + Stop()
20    + Close()
21}
22
23class IOEventHandler{
24    - IOEventHandler* prev
25    - IOEventHandler* next
26    - IOEventReactor* loop
27    - IOEventCallback cb
28    - uint32_t events
29    - int fd
30    + Start() override
31    + Stop() override
32}
33
34class TimerEventHandler{
35    - uint32_t interval
36    + Start() override
37    + Stop() override
38    + Close() override
39}
40
41class FdEvents{
42    <<struct>>
43    IOEventHandler* head
44    uint32_t emask
45    uint8_t flags
46}
47
48class EventReactor{
49    <<Abstact>>
50    + Run()
51    + CleanUp()
52    + AddHandler()
53    + RemoveHandler()
54}
55
56class IOEventReactor{
57    - struct FdEventsHead
58    - struct FdEvents
59    - std::vector~FdEventsHead~ io_handlers
60    - EventDemultiplexer* backend
61    + Run() override
62    + CleanUp() override
63    + AddHandler() override
64    + RemoveHandler() override
65    + SetDemultiplexer():
66}
67
68class EventDemultiplexer{
69    <<Abstact>>
70    + Poll()
71}
72
73class IOEventEpoll{
74    - int epfd
75    + Poll() override
76    + ModifyEvents()
77    + CleanUp()
78}
79
80
81IOEventHandler ..|> EventHandler
82TimerEventHandler --|> IOEventHandler
83IOEventReactor ..|> EventReactor
84FdEvents --* IOEventReactor
85IOEventHandler --> FdEvents
86IOEventHandler ..> IOEventReactor
87EventEpoll ..|> EventDemultiplexer
88EventEpoll --o IOEventReactor
89```
90### IOEventReactor内数据结构
91![](../figs/io_event_reactor_structrues.png)
92
93###
94
95## 涉及功能
96### OHOS::Utils::Events
97#### 描述
98```cpp
99namespace OHOS::Utils::Events;
100```
101命名空间`Events`包含了c_utils中事件处理器功能中各兴趣事件的事件类型。
102
103`#include <io_event_common.h>`
104
105同时`io_event_common.h`头文件中定义了表示事件类型的C++类型`EventId`、表示响应行为的C++类型`EventCallback`(即`std::function<void()>`)。
106#### 属性
107
108|                | 名称           |
109| -------------- | -------------- |
110| constexpr EventId | **EVENT_CLOSE** <br>关闭事件。表明当前事件监听“关闭”事件。  |
111| constexpr EventId | **EVENT_ERROR** <br>错误事件。表明当前事件监听“错误”事件。  |
112| constexpr EventId | **EVENT_INVALID** <br>非法事件。表明当前事件类型设置非法。  |
113| constexpr EventId | **EVENT_NONE** <br>空事件。表明当前事件不监听任何事件类型。  |
114| constexpr EventId | **EVENT_READ** <br>可读事件。表明当前事件监听“可读”事件。  |
115| constexpr EventId | **EVENT_WRITE** <br>可写事件。表明当前事件监听“可写”事件。  |
116
117### OHOS::Utils::IOEventHandler
118#### 描述
119```cpp
120class OHOS::Utils::IOEventHandler;
121```
122事件描述类。其描述了兴趣IO事件的具体事件类型以及具体响应行为。
123当事件系统捕获到响应类型的事件时,将按照该事件描述类对象中定义的响应行为进行响应。
124
125`#include <io_event_handler.h>`
126
127#### 公共成员函数
128
129| 返回类型       | 名称           |
130| -------------- | -------------- |
131| | **IOEventHandler**()<br>默认构造函数。其Fd为-1。  |
132| | **IOEventHandler**(const IOEventHandler && ) =delete |
133| | **IOEventHandler**(const IOEventHandler & ) =delete |
134| | **IOEventHandler**(int fd, EventId events =Events::EVENT_NONE, const EventCallback & cb =nullptr)<br>有参构造函数。需要显示指定Fd。  |
135| virtual | **~IOEventHandler**() |
136| void | **DisableAll**()<br>关闭所有事件监听。  |
137| void | **DisableWrite**()<br>关闭对“可写”事件的监听。  |
138| void | **EnableRead**()<br>开启对“可读”事件的监听。  |
139| void | **EnableWrite**()<br>开启对“可写”事件的监听。  |
140| EventCallback | **GetCallback**() const |
141| EventId | **GetEvents**() const |
142| int | **GetFd**() const |
143| bool | **IsActive**()<br>返回当前事件是否已启动。  |
144| IOEventHandler * | **Next**() const<br>获取链表中后一个事件的指针。  |
145| IOEventHandler & | **operator=**(const IOEventHandler && ) =delete |
146| IOEventHandler & | **operator=**(const IOEventHandler & ) =delete |
147| IOEventHandler * | **Prev**() const<br>获取链表中前一个事件的指针。  |
148| void | **SetCallback**(const EventCallback & cb)<br>设置具体响应行为/回调函数  |
149| void | **SetEvents**(EventId events)<br>设置被监听事件类型。  |
150| void | **SetFd**(int fd)<br>设置被监听对象Fd。  |
151| bool | **Start**(IOEventReactor * reactor)<br>启动当前事件监听。  |
152| bool | **Stop**(IOEventReactor * reactor)<br>停止当前事件监听  |
153| bool | **Update**(IOEventReactor * reactor)<br>更新当前事件状态。当指定事件类型、响应行为变化时需要对其进行更新。  |
154
155### OHOS::Utils::IOEventReactor
156#### 描述
157```cpp
158class OHOS::Utils::IOEventReactor;
159```
160事件响应器类。其作为事件处理系统的中心调度器,负责管理外部添加的各个事件描述,按照描述添加对事件的监听、对各被监听对象进行轮询并对事件进行分发并处理。
161
162`#include <io_event_reactor.h>`
163
164#### 公共成员函数
165
166| 返回类型       | 名称           |
167| -------------- | -------------- |
168| | **IOEventHandler**()<br>默认构造函数。其Fd为-1。  |
169| | **IOEventHandler**(const IOEventHandler && ) =delete |
170| | **IOEventHandler**(const IOEventHandler & ) =delete |
171| | **IOEventHandler**(int fd, EventId events =Events::EVENT_NONE, const EventCallback & cb =nullptr)<br>有参构造函数。需要显示指定Fd。  |
172| virtual | **~IOEventHandler**() |
173| void | **DisableAll**()<br>关闭所有事件监听。  |
174| void | **DisableWrite**()<br>关闭对“可写”事件的监听。  |
175| void | **EnableRead**()<br>开启对“可读”事件的监听。  |
176| void | **EnableWrite**()<br>开启对“可写”事件的监听。  |
177| EventCallback | **GetCallback**() const |
178| EventId | **GetEvents**() const |
179| int | **GetFd**() const |
180| bool | **IsActive**()<br>返回当前事件是否已启动。  |
181| IOEventHandler * | **Next**() const<br>获取链表中后一个事件的指针。  |
182| IOEventHandler & | **operator=**(const IOEventHandler && ) =delete |
183| IOEventHandler & | **operator=**(const IOEventHandler & ) =delete |
184| IOEventHandler * | **Prev**() const<br>获取链表中前一个事件的指针。  |
185| void | **SetCallback**(const EventCallback & cb)<br>设置具体响应行为/回调函数  |
186| void | **SetEvents**(EventId events)<br>设置被监听事件类型。  |
187| void | **SetFd**(int fd)<br>设置被监听对象Fd。  |
188| bool | **Start**(IOEventReactor * reactor)<br>启动当前事件监听。  |
189| bool | **Stop**(IOEventReactor * reactor)<br>停止当前事件监听  |
190| bool | **Update**(IOEventReactor * reactor)<br>更新当前事件状态。当指定事件类型、响应行为变化时需要对其进行更新。  |
191
192## 使用示例
193
1941. 使用方法(伪代码)
195
196```c++
197// IOEventHandler 可以按照业务需要进行继承拓展。如以针对linux底层timerfd定时器为例:
198class TimerFdHandler : public IOEventHandler {
199public:
200    using TimerEventCallback = std::function<void()>;
201    TimerFdHandler(int fd, const TimerEventCallback& cb);
202    ~TimerFdHandler() {}
203    bool Initialize(uint32_t interval);
204    void Uninitialize();
205    void TimeOut();
206
207private:
208    TimerEventCallback timerCallback_;
209};
210```
211
212```c++
213    // 1. 首先创建定时器获取其Fd。
214    int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
215
216    // 2. 创建IOEventHandler对象,对目标事件进行描述
217    std::shared_ptr<TimerFdHandler> handler = std::make_shared<TimerFdHandler>(fd, &TimerCallback1);
218
219    // 3. 创建IOEventReactor响应器对象,启动并使能其事件响应能力。
220    std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
221    ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
222    reactor->EnableHandling();
223
224    // 4. 根据业务需要,对IOEventHandler对象进行其他初始化操作。本例中是设置定时器的超时时间,定时器超时后会抛出"可读"事件,该事件可被捕获从而使响应器对其进行响应。
225    handler->Initialize(10);
226
227    // 5. 启动IOEventHandler对象(也可以使用IOEventReactor::AddHandler 方法启动)
228    handler->Start(reactor.get());
229
230    // 6. 开启事件处理循环,`Run(int timeout)`方法使响应器循环进行事件处理,具体包括捕获事件以及对事件的响应过程。
231    std::thread loopThread([&reactor]{
232        reactor->Run(-1);
233    });
234
235    // 7. 定时器超时需要10ms,适当等待事件触发
236    std::this_thread::sleep_for(std::chrono::milliseconds(16));
237
238    // 8. 确定响应结果, 本例中指定的响应行为 `&TimerCallback1`将对`g_data`加一,故可确定`g_data`的值判断是否响应成功。
239    // EXPECT_GE(g_data, 1);
240
241    // 9. 终止事件处理循环,`Terminate()`方法将使`Run()`方法退出,从而新线程执行完毕。
242    reactor->Terminate();
243    loopThread.join();
244
245    // 10. 事件描述对象生命周期结束时,会从当前响应器对象中移除,从而解除监听。响应器对象生命周期结束时,会清空当前注册的事件描述对象。
246    // Notes:尽管事件描述对象生命周期结束时会自动被移除,但手动停止事件描述对象能够提升运行效率,这是因为事件描述对象由于周期结束而被移除时,响应器对象将不会解除其注册的监听事件,该事件仍有可能被响应器捕获。
247
248    // 11. 所以这里手动停止事件描述对象。
249    handler->Stop(reactor.get());
250```
251
2522. 测试用例编译运行方法
253
254- 测试用例代码参见 base/test/unittest/common/utils_event_test.cpp
255
256- 使用开发者自测试框架,使用方法参见:[开发自测试执行框架-测试用例执行](https://gitee.com/openharmony/testfwk_developer_test#%E6%B5%8B%E8%AF%95%E7%94%A8%E4%BE%8B%E6%89%A7%E8%A1%8C)
257
258- 使用以下具体命令以运行事件处理系统对应测试用例
259
260```bash
261run -t UT -tp utils -ts UtilsEventTest
262```