• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_epoll.h"
17 #include "nstackx_log.h"
18 #include "nstackx_list.h"
19 #include "nstackx_error.h"
20 
21 #define TAG "nStackXEpoll"
22 #define MAX_EPOLL_SIZE 128
23 #define PRINT_RIGHT_MOVE 48
24 static List g_epollTaskList;
25 static bool g_isInit = false;
26 static pthread_mutex_t g_taskListMutex = PTHREAD_MUTEX_INITIALIZER;
27 
28 typedef struct {
29     List list;
30     EpollTask *task;
31 } TaskList;
32 
PrintTaskInfo(EpollTask * task)33 static inline void PrintTaskInfo(EpollTask *task)
34 {
35     uint64_t taskAddress = (uint64_t)task;
36     uint64_t readHandleAddress = (uint64_t)&task->readHandle;
37     LOGI(TAG, "task : %02x******%06x, task->epollfd: %d, task->taskFd: %d, task->readHandle: %02x******%06x",
38          (taskAddress >> PRINT_RIGHT_MOVE) & 0xff, taskAddress & 0xffffff, task->epollfd, task->taskfd,
39          (readHandleAddress >> PRINT_RIGHT_MOVE) & 0xff, readHandleAddress & 0xffffff);
40 }
41 
PrintTaskDebugInfo(EpollTask * task,const char * str)42 static inline void PrintTaskDebugInfo(EpollTask *task, const char *str)
43 {
44     uint64_t taskAddress = (uint64_t)task;
45     uint64_t readHandleAddress = (uint64_t)&task->readHandle;
46     LOGD(TAG, "%s task : %02x******%06x, task->epollfd: %d, task->taskFd: %d, task->readHandle: %02x******%06x",
47          str, (taskAddress >> PRINT_RIGHT_MOVE) & 0xff, taskAddress & 0xffffff, task->epollfd, task->taskfd,
48          (readHandleAddress >> PRINT_RIGHT_MOVE) & 0xff, readHandleAddress & 0xffffff);
49 }
50 
IsEpollTaskEqual(EpollTask * oldTask,EpollTask * newTask)51 static bool IsEpollTaskEqual(EpollTask *oldTask, EpollTask *newTask)
52 {
53     if (oldTask == newTask && oldTask->epollfd == newTask->epollfd &&
54         oldTask->taskfd == newTask->taskfd && oldTask->readHandle == newTask->readHandle) {
55         return true;
56     }
57     return false;
58 }
59 
GetTaskFromList(EpollTask * task)60 static TaskList *GetTaskFromList(EpollTask *task)
61 {
62     if (pthread_mutex_lock(&g_taskListMutex) != 0) {
63         LOGE(TAG, "lock g_taskListMutex failed");
64         return NULL;
65     }
66     if (ListIsEmpty(&g_epollTaskList)) {
67         (void)pthread_mutex_unlock(&g_taskListMutex);
68         return NULL;
69     }
70     TaskList *taskList = NULL;
71     List *pos = NULL;
72     TaskList *node = NULL;
73     LIST_FOR_EACH(pos, &g_epollTaskList) {
74         node = (TaskList *)pos;
75         if (IsEpollTaskEqual(task, node->task)) {
76             taskList = node;
77             break;
78         }
79     }
80     (void)pthread_mutex_unlock(&g_taskListMutex);
81     return taskList;
82 }
83 
AddTaskToList(EpollTask * task)84 static int32_t AddTaskToList(EpollTask *task)
85 {
86     if (task == NULL) {
87         return NSTACKX_EINVAL;
88     }
89 
90     if (!g_isInit) {
91         if (pthread_mutex_lock(&g_taskListMutex) != 0) {
92             LOGE(TAG, "lock g_taskListMutex failed");
93             return NSTACKX_EFAILED;
94         }
95         if (!g_isInit) {
96             ListInitHead(&g_epollTaskList);
97             g_isInit = true;
98         }
99         (void)pthread_mutex_unlock(&g_taskListMutex);
100     }
101 
102     TaskList *taskListCheck = GetTaskFromList(task);
103     if (taskListCheck != NULL) {
104         LOGE(TAG, "taskListCheck GetTaskFromList failed");
105         return NSTACKX_EFAILED;
106     }
107     TaskList *taskList = calloc(1, sizeof(TaskList));
108     if (taskList == NULL) {
109         LOGE(TAG, "calloc failed");
110         return NSTACKX_EFAILED;
111     }
112     taskList->task = task;
113     if (pthread_mutex_lock(&g_taskListMutex) != 0) {
114         free(taskList);
115         LOGE(TAG, "lock g_taskListMutex failed");
116         return NSTACKX_EFAILED;
117     }
118     ListInsertTail(&g_epollTaskList, &taskList->list);
119     (void)pthread_mutex_unlock(&g_taskListMutex);
120 
121     return NSTACKX_EOK;
122 }
123 
DelTaskFromList(EpollTask * task)124 static int32_t DelTaskFromList(EpollTask *task)
125 {
126     if (task == NULL) {
127         LOGE(TAG, "task is null");
128         return NSTACKX_EINVAL;
129     }
130     TaskList *taskList = GetTaskFromList(task);
131     if (taskList == NULL) {
132         LOGE(TAG, "task is not exist");
133         PrintTaskInfo(task);
134         return NSTACKX_EFAILED;
135     }
136     if (pthread_mutex_lock(&g_taskListMutex) != 0) {
137         LOGE(TAG, "lock g_taskListMutex failed");
138         return NSTACKX_EFAILED;
139     }
140     ListRemoveNode(&taskList->list);
141     (void)pthread_mutex_unlock(&g_taskListMutex);
142     free(taskList);
143     return NSTACKX_EOK;
144 }
145 
RefreshEpollTask(EpollTask * task,uint32_t events)146 int32_t RefreshEpollTask(EpollTask *task, uint32_t events)
147 {
148     struct epoll_event event;
149     if (task == NULL) {
150         return NSTACKX_EINVAL;
151     }
152 
153     TaskList *taskList = GetTaskFromList(task);
154     if (taskList == NULL) {
155         LOGE(TAG, "task is not exist");
156         PrintTaskInfo(task);
157         return NSTACKX_EFAILED;
158     }
159     event.data.ptr = task;
160     event.events = events;
161 
162     if (epoll_ctl(task->epollfd, EPOLL_CTL_MOD, task->taskfd, &event) < 0) {
163         LOGE(TAG, "Refresh task failed: %d", errno);
164         return NSTACKX_EFAILED;
165     }
166 
167     PrintTaskDebugInfo(task, "RefreshEpollTask");
168     return NSTACKX_EOK;
169 }
170 
RegisterEpollTask(EpollTask * task,uint32_t events)171 int32_t RegisterEpollTask(EpollTask *task, uint32_t events)
172 {
173     struct epoll_event event;
174     if (task == NULL) {
175         return NSTACKX_EINVAL;
176     }
177 
178     if (AddTaskToList(task) != NSTACKX_EOK) {
179         LOGE(TAG, "task is exist");
180         PrintTaskInfo(task);
181         return NSTACKX_EFAILED;
182     }
183 
184     event.data.ptr = task;
185     event.events = events;
186     if (epoll_ctl(task->epollfd, EPOLL_CTL_ADD, task->taskfd, &event) < 0) {
187         LOGE(TAG, "Register task failed: %d", errno);
188         DelTaskFromList(task);
189         return NSTACKX_EFAILED;
190     }
191 
192     PrintTaskDebugInfo(task, "RegisterEpollTask");
193     return NSTACKX_EOK;
194 }
195 
DeRegisterEpollTask(EpollTask * task)196 int32_t DeRegisterEpollTask(EpollTask *task)
197 {
198     if (task == NULL) {
199         return NSTACKX_EINVAL;
200     }
201 
202     if (DelTaskFromList(task) != NSTACKX_EOK) {
203         LOGE(TAG, "task is not exist");
204         PrintTaskInfo(task);
205         return NSTACKX_EFAILED;
206     }
207     if (epoll_ctl(task->epollfd, EPOLL_CTL_DEL, task->taskfd, NULL) < 0) {
208         LOGE(TAG, "De-register task failed: %d", errno);
209         return NSTACKX_EFAILED;
210     }
211 
212     PrintTaskDebugInfo(task, "DeRegisterEpollTask");
213     return NSTACKX_EOK;
214 }
215 
CreateEpollDesc(void)216 EpollDesc CreateEpollDesc(void)
217 {
218     return epoll_create(1);
219 }
220 
EpollLoop(EpollDesc epollfd,int32_t timeout)221 int32_t EpollLoop(EpollDesc epollfd, int32_t timeout)
222 {
223     int32_t i, nfds;
224     EpollTask *task = NULL;
225     struct epoll_event events[MAX_EPOLL_SIZE];
226 
227     nfds = epoll_wait(epollfd, events, MAX_EPOLL_SIZE, timeout);
228     if (nfds < 0) {
229         if (errno == EINTR) {
230             LOGD(TAG, "epoll_wait EINTR");
231             return NSTACKX_EINTR;
232         }
233         LOGE(TAG, "epoll_wait returned n=%d, error: %d", nfds, errno);
234         return NSTACKX_EFAILED;
235     }
236 
237     for (i = 0; i < nfds; i++) {
238         task = events[i].data.ptr;
239         if (task == NULL) {
240             continue;
241         }
242 
243         if (events[i].events & EPOLLIN) {
244             TaskList *taskList = GetTaskFromList(task);
245             if (taskList == NULL) {
246                 LOGE(TAG, "task is not exist");
247                 PrintTaskInfo(task);
248                 return NSTACKX_OVERFLOW;
249             }
250             if (task->readHandle != NULL) {
251                 task->readHandle(task);
252             }
253         }
254 
255         if (events[i].events & EPOLLOUT) {
256             if (task->writeHandle != NULL) {
257                 task->writeHandle(task);
258             }
259         }
260     }
261 
262     return ((nfds > 0) ? nfds : NSTACKX_ETIMEOUT);
263 }
264