1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "nstackx_event.h"
17 #include "nstackx_log.h"
18 #include "nstackx_error.h"
19 #include "nstackx_util.h"
20 #include "securec.h"
21
22 #define TAG "nStackXEvent"
23
24 typedef struct {
25 EventHandle handle;
26 void *arg;
27 } EventInfo;
28
29 EventNode *SearchEventNode(const List *eventNodeChain, EpollDesc epollfd);
30
CloseNodePipe(const EventNode * node)31 void CloseNodePipe(const EventNode *node)
32 {
33 CloseDesc(node->pipeFd[PIPE_OUT]);
34 CloseDesc(node->pipeFd[PIPE_IN]);
35 }
36
EventProcessHandle(void * arg)37 static void EventProcessHandle(void *arg)
38 {
39 int32_t ret;
40 EventInfo event = {0};
41 EpollTask *task = arg;
42 EventNode *node = container_of(task, EventNode, task);
43
44 ret = (int32_t)read(node->pipeFd[PIPE_OUT], &event, sizeof(event));
45 if (ret != (int32_t)sizeof(event)) {
46 LOGE(TAG, "failed to read from pipe: %d", GetErrno());
47 return;
48 }
49
50 if (event.handle != NULL) {
51 event.handle(event.arg);
52 }
53 }
54
PostEvent(const List * eventNodeChain,EpollDesc epollfd,EventHandle handle,void * arg)55 int32_t PostEvent(const List *eventNodeChain, EpollDesc epollfd, EventHandle handle, void *arg)
56 {
57 int32_t ret;
58 EventNode *node = NULL;
59 EventInfo event = {
60 .handle = handle,
61 .arg = arg,
62 };
63
64 if (eventNodeChain == NULL || handle == NULL) {
65 return NSTACKX_EINVAL;
66 }
67
68 node = SearchEventNode(eventNodeChain, epollfd);
69 if (node == NULL) {
70 LOGE(TAG, "Cannot find event node for %d", epollfd);
71 return NSTACKX_EFAILED;
72 }
73
74 ret = (int32_t)write(node->pipeFd[PIPE_IN], &event, sizeof(event));
75 if (ret != (int32_t)sizeof(event)) {
76 LOGE(TAG, "failed to write to pipe: %d", errno);
77 return NSTACKX_EFAILED;
78 }
79 return NSTACKX_EOK;
80 }
81
ClearEvent(const List * eventNodeChain,EpollDesc epollfd)82 void ClearEvent(const List *eventNodeChain, EpollDesc epollfd)
83 {
84 EventNode *node = NULL;
85 EventInfo event = {0};
86 int32_t eventLen = (int32_t)sizeof(event);
87 if (eventNodeChain == NULL) {
88 LOGE(TAG, "eventNodeChain is null");
89 return;
90 }
91
92 node = SearchEventNode(eventNodeChain, epollfd);
93 if (node == NULL) {
94 return;
95 }
96
97 int32_t ret = eventLen;
98 while (ret == eventLen) {
99 ret = (int32_t)read(node->pipeFd[PIPE_OUT], &event, sizeof(event));
100 if (ret != eventLen) {
101 break;
102 }
103
104 if (event.handle != NULL) {
105 event.handle(event.arg);
106 }
107 }
108 }
109
CreateNonBlockPipe(EventNode * node)110 static int32_t CreateNonBlockPipe(EventNode *node)
111 {
112 int32_t ret;
113 int32_t i, flags;
114
115 if (pipe(node->pipeFd) < 0) {
116 LOGE(TAG, "create pipe error: %d", errno);
117 return NSTACKX_EFAILED;
118 }
119
120 for (i = 0; i < PIPE_FD_NUM; i++) {
121 flags = fcntl(node->pipeFd[i], F_GETFL, 0);
122 if (flags < 0) {
123 LOGE(TAG, "fcntl get flags failed: %d", errno);
124 CloseNodePipe(node);
125 return NSTACKX_EFAILED;
126 }
127
128 flags = (int32_t)((uint32_t)flags | O_NONBLOCK);
129 ret = fcntl(node->pipeFd[i], F_SETFL, flags);
130 if (ret < 0) {
131 LOGE(TAG, "fcntl set flags to non-blocking failed: %d", errno);
132 CloseNodePipe(node);
133 return NSTACKX_EFAILED;
134 }
135 }
136
137 return NSTACKX_EOK;
138 }
139
EventModuleInit(List * eventNodeChain,EpollDesc epollfd)140 int32_t EventModuleInit(List *eventNodeChain, EpollDesc epollfd)
141 {
142 List *pos = NULL;
143 EventNode *node = NULL;
144 if (eventNodeChain == NULL) {
145 LOGE(TAG, "eventNodeChain is null");
146 return NSTACKX_EINVAL;
147 }
148 LIST_FOR_EACH(pos, eventNodeChain) {
149 node = (EventNode *)pos;
150 if (node->epollfd == epollfd) {
151 return NSTACKX_EOK;
152 }
153 }
154
155 node = calloc(1, sizeof(EventNode));
156 if (node == NULL) {
157 return NSTACKX_ENOMEM;
158 }
159
160 if (CreateNonBlockPipe(node) != NSTACKX_EOK) {
161 goto L_ERR_FAILED;
162 }
163
164 node->task.taskfd = node->pipeFd[PIPE_OUT];
165 node->task.epollfd = epollfd;
166 node->task.readHandle = EventProcessHandle;
167
168 node->epollfd = epollfd;
169 if (RegisterEpollTask(&node->task, EPOLLIN) != NSTACKX_EOK) {
170 LOGE(TAG, "RegisterEpollTask failed");
171 CloseNodePipe(node);
172 goto L_ERR_FAILED;
173 }
174
175 ListInsertTail(eventNodeChain, &(node->list));
176 return NSTACKX_EOK;
177 L_ERR_FAILED:
178 free(node);
179 return NSTACKX_EFAILED;
180 }
181
DeleteEventNode(EventNode * node)182 void DeleteEventNode(EventNode *node)
183 {
184 ListRemoveNode(&node->list);
185 if (DeRegisterEpollTask(&node->task) != NSTACKX_EOK) {
186 LOGE(TAG, "DeRegisterEpollTask failed");
187 }
188 CloseNodePipe(node);
189 free(node);
190 }
191